diff options
Diffstat (limited to 'src')
752 files changed, 31485 insertions, 26999 deletions
diff --git a/src/or/auth_dirs.inc b/src/app/config/auth_dirs.inc index e0937541ea..e0937541ea 100644 --- a/src/or/auth_dirs.inc +++ b/src/app/config/auth_dirs.inc diff --git a/src/or/config.c b/src/app/config/config.c index 94a58f3488..665732ea56 100644 --- a/src/or/config.c +++ b/src/app/config/config.c @@ -2,7 +2,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -60,61 +60,84 @@ **/ #define CONFIG_PRIVATE -#include "or.h" -#include "bridges.h" -#include "compat.h" -#include "addressmap.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "circuitstats.h" -#include "compress.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "consdiffmgr.h" -#include "control.h" -#include "confparse.h" -#include "cpuworker.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "dirserv.h" -#include "dns.h" -#include "dos.h" -#include "entrynodes.h" -#include "git_revision.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "relay.h" -#include "rendclient.h" -#include "rendservice.h" -#include "hs_config.h" -#include "rephist.h" -#include "router.h" -#include "sandbox.h" -#include "util.h" -#include "routerlist.h" -#include "routerset.h" -#include "scheduler.h" -#include "statefile.h" -#include "transports.h" -#include "ext_orport.h" -#include "voting_schedule.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "feature/client/addressmap.h" +#include "core/or/channel.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitmux.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/circuitstats.h" +#include "lib/compress/compress.h" +#include "app/config/config.h" +#include "lib/encoding/confline.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/control/control.h" +#include "app/config/confparse.h" +#include "core/mainloop/cpuworker.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/dirserv.h" +#include "feature/relay/dns.h" +#include "core/or/dos.h" +#include "feature/client/entrynodes.h" +#include "core/or/git_revision.h" +#include "feature/stats/geoip.h" +#include "feature/hibernate/hibernate.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/or/relay.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendservice.h" +#include "feature/hs/hs_config.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "lib/sandbox/sandbox.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "core/or/scheduler.h" +#include "app/config/statefile.h" +#include "feature/client/transports.h" +#include "feature/relay/ext_orport.h" +#include "feature/dircommon/voting_schedule.h" #ifdef _WIN32 #include <shlobj.h> #endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "lib/meminfo/meminfo.h" +#include "lib/osinfo/uname.h" +#include "lib/process/daemon.h" +#include "lib/process/pidfile.h" +#include "lib/process/restrict.h" +#include "lib/process/setuid.h" +#include "lib/process/subprocess.h" +#include "lib/net/gethostname.h" +#include "lib/thread/numcpus.h" -#include "procmon.h" +#include "lib/encoding/keyval.h" +#include "lib/fs/conffile.h" +#include "lib/evloop/procmon.h" -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/mode.h" + +#include "core/or/connection_st.h" +#include "core/or/port_cfg_st.h" #ifdef HAVE_SYSTEMD # if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) @@ -132,6 +155,10 @@ static const char unix_socket_prefix[] = "unix:"; * configuration. */ static const char unix_q_socket_prefix[] = "unix:\""; +/* limits for TCP send and recv buffer size used for constrained sockets */ +#define MIN_CONSTRAINED_TCP_BUFFER 2048 +#define MAX_CONSTRAINED_TCP_BUFFER 262144 /* 256k */ + /** macro to help with the bulk rename of *DownloadSchedule to * *DowloadInitialDelay . */ #define DOWNLOAD_SCHEDULE(name) \ @@ -2626,7 +2653,7 @@ print_usage(void) printf( "Copyright (c) 2001-2004, Roger Dingledine\n" "Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson\n" -"Copyright (c) 2007-2017, The Tor Project, Inc.\n\n" +"Copyright (c) 2007-2018, The Tor Project, Inc.\n\n" "tor -f <torrc> [args]\n" "See man page for options, or https://www.torproject.org/ for " "documentation.\n"); @@ -3033,8 +3060,8 @@ ensure_bandwidth_cap(uint64_t *value, const char *desc, char **msg) --*value; } if (*value > ROUTER_MAX_DECLARED_BANDWIDTH) { - tor_asprintf(msg, "%s ("U64_FORMAT") must be at most %d", - desc, U64_PRINTF_ARG(*value), + tor_asprintf(msg, "%s (%"PRIu64") must be at most %d", + desc, (*value), ROUTER_MAX_DECLARED_BANDWIDTH); return -1; } @@ -4567,8 +4594,8 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess) uint64_t result; if (val == 0) { -#define ONE_GIGABYTE (U64_LITERAL(1) << 30) -#define ONE_MEGABYTE (U64_LITERAL(1) << 20) +#define ONE_GIGABYTE (UINT64_C(1) << 30) +#define ONE_MEGABYTE (UINT64_C(1) << 20) /* The user didn't pick a memory limit. Choose a very large one * that is still smaller than the system memory */ static int notice_sent = 0; @@ -4622,10 +4649,10 @@ compute_real_max_mem_in_queues(const uint64_t val, int log_guess) } } if (log_guess && ! notice_sent) { - log_notice(LD_CONFIG, "%sMaxMemInQueues is set to "U64_FORMAT" MB. " + log_notice(LD_CONFIG, "%sMaxMemInQueues is set to %"PRIu64" MB. " "You can override this by setting MaxMemInQueues by hand.", ram ? "Based on detected system memory, " : "", - U64_PRINTF_ARG(result / ONE_MEGABYTE)); + (result / ONE_MEGABYTE)); notice_sent = 1; } return result; @@ -5635,6 +5662,23 @@ addressmap_register_auto(const char *from, const char *to, } /** + * As add_file_log, but open the file as appropriate. + */ +STATIC int +open_and_add_file_log(const log_severity_list_t *severity, + const char *filename, int truncate_log) +{ + int open_flags = O_WRONLY|O_CREAT; + open_flags |= truncate_log ? O_TRUNC : O_APPEND; + + int fd = tor_open_cloexec(filename, open_flags, 0640); + if (fd < 0) + return -1; + + return add_file_log(severity, filename, fd); +} + +/** * Initialize the logs based on the configuration file. */ static int @@ -5759,7 +5803,7 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, } } } - if (add_file_log(severity, fname, truncate_log) < 0) { + if (open_and_add_file_log(severity, fname, truncate_log) < 0) { log_warn(LD_CONFIG, "Couldn't open file for 'Log %s': %s", opt->value, strerror(errno)); ok = 0; @@ -6414,6 +6458,23 @@ parse_dir_authority_line(const char *line, dirinfo_type_t required_type, } addrport = smartlist_get(items, 0); smartlist_del_keeporder(items, 0); + + const char *addrport_sep = strchr(addrport, ':'); + if (!addrport_sep) { + log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s' " + "(':' not found)", addrport); + goto err; + } + + address = tor_strndup(addrport, addrport_sep - addrport); + if (!string_is_valid_ipv4_address(address)) { + log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s' " + "(invalid IPv4 address)", address); + goto err; + } + + tor_free(address); + if (addr_port_lookup(LOG_WARN, addrport, &address, NULL, &dir_port)<0) { log_warn(LD_CONFIG, "Error parsing DirAuthority address '%s'", addrport); goto err; @@ -8449,4 +8510,3 @@ options_any_client_port_set(const or_options_t *options) options->DNSPort_set || options->HTTPTunnelPort_set); } - diff --git a/src/or/config.h b/src/app/config/config.h index 4b41274434..a169cfd451 100644 --- a/src/or/config.h +++ b/src/app/config/config.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,8 @@ #ifndef TOR_CONFIG_H #define TOR_CONFIG_H -#include "testsupport.h" +#include "app/config/or_options_st.h" +#include "lib/testsupport/testsupport.h" #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(DARWIN) #define KERNEL_MAY_SUPPORT_IPFW @@ -24,9 +25,9 @@ /** Maximum default value for MaxMemInQueues, in bytes. */ #if SIZEOF_VOID_P >= 8 -#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (U64_LITERAL(8) << 30) +#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (UINT64_C(8) << 30) #else -#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (U64_LITERAL(2) << 30) +#define MAX_DEFAULT_MEMORY_QUEUE_SIZE (UINT64_C(2) << 30) #endif MOCK_DECL(const char*, get_dirportfrontpage, (void)); @@ -42,7 +43,16 @@ void init_protocol_warning_severity_level(void); int get_protocol_warning_severity_level(void); const char *get_version(void); const char *get_short_version(void); -setopt_err_t options_trial_assign(config_line_t *list, unsigned flags, + +/** An error from options_trial_assign() or options_init_from_string(). */ +typedef enum setopt_err_t { + SETOPT_OK = 0, + SETOPT_ERR_MISC = -1, + SETOPT_ERR_PARSE = -2, + SETOPT_ERR_TRANSITION = -3, + SETOPT_ERR_SETTING = -4, +} setopt_err_t; +setopt_err_t options_trial_assign(struct config_line_t *list, unsigned flags, char **msg); uint32_t get_last_resolved_addr(void); @@ -62,7 +72,7 @@ setopt_err_t options_init_from_string(const char *cf_defaults, const char *cf, int command, const char *command_arg, char **msg); int option_is_recognized(const char *key); const char *option_get_canonical_name(const char *key); -config_line_t *option_get_assignment(const or_options_t *options, +struct config_line_t *option_get_assignment(const or_options_t *options, const char *key); int options_save_current(void); const char *get_torrc_fname(int defaults_fname); @@ -180,8 +190,8 @@ int init_cookie_authentication(const char *fname, const char *header, or_options_t *options_new(void); int config_parse_commandline(int argc, char **argv, int ignore_errors, - config_line_t **result, - config_line_t **cmdline_result); + struct config_line_t **result, + struct config_line_t **cmdline_result); void config_register_addressmaps(const or_options_t *options); /* XXXX move to connection_edge.h */ @@ -260,7 +270,7 @@ STATIC int parse_dir_fallback_line(const char *line, int validate_only); STATIC int have_enough_mem_for_dircache(const or_options_t *options, size_t total_mem, char **msg); STATIC int parse_port_config(smartlist_t *out, - const config_line_t *ports, + const struct config_line_t *ports, const char *portname, int listener_type, const char *defaultaddr, @@ -271,8 +281,10 @@ STATIC int check_bridge_distribution_setting(const char *bd); STATIC uint64_t compute_real_max_mem_in_queues(const uint64_t val, int log_guess); +STATIC int open_and_add_file_log(const log_severity_list_t *severity, + const char *fname, + int truncate_log); #endif /* defined(CONFIG_PRIVATE) */ #endif /* !defined(TOR_CONFIG_H) */ - diff --git a/src/or/confparse.c b/src/app/config/confparse.c index 6bab790945..5b7f54bc65 100644 --- a/src/or/confparse.c +++ b/src/app/config/confparse.c @@ -1,8 +1,7 @@ - /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,9 +21,12 @@ * specified, and a linked list of key-value pairs. */ -#include "or.h" -#include "confparse.h" -#include "routerset.h" +#include "core/or/or.h" +#include "app/config/confparse.h" +#include "feature/nodelist/routerset.h" + +#include "lib/container/bitarray.h" +#include "lib/encoding/confline.h" static uint64_t config_parse_memunit(const char *s, int *ok); static int config_parse_msec_interval(const char *s, int *ok); @@ -573,8 +575,8 @@ config_get_assigned_option(const config_format_t *fmt, const void *options, escape_val = 0; /* Can't need escape. */ break; case CONFIG_TYPE_MEMUNIT: - tor_asprintf(&result->value, U64_FORMAT, - U64_PRINTF_ARG(*(uint64_t*)value)); + tor_asprintf(&result->value, "%"PRIu64, + (*(uint64_t*)value)); escape_val = 0; /* Can't need escape. */ break; case CONFIG_TYPE_DOUBLE: @@ -1039,15 +1041,15 @@ static struct unit_table_t memory_units[] = { { "gigabit", 1<<27 }, { "gbits", 1<<27 }, { "gbit", 1<<27 }, - { "tb", U64_LITERAL(1)<<40 }, - { "tbyte", U64_LITERAL(1)<<40 }, - { "tbytes", U64_LITERAL(1)<<40 }, - { "terabyte", U64_LITERAL(1)<<40 }, - { "terabytes", U64_LITERAL(1)<<40 }, - { "terabits", U64_LITERAL(1)<<37 }, - { "terabit", U64_LITERAL(1)<<37 }, - { "tbits", U64_LITERAL(1)<<37 }, - { "tbit", U64_LITERAL(1)<<37 }, + { "tb", UINT64_C(1)<<40 }, + { "tbyte", UINT64_C(1)<<40 }, + { "tbytes", UINT64_C(1)<<40 }, + { "terabyte", UINT64_C(1)<<40 }, + { "terabytes", UINT64_C(1)<<40 }, + { "terabits", UINT64_C(1)<<37 }, + { "terabit", UINT64_C(1)<<37 }, + { "tbits", UINT64_C(1)<<37 }, + { "tbit", UINT64_C(1)<<37 }, { NULL, 0 }, }; @@ -1116,7 +1118,7 @@ config_parse_units(const char *val, struct unit_table_t *u, int *ok) if (!cp) { *ok = 1; - v = use_float ? DBL_TO_U64(d) : v; + v = use_float ? ((uint64_t)d) : v; goto done; } @@ -1186,4 +1188,3 @@ config_parse_interval(const char *s, int *ok) } return (int)r; } - diff --git a/src/or/confparse.h b/src/app/config/confparse.h index 4b4bf0adb4..cbd2ea88e2 100644 --- a/src/or/confparse.h +++ b/src/app/config/confparse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONFPARSE_H @@ -65,9 +65,9 @@ typedef union { time_t *ISOTIME; smartlist_t **CSV; int *CSV_INTERVAL; - config_line_t **LINELIST; - config_line_t **LINELIST_S; - config_line_t **LINELIST_V; + struct config_line_t **LINELIST; + struct config_line_t **LINELIST_S; + struct config_line_t **LINELIST_V; routerset_t **ROUTERSET; } confparse_dummy_values_t; #endif /* defined(TOR_UNIT_TESTS) */ @@ -185,7 +185,7 @@ void config_free_(const config_format_t *fmt, void *options); (options) = NULL; \ } while (0) -config_line_t *config_get_assigned_option(const config_format_t *fmt, +struct config_line_t *config_get_assigned_option(const config_format_t *fmt, const void *options, const char *key, int escape_val); int config_is_same(const config_format_t *fmt, @@ -197,7 +197,7 @@ char *config_dump(const config_format_t *fmt, const void *default_options, const void *options, int minimal, int comment_defaults); int config_assign(const config_format_t *fmt, void *options, - config_line_t *list, + struct config_line_t *list, unsigned flags, char **msg); config_var_t *config_find_option_mutable(config_format_t *fmt, const char *key); @@ -219,4 +219,3 @@ void warn_deprecated_option(const char *what, const char *why); #define CFG_EQ_ROUTERSET(a,b,opt) routerset_equal((a)->opt, (b)->opt) #endif /* !defined(TOR_CONFPARSE_H) */ - diff --git a/src/or/fallback_dirs.inc b/src/app/config/fallback_dirs.inc index c446152e6a..c446152e6a 100644 --- a/src/or/fallback_dirs.inc +++ b/src/app/config/fallback_dirs.inc diff --git a/src/app/config/or_options_st.h b/src/app/config/or_options_st.h new file mode 100644 index 0000000000..0c0c5d32bb --- /dev/null +++ b/src/app/config/or_options_st.h @@ -0,0 +1,1077 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_OR_OPTIONS_ST_H +#define TOR_OR_OPTIONS_ST_H + +#include "lib/cc/torint.h" +#include "lib/net/address.h" + +struct smartlist_t; +struct config_line_t; + +/** Enumeration of outbound address configuration types: + * Exit-only, OR-only, or both */ +typedef enum {OUTBOUND_ADDR_EXIT, OUTBOUND_ADDR_OR, + OUTBOUND_ADDR_EXIT_AND_OR, + OUTBOUND_ADDR_MAX} outbound_addr_t; + +/** Configuration options for a Tor process. */ +struct or_options_t { + uint32_t magic_; + + /** What should the tor process actually do? */ + enum { + CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT, CMD_HASH_PASSWORD, + CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS, CMD_DUMP_CONFIG, + CMD_KEYGEN, + CMD_KEY_EXPIRATION, + } command; + char *command_arg; /**< Argument for command-line option. */ + + struct config_line_t *Logs; /**< New-style list of configuration lines + * for logs */ + int LogTimeGranularity; /**< Log resolution in milliseconds. */ + + int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which + * each log message occurs? */ + int TruncateLogFile; /**< Boolean: Should we truncate the log file + before we start writing? */ + char *SyslogIdentityTag; /**< Identity tag to add for syslog logging. */ + char *AndroidIdentityTag; /**< Identity tag to add for Android logging. */ + + char *DebugLogFile; /**< Where to send verbose log messages. */ + char *DataDirectory_option; /**< Where to store long-term data, as + * configured by the user. */ + char *DataDirectory; /**< Where to store long-term data, as modified. */ + int DataDirectoryGroupReadable; /**< Boolean: Is the DataDirectory g+r? */ + + char *KeyDirectory_option; /**< Where to store keys, as + * configured by the user. */ + char *KeyDirectory; /**< Where to store keys data, as modified. */ + int KeyDirectoryGroupReadable; /**< Boolean: Is the KeyDirectory g+r? */ + + char *CacheDirectory_option; /**< Where to store cached data, as + * configured by the user. */ + char *CacheDirectory; /**< Where to store cached data, as modified. */ + int CacheDirectoryGroupReadable; /**< Boolean: Is the CacheDirectory g+r? */ + + char *Nickname; /**< OR only: nickname of this onion router. */ + char *Address; /**< OR only: configured address for this onion router. */ + char *PidFile; /**< Where to store PID of Tor process. */ + + routerset_t *ExitNodes; /**< Structure containing nicknames, digests, + * country codes and IP address patterns of ORs to + * consider as exits. */ + routerset_t *EntryNodes;/**< Structure containing nicknames, digests, + * country codes and IP address patterns of ORs to + * consider as entry points. */ + int StrictNodes; /**< Boolean: When none of our EntryNodes or ExitNodes + * are up, or we need to access a node in ExcludeNodes, + * do we just fail instead? */ + routerset_t *ExcludeNodes;/**< Structure containing nicknames, digests, + * country codes and IP address patterns of ORs + * not to use in circuits. But see StrictNodes + * above. */ + routerset_t *ExcludeExitNodes;/**< Structure containing nicknames, digests, + * country codes and IP address patterns of + * ORs not to consider as exits. */ + + /** Union of ExcludeNodes and ExcludeExitNodes */ + routerset_t *ExcludeExitNodesUnion_; + + int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our + * process for all current and future memory. */ + + struct config_line_t *ExitPolicy; /**< Lists of exit policy components. */ + int ExitPolicyRejectPrivate; /**< Should we not exit to reserved private + * addresses, and our own published addresses? + */ + int ExitPolicyRejectLocalInterfaces; /**< Should we not exit to local + * interface addresses? + * Includes OutboundBindAddresses and + * configured ports. */ + int ReducedExitPolicy; /**<Should we use the Reduced Exit Policy? */ + struct config_line_t *SocksPolicy; /**< Lists of socks policy components */ + struct config_line_t *DirPolicy; /**< Lists of dir policy components */ + /** Local address to bind outbound sockets */ + struct config_line_t *OutboundBindAddress; + /** Local address to bind outbound relay sockets */ + struct config_line_t *OutboundBindAddressOR; + /** Local address to bind outbound exit sockets */ + struct config_line_t *OutboundBindAddressExit; + /** Addresses derived from the various OutboundBindAddress lines. + * [][0] is IPv4, [][1] is IPv6 + */ + tor_addr_t OutboundBindAddresses[OUTBOUND_ADDR_MAX][2]; + /** Directory server only: which versions of + * Tor should we tell users to run? */ + struct config_line_t *RecommendedVersions; + struct config_line_t *RecommendedClientVersions; + struct config_line_t *RecommendedServerVersions; + struct config_line_t *RecommendedPackages; + /** Whether dirservers allow router descriptors with private IPs. */ + int DirAllowPrivateAddresses; + /** Whether routers accept EXTEND cells to routers with private IPs. */ + int ExtendAllowPrivateAddresses; + char *User; /**< Name of user to run Tor as. */ + /** Ports to listen on for OR connections. */ + struct config_line_t *ORPort_lines; + /** Ports to listen on for extended OR connections. */ + struct config_line_t *ExtORPort_lines; + /** Ports to listen on for SOCKS connections. */ + struct config_line_t *SocksPort_lines; + /** Ports to listen on for transparent pf/netfilter connections. */ + struct config_line_t *TransPort_lines; + char *TransProxyType; /**< What kind of transparent proxy + * implementation are we using? */ + /** Parsed value of TransProxyType. */ + enum { + TPT_DEFAULT, + TPT_PF_DIVERT, + TPT_IPFW, + TPT_TPROXY, + } TransProxyType_parsed; + /** Ports to listen on for transparent natd connections. */ + struct config_line_t *NATDPort_lines; + /** Ports to listen on for HTTP Tunnel connections. */ + struct config_line_t *HTTPTunnelPort_lines; + struct config_line_t *ControlPort_lines; /**< Ports to listen on for control + * connections. */ + /** List of Unix Domain Sockets to listen on for control connections. */ + struct config_line_t *ControlSocket; + + int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */ + int UnixSocksGroupWritable; /**< Boolean: Are SOCKS Unix sockets g+rw? */ + /** Ports to listen on for directory connections. */ + struct config_line_t *DirPort_lines; + /** Ports to listen on for DNS requests. */ + struct config_line_t *DNSPort_lines; + + /* MaxMemInQueues value as input by the user. We clean this up to be + * MaxMemInQueues. */ + uint64_t MaxMemInQueues_raw; + uint64_t MaxMemInQueues;/**< If we have more memory than this allocated + * for queues and buffers, run the OOM handler */ + /** Above this value, consider ourselves low on RAM. */ + uint64_t MaxMemInQueues_low_threshold; + + /** @name port booleans + * + * Derived booleans: For server ports and ControlPort, true iff there is a + * non-listener port on an AF_INET or AF_INET6 address of the given type + * configured in one of the _lines options above. + * For client ports, also true if there is a unix socket configured. + * If you are checking for client ports, you may want to use: + * SocksPort_set || TransPort_set || NATDPort_set || DNSPort_set || + * HTTPTunnelPort_set + * rather than SocksPort_set. + * + * @{ + */ + unsigned int ORPort_set : 1; + unsigned int SocksPort_set : 1; + unsigned int TransPort_set : 1; + unsigned int NATDPort_set : 1; + unsigned int ControlPort_set : 1; + unsigned int DirPort_set : 1; + unsigned int DNSPort_set : 1; + unsigned int ExtORPort_set : 1; + unsigned int HTTPTunnelPort_set : 1; + /**@}*/ + + int AssumeReachable; /**< Whether to publish our descriptor regardless. */ + int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */ + int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory + * for version 3 directories? */ + int VersioningAuthoritativeDir; /**< Boolean: is this an authoritative + * directory that's willing to recommend + * versions? */ + int BridgeAuthoritativeDir; /**< Boolean: is this an authoritative directory + * that aggregates bridge descriptors? */ + + /** If set on a bridge relay, it will include this value on a new + * "bridge-distribution-request" line in its bridge descriptor. */ + char *BridgeDistribution; + + /** If set on a bridge authority, it will answer requests on its dirport + * for bridge statuses -- but only if the requests use this password. */ + char *BridgePassword; + /** If BridgePassword is set, this is a SHA256 digest of the basic http + * authenticator for it. Used so we can do a time-independent comparison. */ + char *BridgePassword_AuthDigest_; + + int UseBridges; /**< Boolean: should we start all circuits with a bridge? */ + struct config_line_t *Bridges; /**< List of bootstrap bridge addresses. */ + + struct config_line_t *ClientTransportPlugin; /**< List of client + transport plugins. */ + + struct config_line_t *ServerTransportPlugin; /**< List of client + transport plugins. */ + + /** List of TCP/IP addresses that transports should listen at. */ + struct config_line_t *ServerTransportListenAddr; + + /** List of options that must be passed to pluggable transports. */ + struct config_line_t *ServerTransportOptions; + + int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make + * this explicit so we can change how we behave in the + * future. */ + + /** Boolean: if we know the bridge's digest, should we get new + * descriptors from the bridge authorities or from the bridge itself? */ + int UpdateBridgesFromAuthority; + + int AvoidDiskWrites; /**< Boolean: should we never cache things to disk? + * Not used yet. */ + int ClientOnly; /**< Boolean: should we never evolve into a server role? */ + + int ReducedConnectionPadding; /**< Boolean: Should we try to keep connections + open shorter and pad them less against + connection-level traffic analysis? */ + /** Autobool: if auto, then connection padding will be negotiated by client + * and server. If 0, it will be fully disabled. If 1, the client will still + * pad to the server regardless of server support. */ + int ConnectionPadding; + + /** To what authority types do we publish our descriptor? Choices are + * "v1", "v2", "v3", "bridge", or "". */ + struct smartlist_t *PublishServerDescriptor; + /** A bitfield of authority types, derived from PublishServerDescriptor. */ + dirinfo_type_t PublishServerDescriptor_; + /** Boolean: do we publish hidden service descriptors to the HS auths? */ + int PublishHidServDescriptors; + int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */ + int FetchHidServDescriptors; /**< and hidden service descriptors? */ + + int MinUptimeHidServDirectoryV2; /**< As directory authority, accept hidden + * service directories after what time? */ + + int FetchUselessDescriptors; /**< Do we fetch non-running descriptors too? */ + int AllDirActionsPrivate; /**< Should every directory action be sent + * through a Tor circuit? */ + + /** Run in 'tor2web mode'? (I.e. only make client connections to hidden + * services, and use a single hop for all hidden-service-related + * circuits.) */ + int Tor2webMode; + + /** A routerset that should be used when picking RPs for HS circuits. */ + routerset_t *Tor2webRendezvousPoints; + + /** A routerset that should be used when picking middle nodes for HS + * circuits. */ + routerset_t *HSLayer2Nodes; + + /** A routerset that should be used when picking third-hop nodes for HS + * circuits. */ + routerset_t *HSLayer3Nodes; + + /** Onion Services in HiddenServiceSingleHopMode make one-hop (direct) + * circuits between the onion service server, and the introduction and + * rendezvous points. (Onion service descriptors are still posted using + * 3-hop paths, to avoid onion service directories blocking the service.) + * This option makes every hidden service instance hosted by + * this tor instance a Single Onion Service. + * HiddenServiceSingleHopMode requires HiddenServiceNonAnonymousMode to be + * set to 1. + * Use rend_service_allow_non_anonymous_connection() or + * rend_service_reveal_startup_time() instead of using this option directly. + */ + int HiddenServiceSingleHopMode; + /* Makes hidden service clients and servers non-anonymous on this tor + * instance. Allows the non-anonymous HiddenServiceSingleHopMode. Enables + * non-anonymous behaviour in the hidden service protocol. + * Use rend_service_non_anonymous_mode_enabled() instead of using this option + * directly. + */ + int HiddenServiceNonAnonymousMode; + + int ConnLimit; /**< Demanded minimum number of simultaneous connections. */ + int ConnLimit_; /**< Maximum allowed number of simultaneous connections. */ + int ConnLimit_high_thresh; /**< start trying to lower socket usage if we + * have this many. */ + int ConnLimit_low_thresh; /**< try to get down to here after socket + * exhaustion. */ + int RunAsDaemon; /**< If true, run in the background. (Unix only) */ + int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */ + struct smartlist_t *FirewallPorts; /**< Which ports our firewall allows + * (strings). */ + /** IP:ports our firewall allows. */ + struct config_line_t *ReachableAddresses; + struct config_line_t *ReachableORAddresses; /**< IP:ports for OR conns. */ + struct config_line_t *ReachableDirAddresses; /**< IP:ports for Dir conns. */ + + int ConstrainedSockets; /**< Shrink xmit and recv socket buffers. */ + uint64_t ConstrainedSockSize; /**< Size of constrained buffers. */ + + /** Whether we should drop exit streams from Tors that we don't know are + * relays. One of "0" (never refuse), "1" (always refuse), or "-1" (do + * what the consensus says, defaulting to 'refuse' if the consensus says + * nothing). */ + int RefuseUnknownExits; + + /** Application ports that require all nodes in circ to have sufficient + * uptime. */ + struct smartlist_t *LongLivedPorts; + /** Application ports that are likely to be unencrypted and + * unauthenticated; we reject requests for them to prevent the + * user from screwing up and leaking plaintext secrets to an + * observer somewhere on the Internet. */ + struct smartlist_t *RejectPlaintextPorts; + /** Related to RejectPlaintextPorts above, except this config option + * controls whether we warn (in the log and via a controller status + * event) every time a risky connection is attempted. */ + struct smartlist_t *WarnPlaintextPorts; + /** Should we try to reuse the same exit node for a given host */ + struct smartlist_t *TrackHostExits; + int TrackHostExitsExpire; /**< Number of seconds until we expire an + * addressmap */ + struct config_line_t *AddressMap; /**< List of address map directives. */ + int AutomapHostsOnResolve; /**< If true, when we get a resolve request for a + * hostname ending with one of the suffixes in + * <b>AutomapHostsSuffixes</b>, map it to a + * virtual address. */ + /** List of suffixes for <b>AutomapHostsOnResolve</b>. The special value + * "." means "match everything." */ + struct smartlist_t *AutomapHostsSuffixes; + int RendPostPeriod; /**< How often do we post each rendezvous service + * descriptor? Remember to publish them independently. */ + int KeepalivePeriod; /**< How often do we send padding cells to keep + * connections alive? */ + int SocksTimeout; /**< How long do we let a socks connection wait + * unattached before we fail it? */ + int LearnCircuitBuildTimeout; /**< If non-zero, we attempt to learn a value + * for CircuitBuildTimeout based on timeout + * history. Use circuit_build_times_disabled() + * rather than checking this value directly. */ + int CircuitBuildTimeout; /**< Cull non-open circuits that were born at + * least this many seconds ago. Used until + * adaptive algorithm learns a new value. */ + int CircuitsAvailableTimeout; /**< Try to have an open circuit for at + least this long after last activity */ + int CircuitStreamTimeout; /**< If non-zero, detach streams from circuits + * and try a new circuit if the stream has been + * waiting for this many seconds. If zero, use + * our default internal timeout schedule. */ + int MaxOnionQueueDelay; /*< DOCDOC */ + int NewCircuitPeriod; /**< How long do we use a circuit before building + * a new one? */ + int MaxCircuitDirtiness; /**< Never use circs that were first used more than + this interval ago. */ + uint64_t BandwidthRate; /**< How much bandwidth, on average, are we willing + * to use in a second? */ + uint64_t BandwidthBurst; /**< How much bandwidth, at maximum, are we willing + * to use in a second? */ + uint64_t MaxAdvertisedBandwidth; /**< How much bandwidth are we willing to + * tell other nodes we have? */ + uint64_t RelayBandwidthRate; /**< How much bandwidth, on average, are we + * willing to use for all relayed conns? */ + uint64_t RelayBandwidthBurst; /**< How much bandwidth, at maximum, will we + * use in a second for all relayed conns? */ + uint64_t PerConnBWRate; /**< Long-term bw on a single TLS conn, if set. */ + uint64_t PerConnBWBurst; /**< Allowed burst on a single TLS conn, if set. */ + int NumCPUs; /**< How many CPUs should we try to use? */ + struct config_line_t *RendConfigLines; /**< List of configuration lines + * for rendezvous services. */ + struct config_line_t *HidServAuth; /**< List of configuration lines for + * client-side authorizations for hidden + * services */ + char *ContactInfo; /**< Contact info to be published in the directory. */ + + int HeartbeatPeriod; /**< Log heartbeat messages after this many seconds + * have passed. */ + int MainloopStats; /**< Log main loop statistics as part of the + * heartbeat messages. */ + + char *HTTPProxy; /**< hostname[:port] to use as http proxy, if any. */ + tor_addr_t HTTPProxyAddr; /**< Parsed IPv4 addr for http proxy, if any. */ + uint16_t HTTPProxyPort; /**< Parsed port for http proxy, if any. */ + char *HTTPProxyAuthenticator; /**< username:password string, if any. */ + + char *HTTPSProxy; /**< hostname[:port] to use as https proxy, if any. */ + tor_addr_t HTTPSProxyAddr; /**< Parsed addr for https proxy, if any. */ + uint16_t HTTPSProxyPort; /**< Parsed port for https proxy, if any. */ + char *HTTPSProxyAuthenticator; /**< username:password string, if any. */ + + char *Socks4Proxy; /**< hostname:port to use as a SOCKS4 proxy, if any. */ + tor_addr_t Socks4ProxyAddr; /**< Derived from Socks4Proxy. */ + uint16_t Socks4ProxyPort; /**< Derived from Socks4Proxy. */ + + char *Socks5Proxy; /**< hostname:port to use as a SOCKS5 proxy, if any. */ + tor_addr_t Socks5ProxyAddr; /**< Derived from Sock5Proxy. */ + uint16_t Socks5ProxyPort; /**< Derived from Socks5Proxy. */ + char *Socks5ProxyUsername; /**< Username for SOCKS5 authentication, if any */ + char *Socks5ProxyPassword; /**< Password for SOCKS5 authentication, if any */ + + /** List of configuration lines for replacement directory authorities. + * If you just want to replace one class of authority at a time, + * use the "Alternate*Authority" options below instead. */ + struct config_line_t *DirAuthorities; + + /** List of fallback directory servers */ + struct config_line_t *FallbackDir; + /** Whether to use the default hard-coded FallbackDirs */ + int UseDefaultFallbackDirs; + + /** Weight to apply to all directory authority rates if considering them + * along with fallbackdirs */ + double DirAuthorityFallbackRate; + + /** If set, use these main (currently v3) directory authorities and + * not the default ones. */ + struct config_line_t *AlternateDirAuthority; + + /** If set, use these bridge authorities and not the default one. */ + struct config_line_t *AlternateBridgeAuthority; + + struct config_line_t *MyFamily_lines; /**< Declared family for this OR. */ + struct config_line_t *MyFamily; /**< Declared family for this OR, + normalized */ + struct config_line_t *NodeFamilies; /**< List of config lines for + * node families */ + /** List of parsed NodeFamilies values. */ + struct smartlist_t *NodeFamilySets; + struct config_line_t *AuthDirBadExit; /**< Address policy for descriptors to + * mark as bad exits. */ + struct config_line_t *AuthDirReject; /**< Address policy for descriptors to + * reject. */ + struct config_line_t *AuthDirInvalid; /**< Address policy for descriptors to + * never mark as valid. */ + /** @name AuthDir...CC + * + * Lists of country codes to mark as BadExit, or Invalid, or to + * reject entirely. + * + * @{ + */ + struct smartlist_t *AuthDirBadExitCCs; + struct smartlist_t *AuthDirInvalidCCs; + struct smartlist_t *AuthDirRejectCCs; + /**@}*/ + + int AuthDirListBadExits; /**< True iff we should list bad exits, + * and vote for all other exits as good. */ + int AuthDirMaxServersPerAddr; /**< Do not permit more than this + * number of servers per IP address. */ + int AuthDirHasIPv6Connectivity; /**< Boolean: are we on IPv6? */ + int AuthDirPinKeys; /**< Boolean: Do we enforce key-pinning? */ + + /** If non-zero, always vote the Fast flag for any relay advertising + * this amount of capacity or more. */ + uint64_t AuthDirFastGuarantee; + + /** If non-zero, this advertised capacity or more is always sufficient + * to satisfy the bandwidth requirement for the Guard flag. */ + uint64_t AuthDirGuardBWGuarantee; + + char *AccountingStart; /**< How long is the accounting interval, and when + * does it start? */ + uint64_t AccountingMax; /**< How many bytes do we allow per accounting + * interval before hibernation? 0 for "never + * hibernate." */ + /** How do we determine when our AccountingMax has been reached? + * "max" for when in or out reaches AccountingMax + * "sum" for when in plus out reaches AccountingMax + * "in" for when in reaches AccountingMax + * "out" for when out reaches AccountingMax */ + char *AccountingRule_option; + enum { ACCT_MAX, ACCT_SUM, ACCT_IN, ACCT_OUT } AccountingRule; + + /** Base64-encoded hash of accepted passwords for the control system. */ + struct config_line_t *HashedControlPassword; + /** As HashedControlPassword, but not saved. */ + struct config_line_t *HashedControlSessionPassword; + + int CookieAuthentication; /**< Boolean: do we enable cookie-based auth for + * the control system? */ + char *CookieAuthFile; /**< Filesystem location of a ControlPort + * authentication cookie. */ + char *ExtORPortCookieAuthFile; /**< Filesystem location of Extended + * ORPort authentication cookie. */ + int CookieAuthFileGroupReadable; /**< Boolean: Is the CookieAuthFile g+r? */ + int ExtORPortCookieAuthFileGroupReadable; /**< Boolean: Is the + * ExtORPortCookieAuthFile g+r? */ + int LeaveStreamsUnattached; /**< Boolean: Does Tor attach new streams to + * circuits itself (0), or does it expect a controller + * to cope? (1) */ + int DisablePredictedCircuits; /**< Boolean: does Tor preemptively + * make circuits in the background (0), + * or not (1)? */ + + /** Process specifier for a controller that ‘owns’ this Tor + * instance. Tor will terminate if its owning controller does. */ + char *OwningControllerProcess; + /** FD specifier for a controller that owns this Tor instance. */ + int OwningControllerFD; + + int ShutdownWaitLength; /**< When we get a SIGINT and we're a server, how + * long do we wait before exiting? */ + char *SafeLogging; /**< Contains "relay", "1", "0" (meaning no scrubbing). */ + + /* Derived from SafeLogging */ + enum { + SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE + } SafeLogging_; + + int Sandbox; /**< Boolean: should sandboxing be enabled? */ + int SafeSocks; /**< Boolean: should we outright refuse application + * connections that use socks4 or socks5-with-local-dns? */ + int ProtocolWarnings; /**< Boolean: when other parties screw up the Tor + * protocol, is it a warn or an info in our logs? */ + int TestSocks; /**< Boolean: when we get a socks connection, do we loudly + * log whether it was DNS-leaking or not? */ + int HardwareAccel; /**< Boolean: Should we enable OpenSSL hardware + * acceleration where available? */ + /** Token Bucket Refill resolution in milliseconds. */ + int TokenBucketRefillInterval; + char *AccelName; /**< Optional hardware acceleration engine name. */ + char *AccelDir; /**< Optional hardware acceleration engine search dir. */ + + /** Boolean: Do we try to enter from a smallish number + * of fixed nodes? */ + int UseEntryGuards_option; + /** Internal variable to remember whether we're actually acting on + * UseEntryGuards_option -- when we're a non-anonymous Tor2web client or + * Single Onion Service, it is always false, otherwise we use the value of + * UseEntryGuards_option. */ + int UseEntryGuards; + + int NumEntryGuards; /**< How many entry guards do we try to establish? */ + + /** If 1, we use any guardfraction information we see in the + * consensus. If 0, we don't. If -1, let the consensus parameter + * decide. */ + int UseGuardFraction; + + int NumDirectoryGuards; /**< How many dir guards do we try to establish? + * If 0, use value from NumEntryGuards. */ + int NumPrimaryGuards; /**< How many primary guards do we want? */ + + int RephistTrackTime; /**< How many seconds do we keep rephist info? */ + /** Should we always fetch our dir info on the mirror schedule (which + * means directly from the authorities) no matter our other config? */ + int FetchDirInfoEarly; + + /** Should we fetch our dir info at the start of the consensus period? */ + int FetchDirInfoExtraEarly; + + int DirCache; /**< Cache all directory documents and accept requests via + * tunnelled dir conns from clients. If 1, enabled (default); + * If 0, disabled. */ + + char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual + * MAPADDRESS requests for IPv4 addresses */ + char *VirtualAddrNetworkIPv6; /**< Address and mask to hand out for virtual + * MAPADDRESS requests for IPv6 addresses */ + int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit + * addresses to be FQDNs, but rather search for them in + * the local domains. */ + int ServerDNSDetectHijacking; /**< Boolean: If true, check for DNS failure + * hijacking. */ + int ServerDNSRandomizeCase; /**< Boolean: Use the 0x20-hack to prevent + * DNS poisoning attacks. */ + char *ServerDNSResolvConfFile; /**< If provided, we configure our internal + * resolver from the file here rather than from + * /etc/resolv.conf (Unix) or the registry (Windows). */ + char *DirPortFrontPage; /**< This is a full path to a file with an html + disclaimer. This allows a server administrator to show + that they're running Tor and anyone visiting their server + will know this without any specialized knowledge. */ + int DisableDebuggerAttachment; /**< Currently Linux only specific attempt to + disable ptrace; needs BSD testing. */ + /** Boolean: if set, we start even if our resolv.conf file is missing + * or broken. */ + int ServerDNSAllowBrokenConfig; + /** Boolean: if set, then even connections to private addresses will get + * rate-limited. */ + int CountPrivateBandwidth; + /** A list of addresses that definitely should be resolvable. Used for + * testing our DNS server. */ + struct smartlist_t *ServerDNSTestAddresses; + int EnforceDistinctSubnets; /**< If true, don't allow multiple routers in the + * same network zone in the same circuit. */ + int AllowNonRFC953Hostnames; /**< If true, we allow connections to hostnames + * with weird characters. */ + /** If true, we try resolving hostnames with weird characters. */ + int ServerDNSAllowNonRFC953Hostnames; + + /** If true, we try to download extra-info documents (and we serve them, + * if we are a cache). For authorities, this is always true. */ + int DownloadExtraInfo; + + /** If true, we're configured to collect statistics on clients + * requesting network statuses from us as directory. */ + int DirReqStatistics_option; + /** Internal variable to remember whether we're actually acting on + * DirReqStatistics_option -- yes if it's set and we're a server, else no. */ + int DirReqStatistics; + + /** If true, the user wants us to collect statistics on port usage. */ + int ExitPortStatistics; + + /** If true, the user wants us to collect connection statistics. */ + int ConnDirectionStatistics; + + /** If true, the user wants us to collect cell statistics. */ + int CellStatistics; + + /** If true, the user wants us to collect padding statistics. */ + int PaddingStatistics; + + /** If true, the user wants us to collect statistics as entry node. */ + int EntryStatistics; + + /** If true, the user wants us to collect statistics as hidden service + * directory, introduction point, or rendezvous point. */ + int HiddenServiceStatistics_option; + /** Internal variable to remember whether we're actually acting on + * HiddenServiceStatistics_option -- yes if it's set and we're a server, + * else no. */ + int HiddenServiceStatistics; + + /** If true, include statistics file contents in extra-info documents. */ + int ExtraInfoStatistics; + + /** If true, do not believe anybody who tells us that a domain resolves + * to an internal address, or that an internal address has a PTR mapping. + * Helps avoid some cross-site attacks. */ + int ClientDNSRejectInternalAddresses; + + /** If true, do not accept any requests to connect to internal addresses + * over randomly chosen exits. */ + int ClientRejectInternalAddresses; + + /** If true, clients may connect over IPv4. If false, they will avoid + * connecting over IPv4. We enforce this for OR and Dir connections. */ + int ClientUseIPv4; + /** If true, clients may connect over IPv6. If false, they will avoid + * connecting over IPv4. We enforce this for OR and Dir connections. + * Use fascist_firewall_use_ipv6() instead of accessing this value + * directly. */ + int ClientUseIPv6; + /** If true, prefer an IPv6 OR port over an IPv4 one for entry node + * connections. If auto, bridge clients prefer IPv6, and other clients + * prefer IPv4. Use node_ipv6_or_preferred() instead of accessing this value + * directly. */ + int ClientPreferIPv6ORPort; + /** If true, prefer an IPv6 directory port over an IPv4 one for direct + * directory connections. If auto, bridge clients prefer IPv6, and other + * clients prefer IPv4. Use fascist_firewall_prefer_ipv6_dirport() instead of + * accessing this value directly. */ + int ClientPreferIPv6DirPort; + + /** The length of time that we think a consensus should be fresh. */ + int V3AuthVotingInterval; + /** The length of time we think it will take to distribute votes. */ + int V3AuthVoteDelay; + /** The length of time we think it will take to distribute signatures. */ + int V3AuthDistDelay; + /** The number of intervals we think a consensus should be valid. */ + int V3AuthNIntervalsValid; + + /** Should advertise and sign consensuses with a legacy key, for key + * migration purposes? */ + int V3AuthUseLegacyKey; + + /** Location of bandwidth measurement file */ + char *V3BandwidthsFile; + + /** Location of guardfraction file */ + char *GuardfractionFile; + + /** Authority only: key=value pairs that we add to our networkstatus + * consensus vote on the 'params' line. */ + char *ConsensusParams; + + /** Authority only: minimum number of measured bandwidths we must see + * before we only believe measured bandwidths to assign flags. */ + int MinMeasuredBWsForAuthToIgnoreAdvertised; + + /** The length of time that we think an initial consensus should be fresh. + * Only altered on testing networks. */ + int TestingV3AuthInitialVotingInterval; + + /** The length of time we think it will take to distribute initial votes. + * Only altered on testing networks. */ + int TestingV3AuthInitialVoteDelay; + + /** The length of time we think it will take to distribute initial + * signatures. Only altered on testing networks.*/ + int TestingV3AuthInitialDistDelay; + + /** Offset in seconds added to the starting time for consensus + voting. Only altered on testing networks. */ + int TestingV3AuthVotingStartOffset; + + /** If an authority has been around for less than this amount of time, it + * does not believe its reachability information is accurate. Only + * altered on testing networks. */ + int TestingAuthDirTimeToLearnReachability; + + /** Clients don't download any descriptor this recent, since it will + * probably not have propagated to enough caches. Only altered on testing + * networks. */ + int TestingEstimatedDescriptorPropagationTime; + + /** Schedule for when servers should download things in general. Only + * altered on testing networks. */ + int TestingServerDownloadInitialDelay; + + /** Schedule for when clients should download things in general. Only + * altered on testing networks. */ + int TestingClientDownloadInitialDelay; + + /** Schedule for when servers should download consensuses. Only altered + * on testing networks. */ + int TestingServerConsensusDownloadInitialDelay; + + /** Schedule for when clients should download consensuses. Only altered + * on testing networks. */ + int TestingClientConsensusDownloadInitialDelay; + + /** Schedule for when clients should download consensuses from authorities + * if they are bootstrapping (that is, they don't have a usable, reasonably + * live consensus). Only used by clients fetching from a list of fallback + * directory mirrors. + * + * This schedule is incremented by (potentially concurrent) connection + * attempts, unlike other schedules, which are incremented by connection + * failures. Only altered on testing networks. */ + int ClientBootstrapConsensusAuthorityDownloadInitialDelay; + + /** Schedule for when clients should download consensuses from fallback + * directory mirrors if they are bootstrapping (that is, they don't have a + * usable, reasonably live consensus). Only used by clients fetching from a + * list of fallback directory mirrors. + * + * This schedule is incremented by (potentially concurrent) connection + * attempts, unlike other schedules, which are incremented by connection + * failures. Only altered on testing networks. */ + int ClientBootstrapConsensusFallbackDownloadInitialDelay; + + /** Schedule for when clients should download consensuses from authorities + * if they are bootstrapping (that is, they don't have a usable, reasonably + * live consensus). Only used by clients which don't have or won't fetch + * from a list of fallback directory mirrors. + * + * This schedule is incremented by (potentially concurrent) connection + * attempts, unlike other schedules, which are incremented by connection + * failures. Only altered on testing networks. */ + int ClientBootstrapConsensusAuthorityOnlyDownloadInitialDelay; + + /** Schedule for when clients should download bridge descriptors. Only + * altered on testing networks. */ + int TestingBridgeDownloadInitialDelay; + + /** Schedule for when clients should download bridge descriptors when they + * have no running bridges. Only altered on testing networks. */ + int TestingBridgeBootstrapDownloadInitialDelay; + + /** When directory clients have only a few descriptors to request, they + * batch them until they have more, or until this amount of time has + * passed. Only altered on testing networks. */ + int TestingClientMaxIntervalWithoutRequest; + + /** How long do we let a directory connection stall before expiring + * it? Only altered on testing networks. */ + int TestingDirConnectionMaxStall; + + /** How many simultaneous in-progress connections will we make when trying + * to fetch a consensus before we wait for one to complete, timeout, or + * error out? Only altered on testing networks. */ + int ClientBootstrapConsensusMaxInProgressTries; + + /** If true, we take part in a testing network. Change the defaults of a + * couple of other configuration options and allow to change the values + * of certain configuration options. */ + int TestingTorNetwork; + + /** Minimum value for the Exit flag threshold on testing networks. */ + uint64_t TestingMinExitFlagThreshold; + + /** Minimum value for the Fast flag threshold on testing networks. */ + uint64_t TestingMinFastFlagThreshold; + + /** Relays in a testing network which should be voted Exit + * regardless of exit policy. */ + routerset_t *TestingDirAuthVoteExit; + int TestingDirAuthVoteExitIsStrict; + + /** Relays in a testing network which should be voted Guard + * regardless of uptime and bandwidth. */ + routerset_t *TestingDirAuthVoteGuard; + int TestingDirAuthVoteGuardIsStrict; + + /** Relays in a testing network which should be voted HSDir + * regardless of uptime and DirPort. */ + routerset_t *TestingDirAuthVoteHSDir; + int TestingDirAuthVoteHSDirIsStrict; + + /** Enable CONN_BW events. Only altered on testing networks. */ + int TestingEnableConnBwEvent; + + /** Enable CELL_STATS events. Only altered on testing networks. */ + int TestingEnableCellStatsEvent; + + /** If true, and we have GeoIP data, and we're a bridge, keep a per-country + * count of how many client addresses have contacted us so that we can help + * the bridge authority guess which countries have blocked access to us. */ + int BridgeRecordUsageByCountry; + + /** Optionally, IPv4 and IPv6 GeoIP data. */ + char *GeoIPFile; + char *GeoIPv6File; + + /** Autobool: if auto, then any attempt to Exclude{Exit,}Nodes a particular + * country code will exclude all nodes in ?? and A1. If true, all nodes in + * ?? and A1 are excluded. Has no effect if we don't know any GeoIP data. */ + int GeoIPExcludeUnknown; + + /** If true, SIGHUP should reload the torrc. Sometimes controllers want + * to make this false. */ + int ReloadTorrcOnSIGHUP; + + /* The main parameter for picking circuits within a connection. + * + * If this value is positive, when picking a cell to relay on a connection, + * we always relay from the circuit whose weighted cell count is lowest. + * Cells are weighted exponentially such that if one cell is sent + * 'CircuitPriorityHalflife' seconds before another, it counts for half as + * much. + * + * If this value is zero, we're disabling the cell-EWMA algorithm. + * + * If this value is negative, we're using the default approach + * according to either Tor or a parameter set in the consensus. + */ + double CircuitPriorityHalflife; + + /** Set to true if the TestingTorNetwork configuration option is set. + * This is used so that options_validate() has a chance to realize that + * the defaults have changed. */ + int UsingTestNetworkDefaults_; + + /** If 1, we try to use microdescriptors to build circuits. If 0, we don't. + * If -1, Tor decides. */ + int UseMicrodescriptors; + + /** File where we should write the ControlPort. */ + char *ControlPortWriteToFile; + /** Should that file be group-readable? */ + int ControlPortFileGroupReadable; + +#define MAX_MAX_CLIENT_CIRCUITS_PENDING 1024 + /** Maximum number of non-open general-purpose origin circuits to allow at + * once. */ + int MaxClientCircuitsPending; + + /** If 1, we always send optimistic data when it's supported. If 0, we + * never use it. If -1, we do what the consensus says. */ + int OptimisticData; + + /** If 1, we accept and launch no external network connections, except on + * control ports. */ + int DisableNetwork; + + /** + * Parameters for path-bias detection. + * @{ + * These options override the default behavior of Tor's (**currently + * experimental**) path bias detection algorithm. To try to find broken or + * misbehaving guard nodes, Tor looks for nodes where more than a certain + * fraction of circuits through that guard fail to get built. + * + * The PathBiasCircThreshold option controls how many circuits we need to + * build through a guard before we make these checks. The + * PathBiasNoticeRate, PathBiasWarnRate and PathBiasExtremeRate options + * control what fraction of circuits must succeed through a guard so we + * won't write log messages. If less than PathBiasExtremeRate circuits + * succeed *and* PathBiasDropGuards is set to 1, we disable use of that + * guard. + * + * When we have seen more than PathBiasScaleThreshold circuits through a + * guard, we scale our observations by 0.5 (governed by the consensus) so + * that new observations don't get swamped by old ones. + * + * By default, or if a negative value is provided for one of these options, + * Tor uses reasonable defaults from the networkstatus consensus document. + * If no defaults are available there, these options default to 150, .70, + * .50, .30, 0, and 300 respectively. + */ + int PathBiasCircThreshold; + double PathBiasNoticeRate; + double PathBiasWarnRate; + double PathBiasExtremeRate; + int PathBiasDropGuards; + int PathBiasScaleThreshold; + /** @} */ + + /** + * Parameters for path-bias use detection + * @{ + * Similar to the above options, these options override the default behavior + * of Tor's (**currently experimental**) path use bias detection algorithm. + * + * Where as the path bias parameters govern thresholds for successfully + * building circuits, these four path use bias parameters govern thresholds + * only for circuit usage. Circuits which receive no stream usage are not + * counted by this detection algorithm. A used circuit is considered + * successful if it is capable of carrying streams or otherwise receiving + * well-formed responses to RELAY cells. + * + * By default, or if a negative value is provided for one of these options, + * Tor uses reasonable defaults from the networkstatus consensus document. + * If no defaults are available there, these options default to 20, .80, + * .60, and 100, respectively. + */ + int PathBiasUseThreshold; + double PathBiasNoticeUseRate; + double PathBiasExtremeUseRate; + int PathBiasScaleUseThreshold; + /** @} */ + + int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */ + + /** Fraction: */ + double PathsNeededToBuildCircuits; + + /** What expiry time shall we place on our SSL certs? "0" means we + * should guess a suitable value. */ + int SSLKeyLifetime; + + /** How long (seconds) do we keep a guard before picking a new one? */ + int GuardLifetime; + + /** Is this an exit node? This is a tristate, where "1" means "yes, and use + * the default exit policy if none is given" and "0" means "no; exit policy + * is 'reject *'" and "auto" (-1) means "same as 1, but warn the user." + * + * XXXX Eventually, the default will be 0. */ + int ExitRelay; + + /** For how long (seconds) do we declare our signing keys to be valid? */ + int SigningKeyLifetime; + /** For how long (seconds) do we declare our link keys to be valid? */ + int TestingLinkCertLifetime; + /** For how long (seconds) do we declare our auth keys to be valid? */ + int TestingAuthKeyLifetime; + + /** How long before signing keys expire will we try to make a new one? */ + int TestingSigningKeySlop; + /** How long before link keys expire will we try to make a new one? */ + int TestingLinkKeySlop; + /** How long before auth keys expire will we try to make a new one? */ + int TestingAuthKeySlop; + + /** Force use of offline master key features: never generate a master + * ed25519 identity key except from tor --keygen */ + int OfflineMasterKey; + + enum { + FORCE_PASSPHRASE_AUTO=0, + FORCE_PASSPHRASE_ON, + FORCE_PASSPHRASE_OFF + } keygen_force_passphrase; + int use_keygen_passphrase_fd; + int keygen_passphrase_fd; + int change_key_passphrase; + char *master_key_fname; + + /** Autobool: Do we try to retain capabilities if we can? */ + int KeepBindCapabilities; + + /** Maximum total size of unparseable descriptors to log during the + * lifetime of this Tor process. + */ + uint64_t MaxUnparseableDescSizeToLog; + + /** Bool (default: 1): Switch for the shared random protocol. Only + * relevant to a directory authority. If off, the authority won't + * participate in the protocol. If on (default), a flag is added to the + * vote indicating participation. */ + int AuthDirSharedRandomness; + + /** If 1, we skip all OOS checks. */ + int DisableOOSCheck; + + /** Autobool: Should we include Ed25519 identities in extend2 cells? + * If -1, we should do whatever the consensus parameter says. */ + int ExtendByEd25519ID; + + /** Bool (default: 1): When testing routerinfos as a directory authority, + * do we enforce Ed25519 identity match? */ + /* NOTE: remove this option someday. */ + int AuthDirTestEd25519LinkKeys; + + /** Bool (default: 0): Tells if a %include was used on torrc */ + int IncludeUsed; + + /** The seconds after expiration which we as a relay should keep old + * consensuses around so that we can generate diffs from them. If 0, + * use the default. */ + int MaxConsensusAgeForDiffs; + + /** Bool (default: 0). Tells Tor to never try to exec another program. + */ + int NoExec; + + /** Have the KIST scheduler run every X milliseconds. If less than zero, do + * not use the KIST scheduler but use the old vanilla scheduler instead. If + * zero, do what the consensus says and fall back to using KIST as if this is + * set to "10 msec" if the consensus doesn't say anything. */ + int KISTSchedRunInterval; + + /** A multiplier for the KIST per-socket limit calculation. */ + double KISTSockBufSizeFactor; + + /** The list of scheduler type string ordered by priority that is first one + * has to be tried first. Default: KIST,KISTLite,Vanilla */ + struct smartlist_t *Schedulers; + /* An ordered list of scheduler_types mapped from Schedulers. */ + struct smartlist_t *SchedulerTypes_; + + /** List of files that were opened by %include in torrc and torrc-defaults */ + struct smartlist_t *FilesOpenedByIncludes; + + /** If true, Tor shouldn't install any posix signal handlers, since it is + * running embedded inside another process. + */ + int DisableSignalHandlers; + + /** Autobool: Is the circuit creation DoS mitigation subsystem enabled? */ + int DoSCircuitCreationEnabled; + /** Minimum concurrent connection needed from one single address before any + * defense is used. */ + int DoSCircuitCreationMinConnections; + /** Circuit rate used to refill the token bucket. */ + int DoSCircuitCreationRate; + /** Maximum allowed burst of circuits. Reaching that value, the address is + * detected as malicious and a defense might be used. */ + int DoSCircuitCreationBurst; + /** When an address is marked as malicous, what defense should be used + * against it. See the dos_cc_defense_type_t enum. */ + int DoSCircuitCreationDefenseType; + /** For how much time (in seconds) the defense is applicable for a malicious + * address. A random time delta is added to the defense time of an address + * which will be between 1 second and half of this value. */ + int DoSCircuitCreationDefenseTimePeriod; + + /** Autobool: Is the DoS connection mitigation subsystem enabled? */ + int DoSConnectionEnabled; + /** Maximum concurrent connection allowed per address. */ + int DoSConnectionMaxConcurrentCount; + /** When an address is reaches the maximum count, what defense should be + * used against it. See the dos_conn_defense_type_t enum. */ + int DoSConnectionDefenseType; + + /** Autobool: Do we refuse single hop client rendezvous? */ + int DoSRefuseSingleHopClientRendezvous; +}; + +#endif diff --git a/src/app/config/or_state_st.h b/src/app/config/or_state_st.h new file mode 100644 index 0000000000..f1d5f981f1 --- /dev/null +++ b/src/app/config/or_state_st.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_OR_STATE_ST_H +#define TOR_OR_STATE_ST_H + +#include "lib/cc/torint.h" +struct smartlist_t; + +/** Persistent state for an onion router, as saved to disk. */ +struct or_state_t { + uint32_t magic_; + /** The time at which we next plan to write the state to the disk. Equal to + * TIME_MAX if there are no savable changes, 0 if there are changes that + * should be saved right away. */ + time_t next_write; + + /** When was the state last written to disk? */ + time_t LastWritten; + + /** Fields for accounting bandwidth use. */ + time_t AccountingIntervalStart; + uint64_t AccountingBytesReadInInterval; + uint64_t AccountingBytesWrittenInInterval; + int AccountingSecondsActive; + int AccountingSecondsToReachSoftLimit; + time_t AccountingSoftLimitHitAt; + uint64_t AccountingBytesAtSoftLimit; + uint64_t AccountingExpectedUsage; + + /** A list of Entry Guard-related configuration lines. (pre-prop271) */ + struct config_line_t *EntryGuards; + + /** A list of guard-related configuration lines. (post-prop271) */ + struct config_line_t *Guard; + + struct config_line_t *TransportProxies; + + /** Cached revision counters for active hidden services on this host */ + struct config_line_t *HidServRevCounter; + + /** These fields hold information on the history of bandwidth usage for + * servers. The "Ends" fields hold the time when we last updated the + * bandwidth usage. The "Interval" fields hold the granularity, in seconds, + * of the entries of Values. The "Values" lists hold decimal string + * representations of the number of bytes read or written in each + * interval. The "Maxima" list holds decimal strings describing the highest + * rate achieved during the interval. + */ + time_t BWHistoryReadEnds; + int BWHistoryReadInterval; + struct smartlist_t *BWHistoryReadValues; + struct smartlist_t *BWHistoryReadMaxima; + time_t BWHistoryWriteEnds; + int BWHistoryWriteInterval; + struct smartlist_t *BWHistoryWriteValues; + struct smartlist_t *BWHistoryWriteMaxima; + time_t BWHistoryDirReadEnds; + int BWHistoryDirReadInterval; + struct smartlist_t *BWHistoryDirReadValues; + struct smartlist_t *BWHistoryDirReadMaxima; + time_t BWHistoryDirWriteEnds; + int BWHistoryDirWriteInterval; + struct smartlist_t *BWHistoryDirWriteValues; + struct smartlist_t *BWHistoryDirWriteMaxima; + + /** Build time histogram */ + struct config_line_t * BuildtimeHistogram; + int TotalBuildTimes; + int CircuitBuildAbandonedCount; + + /** What version of Tor wrote this state file? */ + char *TorVersion; + + /** Holds any unrecognized values we found in the state file, in the order + * in which we found them. */ + struct config_line_t *ExtraLines; + + /** When did we last rotate our onion key? "0" for 'no idea'. */ + time_t LastRotatedOnionKey; +}; + +#endif diff --git a/src/or/statefile.c b/src/app/config/statefile.c index c81ea44e06..8eeef45026 100644 --- a/src/or/statefile.c +++ b/src/app/config/statefile.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -29,19 +29,26 @@ */ #define STATEFILE_PRIVATE -#include "or.h" -#include "circuitstats.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "control.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "main.h" -#include "rephist.h" -#include "router.h" -#include "sandbox.h" -#include "statefile.h" +#include "core/or/or.h" +#include "core/or/circuitstats.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "feature/client/entrynodes.h" +#include "feature/hibernate/hibernate.h" +#include "core/mainloop/main.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "lib/sandbox/sandbox.h" +#include "app/config/statefile.h" +#include "lib/encoding/confline.h" + +#include "app/config/or_state_st.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /** A list of state-file "abbreviations," for compatibility. */ static config_abbrev_t state_abbrevs_[] = { @@ -708,4 +715,3 @@ or_state_free_all(void) or_state_free(global_state); global_state = NULL; } - diff --git a/src/or/statefile.h b/src/app/config/statefile.h index 5aa2ca9320..e996d5b6e6 100644 --- a/src/or/statefile.h +++ b/src/app/config/statefile.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_STATEFILE_H @@ -20,11 +20,11 @@ void or_state_free_all(void); void or_state_mark_dirty(or_state_t *state, time_t when); #ifdef STATEFILE_PRIVATE -STATIC config_line_t *get_transport_in_state_by_name(const char *transport); +STATIC struct config_line_t *get_transport_in_state_by_name( + const char *transport); STATIC void or_state_free_(or_state_t *state); #define or_state_free(st) FREE_AND_NULL(or_state_t, or_state_free_, (st)) STATIC or_state_t *or_state_new(void); #endif #endif /* !defined(TOR_STATEFILE_H) */ - diff --git a/src/app/include.am b/src/app/include.am new file mode 100644 index 0000000000..7cf20191ab --- /dev/null +++ b/src/app/include.am @@ -0,0 +1,35 @@ + +bin_PROGRAMS+= src/app/tor + +if COVERAGE_ENABLED +noinst_PROGRAMS+= src/app/tor-cov +endif + +noinst_HEADERS += \ + src/app/main/ntmain.h + +src_app_tor_SOURCES = src/app/main/tor_main.c + +# -L flags need to go in LDFLAGS. -l flags need to go in LDADD. +# This seems to matter nowhere but on windows, but I assure you that it +# matters a lot there, and is quite hard to debug if you forget to do it. + +src_app_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ +src_app_tor_LDADD = $(TOR_INTERNAL_LIBS) \ + $(rust_ldadd) \ + @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ + @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ + +if COVERAGE_ENABLED +src_app_tor_cov_SOURCES = $(src_app_tor_SOURCES) +src_app_tor_cov_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_app_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) +src_app_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ +src_app_tor_cov_LDADD = $(TOR_INTERNAL_TESTING_LIBS) \ + @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ \ + @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ + @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ +endif diff --git a/src/or/ntmain.c b/src/app/main/ntmain.c index e9a299807a..232529a803 100644 --- a/src/or/ntmain.c +++ b/src/app/main/ntmain.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,10 +19,13 @@ #ifdef _WIN32 -#include "or.h" -#include "config.h" -#include "main.h" -#include "ntmain.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/main.h" +#include "app/main/ntmain.h" +#include "lib/log/win32err.h" +#include "lib/fs/winlib.h" +#include "lib/evloop/compat_libevent.h" #include <windows.h> #define GENSRV_SERVICENAME "tor" @@ -778,4 +781,3 @@ nt_service_parse_options(int argc, char **argv, int *should_exit) } #endif /* defined(_WIN32) */ - diff --git a/src/or/ntmain.h b/src/app/main/ntmain.h index 81b7159855..223d9e318b 100644 --- a/src/or/ntmain.h +++ b/src/app/main/ntmain.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/tor_main.c b/src/app/main/tor_main.c index 703669ac99..8c497fff8a 100644 --- a/src/or/tor_main.c +++ b/src/app/main/tor_main.c @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/common/Makefile.nmake b/src/common/Makefile.nmake deleted file mode 100644 index a1c819fffa..0000000000 --- a/src/common/Makefile.nmake +++ /dev/null @@ -1,28 +0,0 @@ -all: libor.lib libor-crypto.lib libor-event.lib - -CFLAGS = /O2 /MT /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common \ - /I ..\ext - -LIBOR_OBJECTS = address.obj backtrace.obj compat.obj container.obj di_ops.obj \ - log.obj memarea.obj mempool.obj procmon.obj sandbox.obj util.obj \ - util_codedigest.obj - -LIBOR_CRYPTO_OBJECTS = aes.obj crypto.obj crypto_format.obj compress.obj compress_zlib.obj \ - tortls.obj crypto_curve25519.obj curve25519-donna.obj - -LIBOR_EVENT_OBJECTS = compat_libevent.obj - -curve25519-donna.obj: ..\ext\curve25519_donna\curve25519-donna.c - $(CC) $(CFLAGS) /D inline=_inline /c ..\ext\curve25519_donna\curve25519-donna.c - -libor.lib: $(LIBOR_OBJECTS) - lib $(LIBOR_OBJECTS) /out:libor.lib - -libor-crypto.lib: $(LIBOR_CRYPTO_OBJECTS) - lib $(LIBOR_CRYPTO_OBJECTS) /out:libor-crypto.lib - -libor-event.lib: $(LIBOR_EVENT_OBJECTS) - lib $(LIBOR_EVENT_OBJECTS) /out:libor-event.lib - -clean: - del *.obj *.lib libor*.lib diff --git a/src/common/address_set.c b/src/common/address_set.c deleted file mode 100644 index b2f4bb4c95..0000000000 --- a/src/common/address_set.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file address_set.c - * \brief Implementation for a set of addresses. - * - * This module was first written on a semi-emergency basis to improve the - * robustness of the anti-DoS module. As such, it's written in a pretty - * conservative way, and should be susceptible to improvement later on. - **/ - -#include "orconfig.h" -#include "address_set.h" -#include "address.h" -#include "compat.h" -#include "container.h" -#include "crypto_rand.h" -#include "util.h" -#include "siphash.h" - -/** How many 64-bit siphash values to extract per address */ -#define N_HASHES 2 -/** How many bloom-filter bits we set per address. This is twice the N_HASHES - * value, since we split the siphash output into two 32-bit values. */ -#define N_BITS_PER_ITEM (N_HASHES * 2) - -/* XXXX This code is largely duplicated with digestset_t. We should merge - * them together into a common bloom-filter implementation. I'm keeping - * them separate for now, though, since this module needs to be backported - * all the way to 0.2.9. - * - * The main difference between digestset_t and this code is that we use - * independent siphashes rather than messing around with bit-shifts. The - * approach here is probably more sound, and we should prefer it if&when we - * unify the implementations. - */ - -struct address_set_t { - /** siphash keys to make N_HASHES independent hashes for each address. */ - struct sipkey key[N_HASHES]; - int mask; /**< One less than the number of bits in <b>ba</b>; always one less - * than a power of two. */ - bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ -}; - -/** - * Allocate and return an address_set, suitable for holding up to - * <b>max_address_guess</b> distinct values. - */ -address_set_t * -address_set_new(int max_addresses_guess) -{ - /* See digestset_new() for rationale on this equation. */ - int n_bits = 1u << (tor_log2(max_addresses_guess)+5); - - address_set_t *set = tor_malloc_zero(sizeof(address_set_t)); - set->mask = n_bits - 1; - set->ba = bitarray_init_zero(n_bits); - crypto_rand((char*) set->key, sizeof(set->key)); - - return set; -} - -/** - * Release all storage associated with <b>set</b>. - */ -void -address_set_free(address_set_t *set) -{ - if (! set) - return; - - bitarray_free(set->ba); - tor_free(set); -} - -/** Yield the bit index corresponding to 'val' for set. */ -#define BIT(set, val) ((val) & (set)->mask) - -/** - * Add <b>addr</b> to <b>set</b>. - * - * All future queries for <b>addr</b> in set will return true. Removing - * items is not possible. - */ -void -address_set_add(address_set_t *set, const struct tor_addr_t *addr) -{ - int i; - for (i = 0; i < N_HASHES; ++i) { - uint64_t h = tor_addr_keyed_hash(&set->key[i], addr); - uint32_t high_bits = (uint32_t)(h >> 32); - uint32_t low_bits = (uint32_t)(h); - bitarray_set(set->ba, BIT(set, high_bits)); - bitarray_set(set->ba, BIT(set, low_bits)); - } -} - -/** As address_set_add(), but take an ipv4 address in host order. */ -void -address_set_add_ipv4h(address_set_t *set, uint32_t addr) -{ - tor_addr_t a; - tor_addr_from_ipv4h(&a, addr); - address_set_add(set, &a); -} - -/** - * Return true if <b>addr</b> is a member of <b>set</b>. (And probably, - * return false if <b>addr</b> is not a member of set.) - */ -int -address_set_probably_contains(address_set_t *set, - const struct tor_addr_t *addr) -{ - int i, matches = 0; - for (i = 0; i < N_HASHES; ++i) { - uint64_t h = tor_addr_keyed_hash(&set->key[i], addr); - uint32_t high_bits = (uint32_t)(h >> 32); - uint32_t low_bits = (uint32_t)(h); - // Note that !! is necessary here, since bitarray_is_set does not - // necessarily return 1 on true. - matches += !! bitarray_is_set(set->ba, BIT(set, high_bits)); - matches += !! bitarray_is_set(set->ba, BIT(set, low_bits)); - } - return matches == N_BITS_PER_ITEM; -} - diff --git a/src/common/compat.c b/src/common/compat.c deleted file mode 100644 index 6fdd6ecf00..0000000000 --- a/src/common/compat.c +++ /dev/null @@ -1,3531 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file compat.c - * \brief Wrappers to make calls more portable. This code defines - * functions such as tor_snprintf, get/set various data types, - * renaming, setting socket options, switching user IDs. It is basically - * where the non-portable items are conditionally included depending on - * the platform. - **/ - -#define COMPAT_PRIVATE -#include "compat.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <sys/locking.h> -#endif - -#ifdef HAVE_UNAME -#include <sys/utsname.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_SYSCTL_H -#include <sys/sysctl.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_UTIME_H -#include <utime.h> -#endif -#ifdef HAVE_SYS_UTIME_H -#include <sys/utime.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif -#ifdef HAVE_GRP_H -#include <grp.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_CRT_EXTERNS_H -#include <crt_externs.h> -#endif -#ifdef HAVE_SYS_STATVFS_H -#include <sys/statvfs.h> -#endif -#ifdef HAVE_SYS_CAPABILITY_H -#include <sys/capability.h> -#endif - -#ifdef _WIN32 -#include <conio.h> -#include <wchar.h> -/* Some mingw headers lack these. :p */ -#if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH -wint_t _getwch(void); -#endif -#ifndef WEOF -#define WEOF (wchar_t)(0xFFFF) -#endif -#if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY -static inline void -SecureZeroMemory(PVOID ptr, SIZE_T cnt) -{ - volatile char *vcptr = (volatile char*)ptr; - while (cnt--) - *vcptr++ = 0; -} -#endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */ -#elif defined(HAVE_READPASSPHRASE_H) -#include <readpassphrase.h> -#else -#include "tor_readpassphrase.h" -#endif /* defined(_WIN32) || ... */ - -/* Includes for the process attaching prevention */ -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) -/* Only use the linux prctl; the IRIX prctl is totally different */ -#include <sys/prctl.h> -#elif defined(__APPLE__) -#include <sys/ptrace.h> -#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) || ... */ - -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> /* FreeBSD needs this to know what version it is */ -#endif -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_MMAP -#include <sys/mman.h> -#endif -#ifdef HAVE_SYS_SYSLIMITS_H -#include <sys/syslimits.h> -#endif -#ifdef HAVE_SYS_FILE_H -#include <sys/file.h> -#endif - -#include "torlog.h" -#include "util.h" -#include "container.h" -#include "address.h" -#include "sandbox.h" - -/* Inline the strl functions if the platform doesn't have them. */ -#ifndef HAVE_STRLCPY -#include "strlcpy.c" -#endif -#ifndef HAVE_STRLCAT -#include "strlcat.c" -#endif - -/* When set_max_file_descriptors() is called, update this with the max file - * descriptor value so we can use it to check the limit when opening a new - * socket. Default value is what Debian sets as the default hard limit. */ -static int max_sockets = 1024; - -/** As open(path, flags, mode), but return an fd with the close-on-exec mode - * set. */ -int -tor_open_cloexec(const char *path, int flags, unsigned mode) -{ - int fd; - const char *p = sandbox_intern_string(path); -#ifdef O_CLOEXEC - fd = open(p, flags|O_CLOEXEC, mode); - if (fd >= 0) - return fd; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with O_CLOEXEC support, we - * are running on one without. */ - if (errno != EINVAL) - return -1; -#endif /* defined(O_CLOEXEC) */ - - log_debug(LD_FS, "Opening %s with flags %x", p, flags); - fd = open(p, flags, mode); -#ifdef FD_CLOEXEC - if (fd >= 0) { - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - close(fd); - return -1; - } - } -#endif /* defined(FD_CLOEXEC) */ - return fd; -} - -/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the - * underlying file handle. */ -FILE * -tor_fopen_cloexec(const char *path, const char *mode) -{ - FILE *result = fopen(path, mode); -#ifdef FD_CLOEXEC - if (result != NULL) { - if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - fclose(result); - return NULL; - } - } -#endif /* defined(FD_CLOEXEC) */ - return result; -} - -/** As rename(), but work correctly with the sandbox. */ -int -tor_rename(const char *path_old, const char *path_new) -{ - log_debug(LD_FS, "Renaming %s to %s", path_old, path_new); - return rename(sandbox_intern_string(path_old), - sandbox_intern_string(path_new)); -} - -#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) -/** Try to create a memory mapping for <b>filename</b> and return it. On - * failure, return NULL. Sets errno properly, using ERANGE to mean - * "empty file". Must only be called on trusted Tor-owned files, as changing - * the underlying file's size causes unspecified behavior. */ -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - int fd; /* router file */ - char *string; - int result; - tor_mmap_t *res; - size_t size, filesize; - struct stat st; - - tor_assert(filename); - - fd = tor_open_cloexec(filename, O_RDONLY, 0); - if (fd<0) { - int save_errno = errno; - int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN; - log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - /* Get the size of the file */ - result = fstat(fd, &st); - if (result != 0) { - int save_errno = errno; - log_warn(LD_FS, - "Couldn't fstat opened descriptor for \"%s\" during mmap: %s", - filename, strerror(errno)); - close(fd); - errno = save_errno; - return NULL; - } - size = filesize = (size_t)(st.st_size); - - if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) { - log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename); - errno = EFBIG; - close(fd); - return NULL; - } - if (!size) { - /* Zero-length file. If we call mmap on it, it will succeed but - * return NULL, and bad things will happen. So just fail. */ - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - errno = ERANGE; - close(fd); - return NULL; - } - - string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); - close(fd); - if (string == MAP_FAILED) { - int save_errno = errno; - log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - res = tor_malloc_zero(sizeof(tor_mmap_t)); - res->data = string; - res->size = filesize; - res->mapping_size = size; - - return res; -} -/** Release storage held for a memory mapping; returns 0 on success, - * or -1 on failure (and logs a warning). */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - int res; - - if (handle == NULL) - return 0; - - res = munmap((char*)handle->data, handle->mapping_size); - if (res == 0) { - /* munmap() succeeded */ - tor_free(handle); - } else { - log_warn(LD_FS, "Failed to munmap() in tor_munmap_file(): %s", - strerror(errno)); - res = -1; - } - - return res; -} -#elif defined(_WIN32) -tor_mmap_t * -tor_mmap_file(const char *filename) -{ - TCHAR tfilename[MAX_PATH]= {0}; - tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t)); - int empty = 0; - HANDLE file_handle = INVALID_HANDLE_VALUE; - DWORD size_low, size_high; - uint64_t real_size; - res->mmap_handle = NULL; -#ifdef UNICODE - mbstowcs(tfilename,filename,MAX_PATH); -#else - strlcpy(tfilename,filename,MAX_PATH); -#endif - file_handle = CreateFile(tfilename, - GENERIC_READ, FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, - 0); - - if (file_handle == INVALID_HANDLE_VALUE) - goto win_err; - - size_low = GetFileSize(file_handle, &size_high); - - if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { - log_warn(LD_FS,"Error getting size of \"%s\".",filename); - goto win_err; - } - if (size_low == 0 && size_high == 0) { - log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); - empty = 1; - goto err; - } - real_size = (((uint64_t)size_high)<<32) | size_low; - if (real_size > SIZE_MAX) { - log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename); - goto err; - } - res->size = real_size; - - res->mmap_handle = CreateFileMapping(file_handle, - NULL, - PAGE_READONLY, - size_high, - size_low, - NULL); - if (res->mmap_handle == NULL) - goto win_err; - res->data = (char*) MapViewOfFile(res->mmap_handle, - FILE_MAP_READ, - 0, 0, 0); - if (!res->data) - goto win_err; - - CloseHandle(file_handle); - return res; - win_err: { - DWORD e = GetLastError(); - int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ? - LOG_INFO : LOG_WARN; - char *msg = format_win32_error(e); - log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg); - tor_free(msg); - if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) - errno = ENOENT; - else - errno = EINVAL; - } - err: - if (empty) - errno = ERANGE; - if (file_handle != INVALID_HANDLE_VALUE) - CloseHandle(file_handle); - tor_munmap_file(res); - return NULL; -} - -/* Unmap the file, and return 0 for success or -1 for failure */ -int -tor_munmap_file(tor_mmap_t *handle) -{ - if (handle == NULL) - return 0; - - if (handle->data) { - /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would - have to be redefined as non-const. */ - BOOL ok = UnmapViewOfFile( (LPVOID) handle->data); - if (!ok) { - log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d", - (int)GetLastError()); - } - } - - if (handle->mmap_handle != NULL) - CloseHandle(handle->mmap_handle); - tor_free(handle); - - return 0; -} -#else -#error "cannot implement tor_mmap_file" -#endif /* defined(HAVE_MMAP) || ... || ... */ - -/** Replacement for snprintf. Differs from platform snprintf in two - * ways: First, always NUL-terminates its output. Second, always - * returns -1 if the result is truncated. (Note that this return - * behavior does <i>not</i> conform to C99; it just happens to be - * easier to emulate "return -1" with conformant implementations than - * it is to emulate "return number that would be written" with - * non-conformant implementations.) */ -int -tor_snprintf(char *str, size_t size, const char *format, ...) -{ - va_list ap; - int r; - va_start(ap,format); - r = tor_vsnprintf(str,size,format,ap); - va_end(ap); - return r; -} - -/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from - * snprintf. - */ -int -tor_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - int r; - if (size == 0) - return -1; /* no place for the NUL */ - if (size > SIZE_T_CEILING) - return -1; -#ifdef _WIN32 - r = _vsnprintf(str, size, format, args); -#else - r = vsnprintf(str, size, format, args); -#endif - str[size-1] = '\0'; - if (r < 0 || r >= (ssize_t)size) - return -1; - return r; -} - -/** - * Portable asprintf implementation. Does a printf() into a newly malloc'd - * string. Sets *<b>strp</b> to this string, and returns its length (not - * including the terminating NUL character). - * - * You can treat this function as if its implementation were something like - <pre> - char buf[_INFINITY_]; - tor_snprintf(buf, sizeof(buf), fmt, args); - *strp = tor_strdup(buf); - return strlen(*strp): - </pre> - * Where _INFINITY_ is an imaginary constant so big that any string can fit - * into it. - */ -int -tor_asprintf(char **strp, const char *fmt, ...) -{ - int r; - va_list args; - va_start(args, fmt); - r = tor_vasprintf(strp, fmt, args); - va_end(args); - if (!*strp || r < 0) { - /* LCOV_EXCL_START */ - log_err(LD_BUG, "Internal error in asprintf"); - tor_assert(0); - /* LCOV_EXCL_STOP */ - } - return r; -} - -/** - * Portable vasprintf implementation. Does a printf() into a newly malloc'd - * string. Differs from regular vasprintf in the same ways that - * tor_asprintf() differs from regular asprintf. - */ -int -tor_vasprintf(char **strp, const char *fmt, va_list args) -{ - /* use a temporary variable in case *strp is in args. */ - char *strp_tmp=NULL; -#ifdef HAVE_VASPRINTF - /* If the platform gives us one, use it. */ - int r = vasprintf(&strp_tmp, fmt, args); - if (r < 0) - *strp = NULL; - else - *strp = strp_tmp; - return r; -#elif defined(HAVE__VSCPRINTF) - /* On Windows, _vsnprintf won't tell us the length of the string if it - * overflows, so we need to use _vcsprintf to tell how much to allocate */ - int len, r; - va_list tmp_args; - va_copy(tmp_args, args); - len = _vscprintf(fmt, tmp_args); - va_end(tmp_args); - if (len < 0) { - *strp = NULL; - return -1; - } - strp_tmp = tor_malloc(len + 1); - r = _vsnprintf(strp_tmp, len+1, fmt, args); - if (r != len) { - tor_free(strp_tmp); - *strp = NULL; - return -1; - } - *strp = strp_tmp; - return len; -#else - /* Everywhere else, we have a decent vsnprintf that tells us how many - * characters we need. We give it a try on a short buffer first, since - * it might be nice to avoid the second vsnprintf call. - */ - char buf[128]; - int len, r; - va_list tmp_args; - va_copy(tmp_args, args); - /* vsnprintf() was properly checked but tor_vsnprintf() available so - * why not use it? */ - len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args); - va_end(tmp_args); - if (len < (int)sizeof(buf)) { - *strp = tor_strdup(buf); - return len; - } - strp_tmp = tor_malloc(len+1); - /* use of tor_vsnprintf() will ensure string is null terminated */ - r = tor_vsnprintf(strp_tmp, len+1, fmt, args); - if (r != len) { - tor_free(strp_tmp); - *strp = NULL; - return -1; - } - *strp = strp_tmp; - return len; -#endif /* defined(HAVE_VASPRINTF) || ... */ -} - -/** Given <b>hlen</b> bytes at <b>haystack</b> and <b>nlen</b> bytes at - * <b>needle</b>, return a pointer to the first occurrence of the needle - * within the haystack, or NULL if there is no such occurrence. - * - * This function is <em>not</em> timing-safe. - * - * Requires that <b>nlen</b> be greater than zero. - */ -const void * -tor_memmem(const void *_haystack, size_t hlen, - const void *_needle, size_t nlen) -{ -#if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) - tor_assert(nlen); - return memmem(_haystack, hlen, _needle, nlen); -#else - /* This isn't as fast as the GLIBC implementation, but it doesn't need to - * be. */ - const char *p, *last_possible_start; - const char *haystack = (const char*)_haystack; - const char *needle = (const char*)_needle; - char first; - tor_assert(nlen); - - if (nlen > hlen) - return NULL; - - p = haystack; - /* Last position at which the needle could start. */ - last_possible_start = haystack + hlen - nlen; - first = *(const char*)needle; - while ((p = memchr(p, first, last_possible_start + 1 - p))) { - if (fast_memeq(p, needle, nlen)) - return p; - if (++p > last_possible_start) { - /* This comparison shouldn't be necessary, since if p was previously - * equal to last_possible_start, the next memchr call would be - * "memchr(p, first, 0)", which will return NULL. But it clarifies the - * logic. */ - return NULL; - } - } - return NULL; -#endif /* defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) */ -} - -/** - * Tables to implement ctypes-replacement TOR_IS*() functions. Each table - * has 256 bits to look up whether a character is in some set or not. This - * fails on non-ASCII platforms, but it is hard to find a platform whose - * character set is not a superset of ASCII nowadays. */ - -/**@{*/ -const uint32_t TOR_ISALPHA_TABLE[8] = - { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; -const uint32_t TOR_ISALNUM_TABLE[8] = - { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; -const uint32_t TOR_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISXDIGIT_TABLE[8] = - { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 }; -const uint32_t TOR_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISPRINT_TABLE[8] = - { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 }; -const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 }; -const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 }; - -/** Upper-casing and lowercasing tables to map characters to upper/lowercase - * equivalents. Used by tor_toupper() and tor_tolower(). */ -/**@{*/ -const uint8_t TOR_TOUPPER_TABLE[256] = { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, - 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, - 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, - 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, - 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, - 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127, - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, -}; -const uint8_t TOR_TOLOWER_TABLE[256] = { - 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, - 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, - 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, - 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, - 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95, - 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, - 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, - 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, - 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, - 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, - 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, - 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, - 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, - 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, - 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, -}; -/**@}*/ - -/** Helper for tor_strtok_r_impl: Advances cp past all characters in - * <b>sep</b>, and returns its new value. */ -static char * -strtok_helper(char *cp, const char *sep) -{ - if (sep[1]) { - while (*cp && strchr(sep, *cp)) - ++cp; - } else { - while (*cp && *cp == *sep) - ++cp; - } - return cp; -} - -/** Implementation of strtok_r for platforms whose coders haven't figured out - * how to write one. Hey, retrograde libc developers! You can use this code - * here for free! */ -char * -tor_strtok_r_impl(char *str, const char *sep, char **lasts) -{ - char *cp, *start; - tor_assert(*sep); - if (str) { - str = strtok_helper(str, sep); - if (!*str) - return NULL; - start = cp = *lasts = str; - } else if (!*lasts || !**lasts) { - return NULL; - } else { - start = cp = *lasts; - } - - if (sep[1]) { - while (*cp && !strchr(sep, *cp)) - ++cp; - } else { - cp = strchr(cp, *sep); - } - - if (!cp || !*cp) { - *lasts = NULL; - } else { - *cp++ = '\0'; - *lasts = strtok_helper(cp, sep); - } - return start; -} - -#ifdef _WIN32 -/** Take a filename and return a pointer to its final element. This - * function is called on __FILE__ to fix a MSVC nit where __FILE__ - * contains the full path to the file. This is bad, because it - * confuses users to find the home directory of the person who - * compiled the binary in their warning messages. - */ -const char * -tor_fix_source_file(const char *fname) -{ - const char *cp1, *cp2, *r; - cp1 = strrchr(fname, '/'); - cp2 = strrchr(fname, '\\'); - if (cp1 && cp2) { - r = (cp1<cp2)?(cp2+1):(cp1+1); - } else if (cp1) { - r = cp1+1; - } else if (cp2) { - r = cp2+1; - } else { - r = fname; - } - return r; -} -#endif /* defined(_WIN32) */ - -/** - * Read a 16-bit value beginning at <b>cp</b>. Equivalent to - * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint16_t -get_uint16(const void *cp) -{ - uint16_t v; - memcpy(&v,cp,2); - return v; -} -/** - * Read a 32-bit value beginning at <b>cp</b>. Equivalent to - * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint32_t -get_uint32(const void *cp) -{ - uint32_t v; - memcpy(&v,cp,4); - return v; -} -/** - * Read a 64-bit value beginning at <b>cp</b>. Equivalent to - * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid - * unaligned memory access. - */ -uint64_t -get_uint64(const void *cp) -{ - uint64_t v; - memcpy(&v,cp,8); - return v; -} - -/** - * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint16_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint16(void *cp, uint16_t v) -{ - memcpy(cp,&v,2); -} -/** - * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint32_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint32(void *cp, uint32_t v) -{ - memcpy(cp,&v,4); -} -/** - * Set a 64-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to - * *(uint64_t*)(cp) = v, but will not cause segfaults on platforms that forbid - * unaligned memory access. */ -void -set_uint64(void *cp, uint64_t v) -{ - memcpy(cp,&v,8); -} - -/** - * Rename the file <b>from</b> to the file <b>to</b>. On Unix, this is - * the same as rename(2). On windows, this removes <b>to</b> first if - * it already exists. - * Returns 0 on success. Returns -1 and sets errno on failure. - */ -int -replace_file(const char *from, const char *to) -{ -#ifndef _WIN32 - return tor_rename(from, to); -#else - switch (file_status(to)) - { - case FN_NOENT: - break; - case FN_FILE: - case FN_EMPTY: - if (unlink(to)) return -1; - break; - case FN_ERROR: - return -1; - case FN_DIR: - errno = EISDIR; - return -1; - } - return tor_rename(from,to); -#endif /* !defined(_WIN32) */ -} - -/** Change <b>fname</b>'s modification time to now. */ -int -touch_file(const char *fname) -{ - if (utime(fname, NULL)!=0) - return -1; - return 0; -} - -/** Represents a lockfile on which we hold the lock. */ -struct tor_lockfile_t { - /** Name of the file */ - char *filename; - /** File descriptor used to hold the file open */ - int fd; -}; - -/** Try to get a lock on the lockfile <b>filename</b>, creating it as - * necessary. If someone else has the lock and <b>blocking</b> is true, - * wait until the lock is available. Otherwise return immediately whether - * we succeeded or not. - * - * Set *<b>locked_out</b> to true if somebody else had the lock, and to false - * otherwise. - * - * Return a <b>tor_lockfile_t</b> on success, NULL on failure. - * - * (Implementation note: because we need to fall back to fcntl on some - * platforms, these locks are per-process, not per-thread. If you want - * to do in-process locking, use tor_mutex_t like a normal person. - * On Windows, when <b>blocking</b> is true, the maximum time that - * is actually waited is 10 seconds, after which NULL is returned - * and <b>locked_out</b> is set to 1.) - */ -tor_lockfile_t * -tor_lockfile_lock(const char *filename, int blocking, int *locked_out) -{ - tor_lockfile_t *result; - int fd; - *locked_out = 0; - - log_info(LD_FS, "Locking \"%s\"", filename); - fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); - if (fd < 0) { - log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename, - strerror(errno)); - return NULL; - } - -#ifdef _WIN32 - _lseek(fd, 0, SEEK_SET); - if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) { - if (errno != EACCES && errno != EDEADLOCK) - log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } -#elif defined(HAVE_FLOCK) - if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) { - if (errno != EWOULDBLOCK) - log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } -#else - { - struct flock lock; - memset(&lock, 0, sizeof(lock)); - lock.l_type = F_WRLCK; - lock.l_whence = SEEK_SET; - if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) { - if (errno != EACCES && errno != EAGAIN) - log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno)); - else - *locked_out = 1; - close(fd); - return NULL; - } - } -#endif /* defined(_WIN32) || ... */ - - result = tor_malloc(sizeof(tor_lockfile_t)); - result->filename = tor_strdup(filename); - result->fd = fd; - return result; -} - -/** Release the lock held as <b>lockfile</b>. */ -void -tor_lockfile_unlock(tor_lockfile_t *lockfile) -{ - tor_assert(lockfile); - - log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename); -#ifdef _WIN32 - _lseek(lockfile->fd, 0, SEEK_SET); - if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) { - log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename, - strerror(errno)); - } -#elif defined(HAVE_FLOCK) - if (flock(lockfile->fd, LOCK_UN) < 0) { - log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename, - strerror(errno)); - } -#else - /* Closing the lockfile is sufficient. */ -#endif /* defined(_WIN32) || ... */ - - close(lockfile->fd); - lockfile->fd = -1; - tor_free(lockfile->filename); - tor_free(lockfile); -} - -/** @{ */ -/** Some old versions of Unix didn't define constants for these values, - * and instead expect you to say 0, 1, or 2. */ -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif -#ifndef SEEK_END -#define SEEK_END 2 -#endif -/** @} */ - -/** Return the position of <b>fd</b> with respect to the start of the file. */ -off_t -tor_fd_getpos(int fd) -{ -#ifdef _WIN32 - return (off_t) _lseek(fd, 0, SEEK_CUR); -#else - return (off_t) lseek(fd, 0, SEEK_CUR); -#endif -} - -/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. - * If the file is a pipe, do nothing and succeed. - **/ -int -tor_fd_seekend(int fd) -{ -#ifdef _WIN32 - return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; -#else - off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; -#ifdef ESPIPE - /* If we get an error and ESPIPE, then it's a pipe or a socket of a fifo: - * no need to worry. */ - if (rc < 0 && errno == ESPIPE) - rc = 0; -#endif /* defined(ESPIPE) */ - return (rc < 0) ? -1 : 0; -#endif /* defined(_WIN32) */ -} - -/** Move <b>fd</b> to position <b>pos</b> in the file. Return -1 on error, 0 - * on success. */ -int -tor_fd_setpos(int fd, off_t pos) -{ -#ifdef _WIN32 - return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; -#else - return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; -#endif -} - -/** Replacement for ftruncate(fd, 0): move to the front of the file and remove - * all the rest of the file. Return -1 on error, 0 on success. */ -int -tor_ftruncate(int fd) -{ - /* Rumor has it that some versions of ftruncate do not move the file pointer. - */ - if (tor_fd_setpos(fd, 0) < 0) - return -1; - -#ifdef _WIN32 - return _chsize(fd, 0); -#else - return ftruncate(fd, 0); -#endif -} - -#undef DEBUG_SOCKET_COUNTING -#ifdef DEBUG_SOCKET_COUNTING -/** A bitarray of all fds that should be passed to tor_socket_close(). Only - * used if DEBUG_SOCKET_COUNTING is defined. */ -static bitarray_t *open_sockets = NULL; -/** The size of <b>open_sockets</b>, in bits. */ -static int max_socket = -1; -#endif /* defined(DEBUG_SOCKET_COUNTING) */ - -/** Count of number of sockets currently open. (Undercounts sockets opened by - * eventdns and libevent.) */ -static int n_sockets_open = 0; - -/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */ -static tor_mutex_t *socket_accounting_mutex = NULL; - -/** Helper: acquire the socket accounting lock. */ -static inline void -socket_accounting_lock(void) -{ - if (PREDICT_UNLIKELY(!socket_accounting_mutex)) - socket_accounting_mutex = tor_mutex_new(); - tor_mutex_acquire(socket_accounting_mutex); -} - -/** Helper: release the socket accounting lock. */ -static inline void -socket_accounting_unlock(void) -{ - tor_mutex_release(socket_accounting_mutex); -} - -/** As close(), but guaranteed to work for sockets across platforms (including - * Windows, where close()ing a socket doesn't work. Returns 0 on success and - * the socket error code on failure. */ -int -tor_close_socket_simple(tor_socket_t s) -{ - int r = 0; - - /* On Windows, you have to call close() on fds returned by open(), - * and closesocket() on fds returned by socket(). On Unix, everything - * gets close()'d. We abstract this difference by always using - * tor_close_socket to close sockets, and always using close() on - * files. - */ - #if defined(_WIN32) - r = closesocket(s); - #else - r = close(s); - #endif - - if (r != 0) { - int err = tor_socket_errno(-1); - log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err)); - return err; - } - - return r; -} - -/** As tor_close_socket_simple(), but keeps track of the number - * of open sockets. Returns 0 on success, -1 on failure. */ -MOCK_IMPL(int, -tor_close_socket,(tor_socket_t s)) -{ - int r = tor_close_socket_simple(s); - - socket_accounting_lock(); -#ifdef DEBUG_SOCKET_COUNTING - if (s > max_socket || ! bitarray_is_set(open_sockets, s)) { - log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_" - "socket(), or that was already closed or something.", s); - } else { - tor_assert(open_sockets && s <= max_socket); - bitarray_clear(open_sockets, s); - } -#endif /* defined(DEBUG_SOCKET_COUNTING) */ - if (r == 0) { - --n_sockets_open; - } else { -#ifdef _WIN32 - if (r != WSAENOTSOCK) - --n_sockets_open; -#else - if (r != EBADF) - --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force. -#endif /* defined(_WIN32) */ - r = -1; - } - - tor_assert_nonfatal(n_sockets_open >= 0); - socket_accounting_unlock(); - return r; -} - -/** @{ */ -#ifdef DEBUG_SOCKET_COUNTING -/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is - * now an open socket. */ -static inline void -mark_socket_open(tor_socket_t s) -{ - /* XXXX This bitarray business will NOT work on windows: sockets aren't - small ints there. */ - if (s > max_socket) { - if (max_socket == -1) { - open_sockets = bitarray_init_zero(s+128); - max_socket = s+128; - } else { - open_sockets = bitarray_expand(open_sockets, max_socket, s+128); - max_socket = s+128; - } - } - if (bitarray_is_set(open_sockets, s)) { - log_warn(LD_BUG, "I thought that %d was already open, but socket() just " - "gave it to me!", s); - } - bitarray_set(open_sockets, s); -} -#else /* !(defined(DEBUG_SOCKET_COUNTING)) */ -#define mark_socket_open(s) ((void) (s)) -#endif /* defined(DEBUG_SOCKET_COUNTING) */ -/** @} */ - -/** As socket(), but counts the number of open sockets. */ -MOCK_IMPL(tor_socket_t, -tor_open_socket,(int domain, int type, int protocol)) -{ - return tor_open_socket_with_extensions(domain, type, protocol, 1, 0); -} - -/** Mockable wrapper for connect(). */ -MOCK_IMPL(tor_socket_t, -tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address, - socklen_t address_len)) -{ - return connect(sock,address,address_len); -} - -/** As socket(), but creates a nonblocking socket and - * counts the number of open sockets. */ -tor_socket_t -tor_open_socket_nonblocking(int domain, int type, int protocol) -{ - return tor_open_socket_with_extensions(domain, type, protocol, 1, 1); -} - -/** As socket(), but counts the number of open sockets and handles - * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. - * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate - * if the corresponding extension should be used.*/ -tor_socket_t -tor_open_socket_with_extensions(int domain, int type, int protocol, - int cloexec, int nonblock) -{ - tor_socket_t s; - - /* We are about to create a new file descriptor so make sure we have - * enough of them. */ - if (get_n_open_sockets() >= max_sockets - 1) { -#ifdef _WIN32 - WSASetLastError(WSAEMFILE); -#else - errno = EMFILE; -#endif - return TOR_INVALID_SOCKET; - } - -#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) - int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | - (nonblock ? SOCK_NONBLOCK : 0); - s = socket(domain, type|ext_flags, protocol); - if (SOCKET_OK(s)) - goto socket_ok; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK - * support, we are running on one without. */ - if (errno != EINVAL) - return s; -#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */ - - s = socket(domain, type, protocol); - if (! SOCKET_OK(s)) - return s; - -#if defined(FD_CLOEXEC) - if (cloexec) { - if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } -#else /* !(defined(FD_CLOEXEC)) */ - (void)cloexec; -#endif /* defined(FD_CLOEXEC) */ - - if (nonblock) { - if (set_socket_nonblocking(s) == -1) { - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } - - goto socket_ok; /* So that socket_ok will not be unused. */ - - socket_ok: - tor_take_socket_ownership(s); - return s; -} - -/** - * For socket accounting: remember that we are the owner of the socket - * <b>s</b>. This will prevent us from overallocating sockets, and prevent us - * from asserting later when we close the socket <b>s</b>. - */ -void -tor_take_socket_ownership(tor_socket_t s) -{ - socket_accounting_lock(); - ++n_sockets_open; - mark_socket_open(s); - socket_accounting_unlock(); -} - -/** As accept(), but counts the number of open sockets. */ -tor_socket_t -tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len) -{ - return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0); -} - -/** As accept(), but returns a nonblocking socket and - * counts the number of open sockets. */ -tor_socket_t -tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len) -{ - return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1); -} - -/** As accept(), but counts the number of open sockets and handles - * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. - * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate - * if the corresponding extension should be used.*/ -tor_socket_t -tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len, int cloexec, int nonblock) -{ - tor_socket_t s; - - /* We are about to create a new file descriptor so make sure we have - * enough of them. */ - if (get_n_open_sockets() >= max_sockets - 1) { -#ifdef _WIN32 - WSASetLastError(WSAEMFILE); -#else - errno = EMFILE; -#endif - return TOR_INVALID_SOCKET; - } - -#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \ - && defined(SOCK_NONBLOCK) - int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | - (nonblock ? SOCK_NONBLOCK : 0); - s = accept4(sockfd, addr, len, ext_flags); - if (SOCKET_OK(s)) - goto socket_ok; - /* If we got an error, see if it is ENOSYS. ENOSYS indicates that, - * even though we were built on a system with accept4 support, we - * are running on one without. Also, check for EINVAL, which indicates that - * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */ - if (errno != EINVAL && errno != ENOSYS) - return s; -#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */ - - s = accept(sockfd, addr, len); - if (!SOCKET_OK(s)) - return s; - -#if defined(FD_CLOEXEC) - if (cloexec) { - if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { - log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno)); - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } -#else /* !(defined(FD_CLOEXEC)) */ - (void)cloexec; -#endif /* defined(FD_CLOEXEC) */ - - if (nonblock) { - if (set_socket_nonblocking(s) == -1) { - tor_close_socket_simple(s); - return TOR_INVALID_SOCKET; - } - } - - goto socket_ok; /* So that socket_ok will not be unused. */ - - socket_ok: - tor_take_socket_ownership(s); - return s; -} - -/** Return the number of sockets we currently have opened. */ -int -get_n_open_sockets(void) -{ - int n; - socket_accounting_lock(); - n = n_sockets_open; - socket_accounting_unlock(); - return n; -} - -/** Mockable wrapper for getsockname(). */ -MOCK_IMPL(int, -tor_getsockname,(tor_socket_t sock, struct sockaddr *address, - socklen_t *address_len)) -{ - return getsockname(sock, address, address_len); -} - -/** - * Find the local address associated with the socket <b>sock</b>, and - * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure. - * - * (As tor_getsockname, but instead places the result in a tor_addr_t.) */ -int -tor_addr_from_getsockname(tor_addr_t *addr_out, tor_socket_t sock) -{ - struct sockaddr_storage ss; - socklen_t ss_len = sizeof(ss); - memset(&ss, 0, sizeof(ss)); - - if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0) - return -1; - - return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL); -} - -/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1 - * on failure. - */ -int -set_socket_nonblocking(tor_socket_t sock) -{ -#if defined(_WIN32) - unsigned long nonblocking = 1; - ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking); -#else - int flags; - - flags = fcntl(sock, F_GETFL, 0); - if (flags == -1) { - log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno)); - return -1; - } - flags |= O_NONBLOCK; - if (fcntl(sock, F_SETFL, flags) == -1) { - log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno)); - return -1; - } -#endif /* defined(_WIN32) */ - - return 0; -} - -/** - * Allocate a pair of connected sockets. (Like socketpair(family, - * type,protocol,fd), but works on systems that don't have - * socketpair.) - * - * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported. - * - * Note that on systems without socketpair, this call will fail if - * localhost is inaccessible (for example, if the networking - * stack is down). And even if it succeeds, the socket pair will not - * be able to read while localhost is down later (the socket pair may - * even close, depending on OS-specific timeouts). - * - * Returns 0 on success and -errno on failure; do not rely on the value - * of errno or WSAGetLastError(). - **/ -/* It would be nicer just to set errno, but that won't work for windows. */ -int -tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) -{ -//don't use win32 socketpairs (they are always bad) -#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32) - int r; - -#ifdef SOCK_CLOEXEC - r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd); - if (r == 0) - goto sockets_ok; - /* If we got an error, see if it is EINVAL. EINVAL might indicate that, - * even though we were built on a system with SOCK_CLOEXEC support, we - * are running on one without. */ - if (errno != EINVAL) - return -errno; -#endif /* defined(SOCK_CLOEXEC) */ - - r = socketpair(family, type, protocol, fd); - if (r < 0) - return -errno; - -#if defined(FD_CLOEXEC) - if (SOCKET_OK(fd[0])) { - r = fcntl(fd[0], F_SETFD, FD_CLOEXEC); - if (r == -1) { - close(fd[0]); - close(fd[1]); - return -errno; - } - } - if (SOCKET_OK(fd[1])) { - r = fcntl(fd[1], F_SETFD, FD_CLOEXEC); - if (r == -1) { - close(fd[0]); - close(fd[1]); - return -errno; - } - } -#endif /* defined(FD_CLOEXEC) */ - goto sockets_ok; /* So that sockets_ok will not be unused. */ - - sockets_ok: - socket_accounting_lock(); - if (SOCKET_OK(fd[0])) { - ++n_sockets_open; - mark_socket_open(fd[0]); - } - if (SOCKET_OK(fd[1])) { - ++n_sockets_open; - mark_socket_open(fd[1]); - } - socket_accounting_unlock(); - - return 0; -#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */ - return tor_ersatz_socketpair(family, type, protocol, fd); -#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */ -} - -#ifdef NEED_ERSATZ_SOCKETPAIR - -static inline socklen_t -SIZEOF_SOCKADDR(int domain) -{ - switch (domain) { - case AF_INET: - return sizeof(struct sockaddr_in); - case AF_INET6: - return sizeof(struct sockaddr_in6); - default: - return 0; - } -} - -/** - * Helper used to implement socketpair on systems that lack it, by - * making a direct connection to localhost. - */ -STATIC int -tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) -{ - /* This socketpair does not work when localhost is down. So - * it's really not the same thing at all. But it's close enough - * for now, and really, when localhost is down sometimes, we - * have other problems too. - */ - tor_socket_t listener = TOR_INVALID_SOCKET; - tor_socket_t connector = TOR_INVALID_SOCKET; - tor_socket_t acceptor = TOR_INVALID_SOCKET; - tor_addr_t listen_tor_addr; - struct sockaddr_storage connect_addr_ss, listen_addr_ss; - struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss; - uint16_t listen_port = 0; - tor_addr_t connect_tor_addr; - uint16_t connect_port = 0; - struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss; - socklen_t size; - int saved_errno = -1; - int ersatz_domain = AF_INET; - - memset(&connect_tor_addr, 0, sizeof(connect_tor_addr)); - memset(&connect_addr_ss, 0, sizeof(connect_addr_ss)); - memset(&listen_tor_addr, 0, sizeof(listen_tor_addr)); - memset(&listen_addr_ss, 0, sizeof(listen_addr_ss)); - - if (protocol -#ifdef AF_UNIX - || family != AF_UNIX -#endif - ) { -#ifdef _WIN32 - return -WSAEAFNOSUPPORT; -#else - return -EAFNOSUPPORT; -#endif - } - if (!fd) { - return -EINVAL; - } - - listener = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(listener)) { - int first_errno = tor_socket_errno(-1); - if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT) - && ersatz_domain == AF_INET) { - /* Assume we're on an IPv6-only system */ - ersatz_domain = AF_INET6; - listener = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(listener)) { - /* Keep the previous behaviour, which was to return the IPv4 error. - * (This may be less informative on IPv6-only systems.) - * XX/teor - is there a better way to decide which errno to return? - * (I doubt we care much either way, once there is an error.) - */ - return -first_errno; - } - } - } - /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we - * risk exposing a socketpair on a routable IP address. (Some BSD jails - * use a routable address for localhost. Fortunately, they have the real - * AF_UNIX socketpair.) */ - if (ersatz_domain == AF_INET) { - tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK); - } else { - tor_addr_parse(&listen_tor_addr, "[::1]"); - } - tor_assert(tor_addr_is_loopback(&listen_tor_addr)); - size = tor_addr_to_sockaddr(&listen_tor_addr, - 0 /* kernel chooses port. */, - listen_addr, - sizeof(listen_addr_ss)); - if (bind(listener, listen_addr, size) == -1) - goto tidy_up_and_fail; - if (listen(listener, 1) == -1) - goto tidy_up_and_fail; - - connector = tor_open_socket(ersatz_domain, type, 0); - if (!SOCKET_OK(connector)) - goto tidy_up_and_fail; - /* We want to find out the port number to connect to. */ - size = sizeof(connect_addr_ss); - if (getsockname(listener, connect_addr, &size) == -1) - goto tidy_up_and_fail; - if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)) - goto abort_tidy_up_and_fail; - if (connect(connector, connect_addr, size) == -1) - goto tidy_up_and_fail; - - size = sizeof(listen_addr_ss); - acceptor = tor_accept_socket(listener, listen_addr, &size); - if (!SOCKET_OK(acceptor)) - goto tidy_up_and_fail; - if (size != SIZEOF_SOCKADDR(listen_addr->sa_family)) - goto abort_tidy_up_and_fail; - /* Now check we are talking to ourself by matching port and host on the - two sockets. */ - if (getsockname(connector, connect_addr, &size) == -1) - goto tidy_up_and_fail; - /* Set *_tor_addr and *_port to the address and port that was used */ - tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port); - tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port); - if (size != SIZEOF_SOCKADDR (connect_addr->sa_family) - || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC) - || listen_port != connect_port) { - goto abort_tidy_up_and_fail; - } - tor_close_socket(listener); - fd[0] = connector; - fd[1] = acceptor; - - return 0; - - abort_tidy_up_and_fail: -#ifdef _WIN32 - saved_errno = WSAECONNABORTED; -#else - saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */ -#endif - tidy_up_and_fail: - if (saved_errno < 0) - saved_errno = errno; - if (SOCKET_OK(listener)) - tor_close_socket(listener); - if (SOCKET_OK(connector)) - tor_close_socket(connector); - if (SOCKET_OK(acceptor)) - tor_close_socket(acceptor); - return -saved_errno; -} - -#undef SIZEOF_SOCKADDR - -#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */ - -/* Return the maximum number of allowed sockets. */ -int -get_max_sockets(void) -{ - return max_sockets; -} - -/** Number of extra file descriptors to keep in reserve beyond those that we - * tell Tor it's allowed to use. */ -#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */ - -/** Learn the maximum allowed number of file descriptors, and tell the - * system we want to use up to that number. (Some systems have a low soft - * limit, and let us set it higher.) We compute this by finding the largest - * number that we can use. - * - * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER), - * return -1 and <b>max_out</b> is untouched. - * - * If we can't find a number greater than or equal to <b>limit</b>, then we - * fail by returning -1 and <b>max_out</b> is untouched. - * - * If we are unable to set the limit value because of setrlimit() failing, - * return 0 and <b>max_out</b> is set to the current maximum value returned - * by getrlimit(). - * - * Otherwise, return 0 and store the maximum we found inside <b>max_out</b> - * and set <b>max_sockets</b> with that value as well.*/ -int -set_max_file_descriptors(rlim_t limit, int *max_out) -{ - if (limit < ULIMIT_BUFFER) { - log_warn(LD_CONFIG, - "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER); - return -1; - } - - /* Define some maximum connections values for systems where we cannot - * automatically determine a limit. Re Cygwin, see - * http://archives.seul.org/or/talk/Aug-2006/msg00210.html - * For an iPhone, 9999 should work. For Windows and all other unknown - * systems we use 15000 as the default. */ -#ifndef HAVE_GETRLIMIT -#if defined(CYGWIN) || defined(__CYGWIN__) - const char *platform = "Cygwin"; - const unsigned long MAX_CONNECTIONS = 3200; -#elif defined(_WIN32) - const char *platform = "Windows"; - const unsigned long MAX_CONNECTIONS = 15000; -#else - const char *platform = "unknown platforms with no getrlimit()"; - const unsigned long MAX_CONNECTIONS = 15000; -#endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */ - log_fn(LOG_INFO, LD_NET, - "This platform is missing getrlimit(). Proceeding."); - if (limit > MAX_CONNECTIONS) { - log_warn(LD_CONFIG, - "We do not support more than %lu file descriptors " - "on %s. Tried to raise to %lu.", - (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit); - return -1; - } - limit = MAX_CONNECTIONS; -#else /* !(!defined(HAVE_GETRLIMIT)) */ - struct rlimit rlim; - - if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { - log_warn(LD_NET, "Could not get maximum number of file descriptors: %s", - strerror(errno)); - return -1; - } - if (rlim.rlim_max < limit) { - log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're " - "limited to %lu. Please change your ulimit -n.", - (unsigned long)limit, (unsigned long)rlim.rlim_max); - return -1; - } - - if (rlim.rlim_max > rlim.rlim_cur) { - log_info(LD_NET,"Raising max file descriptors from %lu to %lu.", - (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max); - } - /* Set the current limit value so if the attempt to set the limit to the - * max fails at least we'll have a valid value of maximum sockets. */ - *max_out = max_sockets = (int)rlim.rlim_cur - ULIMIT_BUFFER; - rlim.rlim_cur = rlim.rlim_max; - - if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { - int couldnt_set = 1; - const int setrlimit_errno = errno; -#ifdef OPEN_MAX - uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER; - if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) { - /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is - * full of nasty lies. I'm looking at you, OSX 10.5.... */ - rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur); - if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) { - if (rlim.rlim_cur < (rlim_t)limit) { - log_warn(LD_CONFIG, "We are limited to %lu file descriptors by " - "OPEN_MAX (%lu), and ConnLimit is %lu. Changing " - "ConnLimit; sorry.", - (unsigned long)try_limit, (unsigned long)OPEN_MAX, - (unsigned long)limit); - } else { - log_info(LD_CONFIG, "Dropped connection limit to %lu based on " - "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit " - "lied to us.", - (unsigned long)try_limit, (unsigned long)OPEN_MAX, - (unsigned long)rlim.rlim_max); - } - couldnt_set = 0; - } - } -#endif /* defined(OPEN_MAX) */ - if (couldnt_set) { - log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s", - strerror(setrlimit_errno)); - } - } - /* leave some overhead for logs, etc, */ - limit = rlim.rlim_cur; -#endif /* !defined(HAVE_GETRLIMIT) */ - - if (limit > INT_MAX) - limit = INT_MAX; - tor_assert(max_out); - *max_out = max_sockets = (int)limit - ULIMIT_BUFFER; - return 0; -} - -#ifndef _WIN32 -/** Log details of current user and group credentials. Return 0 on - * success. Logs and return -1 on failure. - */ -static int -log_credential_status(void) -{ -/** Log level to use when describing non-error UID/GID status. */ -#define CREDENTIAL_LOG_LEVEL LOG_INFO - /* Real, effective and saved UIDs */ - uid_t ruid, euid, suid; - /* Read, effective and saved GIDs */ - gid_t rgid, egid, sgid; - /* Supplementary groups */ - gid_t *sup_gids = NULL; - int sup_gids_size; - /* Number of supplementary groups */ - int ngids; - - /* log UIDs */ -#ifdef HAVE_GETRESUID - if (getresuid(&ruid, &euid, &suid) != 0 ) { - log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno)); - return -1; - } else { - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "UID is %u (real), %u (effective), %u (saved)", - (unsigned)ruid, (unsigned)euid, (unsigned)suid); - } -#else /* !(defined(HAVE_GETRESUID)) */ - /* getresuid is not present on MacOS X, so we can't get the saved (E)UID */ - ruid = getuid(); - euid = geteuid(); - (void)suid; - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "UID is %u (real), %u (effective), unknown (saved)", - (unsigned)ruid, (unsigned)euid); -#endif /* defined(HAVE_GETRESUID) */ - - /* log GIDs */ -#ifdef HAVE_GETRESGID - if (getresgid(&rgid, &egid, &sgid) != 0 ) { - log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno)); - return -1; - } else { - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "GID is %u (real), %u (effective), %u (saved)", - (unsigned)rgid, (unsigned)egid, (unsigned)sgid); - } -#else /* !(defined(HAVE_GETRESGID)) */ - /* getresgid is not present on MacOS X, so we can't get the saved (E)GID */ - rgid = getgid(); - egid = getegid(); - (void)sgid; - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, - "GID is %u (real), %u (effective), unknown (saved)", - (unsigned)rgid, (unsigned)egid); -#endif /* defined(HAVE_GETRESGID) */ - - /* log supplementary groups */ - sup_gids_size = 64; - sup_gids = tor_calloc(64, sizeof(gid_t)); - while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 && - errno == EINVAL && - sup_gids_size < NGROUPS_MAX) { - sup_gids_size *= 2; - sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size); - } - - if (ngids < 0) { - log_warn(LD_GENERAL, "Error getting supplementary GIDs: %s", - strerror(errno)); - tor_free(sup_gids); - return -1; - } else { - int i, retval = 0; - char *s = NULL; - smartlist_t *elts = smartlist_new(); - - for (i = 0; i<ngids; i++) { - smartlist_add_asprintf(elts, "%u", (unsigned)sup_gids[i]); - } - - s = smartlist_join_strings(elts, " ", 0, NULL); - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Supplementary groups are: %s",s); - - tor_free(s); - SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); - smartlist_free(elts); - tor_free(sup_gids); - - return retval; - } - - return 0; -} -#endif /* !defined(_WIN32) */ - -#ifndef _WIN32 -/** Cached struct from the last getpwname() call we did successfully. */ -static struct passwd *passwd_cached = NULL; - -/** Helper: copy a struct passwd object. - * - * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use - * any others, and I don't want to run into incompatibilities. - */ -static struct passwd * -tor_passwd_dup(const struct passwd *pw) -{ - struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd)); - if (pw->pw_name) - new_pw->pw_name = tor_strdup(pw->pw_name); - if (pw->pw_dir) - new_pw->pw_dir = tor_strdup(pw->pw_dir); - new_pw->pw_uid = pw->pw_uid; - new_pw->pw_gid = pw->pw_gid; - - return new_pw; -} - -#define tor_passwd_free(pw) \ - FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw)) - -/** Helper: free one of our cached 'struct passwd' values. */ -static void -tor_passwd_free_(struct passwd *pw) -{ - if (!pw) - return; - - tor_free(pw->pw_name); - tor_free(pw->pw_dir); - tor_free(pw); -} - -/** Wrapper around getpwnam() that caches result. Used so that we don't need - * to give the sandbox access to /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - * - * When called with a NULL argument, this function clears storage associated - * with static variables it uses. - **/ -const struct passwd * -tor_getpwnam(const char *username) -{ - struct passwd *pw; - - if (username == NULL) { - tor_passwd_free(passwd_cached); - passwd_cached = NULL; - return NULL; - } - - if ((pw = getpwnam(username))) { - tor_passwd_free(passwd_cached); - passwd_cached = tor_passwd_dup(pw); - log_info(LD_GENERAL, "Caching new entry %s for %s", - passwd_cached->pw_name, username); - return pw; - } - - /* Lookup failed */ - if (! passwd_cached || ! passwd_cached->pw_name) - return NULL; - - if (! strcmp(username, passwd_cached->pw_name)) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} - -/** Wrapper around getpwnam() that can use cached result from - * tor_getpwnam(). Used so that we don't need to give the sandbox access to - * /etc/passwd. - * - * The following fields alone will definitely be copied in the output: pw_uid, - * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. - */ -const struct passwd * -tor_getpwuid(uid_t uid) -{ - struct passwd *pw; - - if ((pw = getpwuid(uid))) { - return pw; - } - - /* Lookup failed */ - if (! passwd_cached) - return NULL; - - if (uid == passwd_cached->pw_uid) - return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky - - return NULL; -} -#endif /* !defined(_WIN32) */ - -/** Return true iff we were compiled with capability support, and capabilities - * seem to work. **/ -int -have_capability_support(void) -{ -#ifdef HAVE_LINUX_CAPABILITIES - cap_t caps = cap_get_proc(); - if (caps == NULL) - return 0; - cap_free(caps); - return 1; -#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ - return 0; -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ -} - -#ifdef HAVE_LINUX_CAPABILITIES -/** Helper. Drop all capabilities but a small set, and set PR_KEEPCAPS as - * appropriate. - * - * If pre_setuid, retain only CAP_NET_BIND_SERVICE, CAP_SETUID, and - * CAP_SETGID, and use PR_KEEPCAPS to ensure that capabilities persist across - * setuid(). - * - * If not pre_setuid, retain only CAP_NET_BIND_SERVICE, and disable - * PR_KEEPCAPS. - * - * Return 0 on success, and -1 on failure. - */ -static int -drop_capabilities(int pre_setuid) -{ - /* We keep these three capabilities, and these only, as we setuid. - * After we setuid, we drop all but the first. */ - const cap_value_t caplist[] = { - CAP_NET_BIND_SERVICE, CAP_SETUID, CAP_SETGID - }; - const char *where = pre_setuid ? "pre-setuid" : "post-setuid"; - const int n_effective = pre_setuid ? 3 : 1; - const int n_permitted = pre_setuid ? 3 : 1; - const int n_inheritable = 1; - const int keepcaps = pre_setuid ? 1 : 0; - - /* Sets whether we keep capabilities across a setuid. */ - if (prctl(PR_SET_KEEPCAPS, keepcaps) < 0) { - log_warn(LD_CONFIG, "Unable to call prctl() %s: %s", - where, strerror(errno)); - return -1; - } - - cap_t caps = cap_get_proc(); - if (!caps) { - log_warn(LD_CONFIG, "Unable to call cap_get_proc() %s: %s", - where, strerror(errno)); - return -1; - } - cap_clear(caps); - - cap_set_flag(caps, CAP_EFFECTIVE, n_effective, caplist, CAP_SET); - cap_set_flag(caps, CAP_PERMITTED, n_permitted, caplist, CAP_SET); - cap_set_flag(caps, CAP_INHERITABLE, n_inheritable, caplist, CAP_SET); - - int r = cap_set_proc(caps); - cap_free(caps); - if (r < 0) { - log_warn(LD_CONFIG, "No permission to set capabilities %s: %s", - where, strerror(errno)); - return -1; - } - - return 0; -} -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - -/** Call setuid and setgid to run as <b>user</b> and switch to their - * primary group. Return 0 on success. On failure, log and return -1. - * - * If SWITCH_ID_KEEP_BINDLOW is set in 'flags', try to use the capability - * system to retain the abilitity to bind low ports. - * - * If SWITCH_ID_WARN_IF_NO_CAPS is set in flags, also warn if we have - * don't have capability support. - */ -int -switch_id(const char *user, const unsigned flags) -{ -#ifndef _WIN32 - const struct passwd *pw = NULL; - uid_t old_uid; - gid_t old_gid; - static int have_already_switched_id = 0; - const int keep_bindlow = !!(flags & SWITCH_ID_KEEP_BINDLOW); - const int warn_if_no_caps = !!(flags & SWITCH_ID_WARN_IF_NO_CAPS); - - tor_assert(user); - - if (have_already_switched_id) - return 0; - - /* Log the initial credential state */ - if (log_credential_status()) - return -1; - - log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Changing user and groups"); - - /* Get old UID/GID to check if we changed correctly */ - old_uid = getuid(); - old_gid = getgid(); - - /* Lookup the user and group information, if we have a problem, bail out. */ - pw = tor_getpwnam(user); - if (pw == NULL) { - log_warn(LD_CONFIG, "Error setting configured user: %s not found", user); - return -1; - } - -#ifdef HAVE_LINUX_CAPABILITIES - (void) warn_if_no_caps; - if (keep_bindlow) { - if (drop_capabilities(1)) - return -1; - } -#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ - (void) keep_bindlow; - if (warn_if_no_caps) { - log_warn(LD_CONFIG, "KeepBindCapabilities set, but no capability support " - "on this system."); - } -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - - /* Properly switch egid,gid,euid,uid here or bail out */ - if (setgroups(1, &pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting groups to gid %d: \"%s\".", - (int)pw->pw_gid, strerror(errno)); - if (old_uid == pw->pw_uid) { - log_warn(LD_GENERAL, "Tor is already running as %s. You do not need " - "the \"User\" option if you are already running as the user " - "you want to be. (If you did not set the User option in your " - "torrc, check whether it was specified on the command line " - "by a startup script.)", user); - } else { - log_warn(LD_GENERAL, "If you set the \"User\" option, you must start Tor" - " as root."); - } - return -1; - } - - if (setegid(pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting egid to %d: %s", - (int)pw->pw_gid, strerror(errno)); - return -1; - } - - if (setgid(pw->pw_gid)) { - log_warn(LD_GENERAL, "Error setting gid to %d: %s", - (int)pw->pw_gid, strerror(errno)); - return -1; - } - - if (setuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured uid to %s (%d): %s", - user, (int)pw->pw_uid, strerror(errno)); - return -1; - } - - if (seteuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured euid to %s (%d): %s", - user, (int)pw->pw_uid, strerror(errno)); - return -1; - } - - /* This is how OpenBSD rolls: - if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || - setgid(pw->pw_gid) || setuid(pw->pw_uid) || seteuid(pw->pw_uid)) { - setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) { - log_warn(LD_GENERAL, "Error setting configured UID/GID: %s", - strerror(errno)); - return -1; - } - */ - - /* We've properly switched egid, gid, euid, uid, and supplementary groups if - * we're here. */ -#ifdef HAVE_LINUX_CAPABILITIES - if (keep_bindlow) { - if (drop_capabilities(0)) - return -1; - } -#endif /* defined(HAVE_LINUX_CAPABILITIES) */ - -#if !defined(CYGWIN) && !defined(__CYGWIN__) - /* If we tried to drop privilege to a group/user other than root, attempt to - * restore root (E)(U|G)ID, and abort if the operation succeeds */ - - /* Only check for privilege dropping if we were asked to be non-root */ - if (pw->pw_uid) { - /* Try changing GID/EGID */ - if (pw->pw_gid != old_gid && - (setgid(old_gid) != -1 || setegid(old_gid) != -1)) { - log_warn(LD_GENERAL, "Was able to restore group credentials even after " - "switching GID: this means that the setgid code didn't work."); - return -1; - } - - /* Try changing UID/EUID */ - if (pw->pw_uid != old_uid && - (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) { - log_warn(LD_GENERAL, "Was able to restore user credentials even after " - "switching UID: this means that the setuid code didn't work."); - return -1; - } - } -#endif /* !defined(CYGWIN) && !defined(__CYGWIN__) */ - - /* Check what really happened */ - if (log_credential_status()) { - return -1; - } - - have_already_switched_id = 1; /* mark success so we never try again */ - -#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && \ - defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) - if (pw->pw_uid) { - /* Re-enable core dumps if we're not running as root. */ - log_info(LD_CONFIG, "Re-enabling coredumps"); - if (prctl(PR_SET_DUMPABLE, 1)) { - log_warn(LD_CONFIG, "Unable to re-enable coredumps: %s",strerror(errno)); - } - } -#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && ... */ - return 0; - -#else /* !(!defined(_WIN32)) */ - (void)user; - (void)flags; - - log_warn(LD_CONFIG, "Switching users is unsupported on your OS."); - return -1; -#endif /* !defined(_WIN32) */ -} - -/* We only use the linux prctl for now. There is no Win32 support; this may - * also work on various BSD systems and Mac OS X - send testing feedback! - * - * On recent Gnu/Linux kernels it is possible to create a system-wide policy - * that will prevent non-root processes from attaching to other processes - * unless they are the parent process; thus gdb can attach to programs that - * they execute but they cannot attach to other processes running as the same - * user. The system wide policy may be set with the sysctl - * kernel.yama.ptrace_scope or by inspecting - * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04. - * - * This ptrace scope will be ignored on Gnu/Linux for users with - * CAP_SYS_PTRACE and so it is very likely that root will still be able to - * attach to the Tor process. - */ -/** Attempt to disable debugger attachment: return 1 on success, -1 on - * failure, and 0 if we don't know how to try on this platform. */ -int -tor_disable_debugger_attach(void) -{ - int r = -1; - log_debug(LD_CONFIG, - "Attemping to disable debugger attachment to Tor for " - "unprivileged users."); -#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) \ - && defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) -#define TRIED_TO_DISABLE - r = prctl(PR_SET_DUMPABLE, 0); -#elif defined(__APPLE__) && defined(PT_DENY_ATTACH) -#define TRIED_TO_ATTACH - r = ptrace(PT_DENY_ATTACH, 0, 0, 0); -#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) ... || ... */ - - // XXX: TODO - Mac OS X has dtrace and this may be disabled. - // XXX: TODO - Windows probably has something similar -#ifdef TRIED_TO_DISABLE - if (r == 0) { - log_debug(LD_CONFIG,"Debugger attachment disabled for " - "unprivileged users."); - return 1; - } else { - log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s", - strerror(errno)); - } -#endif /* defined(TRIED_TO_DISABLE) */ -#undef TRIED_TO_DISABLE - return r; -} - -#ifdef HAVE_PWD_H -/** Allocate and return a string containing the home directory for the - * user <b>username</b>. Only works on posix-like systems. */ -char * -get_user_homedir(const char *username) -{ - const struct passwd *pw; - tor_assert(username); - - if (!(pw = tor_getpwnam(username))) { - log_err(LD_CONFIG,"User \"%s\" not found.", username); - return NULL; - } - return tor_strdup(pw->pw_dir); -} -#endif /* defined(HAVE_PWD_H) */ - -/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't - * actually examine the filesystem; does a purely syntactic modification. - * - * The parent of the root director is considered to be iteself. - * - * Path separators are the forward slash (/) everywhere and additionally - * the backslash (\) on Win32. - * - * Cuts off any number of trailing path separators but otherwise ignores - * them for purposes of finding the parent directory. - * - * Returns 0 if a parent directory was successfully found, -1 otherwise (fname - * did not have any path separators or only had them at the end). - * */ -int -get_parent_directory(char *fname) -{ - char *cp; - int at_end = 1; - tor_assert(fname); -#ifdef _WIN32 - /* If we start with, say, c:, then don't consider that the start of the path - */ - if (fname[0] && fname[1] == ':') { - fname += 2; - } -#endif /* defined(_WIN32) */ - /* Now we want to remove all path-separators at the end of the string, - * and to remove the end of the string starting with the path separator - * before the last non-path-separator. In perl, this would be - * s#[/]*$##; s#/[^/]*$##; - * on a unixy platform. - */ - cp = fname + strlen(fname); - at_end = 1; - while (--cp >= fname) { - int is_sep = (*cp == '/' -#ifdef _WIN32 - || *cp == '\\' -#endif - ); - if (is_sep) { - if (cp == fname) { - /* This is the first separator in the file name; don't remove it! */ - cp[1] = '\0'; - return 0; - } - *cp = '\0'; - if (! at_end) - return 0; - } else { - at_end = 0; - } - } - return -1; -} - -#ifndef _WIN32 -/** Return a newly allocated string containing the output of getcwd(). Return - * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since - * Hurd hasn't got a PATH_MAX.) - */ -static char * -alloc_getcwd(void) -{ -#ifdef HAVE_GET_CURRENT_DIR_NAME - /* Glibc makes this nice and simple for us. */ - char *cwd = get_current_dir_name(); - char *result = NULL; - if (cwd) { - /* We make a copy here, in case tor_malloc() is not malloc(). */ - result = tor_strdup(cwd); - raw_free(cwd); // alias for free to avoid tripping check-spaces. - } - return result; -#else /* !(defined(HAVE_GET_CURRENT_DIR_NAME)) */ - size_t size = 1024; - char *buf = NULL; - char *ptr = NULL; - - while (ptr == NULL) { - buf = tor_realloc(buf, size); - ptr = getcwd(buf, size); - - if (ptr == NULL && errno != ERANGE) { - tor_free(buf); - return NULL; - } - - size *= 2; - } - return buf; -#endif /* defined(HAVE_GET_CURRENT_DIR_NAME) */ -} -#endif /* !defined(_WIN32) */ - -/** Expand possibly relative path <b>fname</b> to an absolute path. - * Return a newly allocated string, possibly equal to <b>fname</b>. */ -char * -make_path_absolute(char *fname) -{ -#ifdef _WIN32 - char *absfname_malloced = _fullpath(NULL, fname, 1); - - /* We don't want to assume that tor_free can free a string allocated - * with malloc. On failure, return fname (it's better than nothing). */ - char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); - if (absfname_malloced) raw_free(absfname_malloced); - - return absfname; -#else /* !(defined(_WIN32)) */ - char *absfname = NULL, *path = NULL; - - tor_assert(fname); - - if (fname[0] == '/') { - absfname = tor_strdup(fname); - } else { - path = alloc_getcwd(); - if (path) { - tor_asprintf(&absfname, "%s/%s", path, fname); - tor_free(path); - } else { - /* LCOV_EXCL_START Can't make getcwd fail. */ - /* If getcwd failed, the best we can do here is keep using the - * relative path. (Perhaps / isn't readable by this UID/GID.) */ - log_warn(LD_GENERAL, "Unable to find current working directory: %s", - strerror(errno)); - absfname = tor_strdup(fname); - /* LCOV_EXCL_STOP */ - } - } - return absfname; -#endif /* defined(_WIN32) */ -} - -#ifndef HAVE__NSGETENVIRON -#ifndef HAVE_EXTERN_ENVIRON_DECLARED -/* Some platforms declare environ under some circumstances, others don't. */ -#ifndef RUNNING_DOXYGEN -extern char **environ; -#endif -#endif /* !defined(HAVE_EXTERN_ENVIRON_DECLARED) */ -#endif /* !defined(HAVE__NSGETENVIRON) */ - -/** Return the current environment. This is a portable replacement for - * 'environ'. */ -char ** -get_environment(void) -{ -#ifdef HAVE__NSGETENVIRON - /* This is for compatibility between OSX versions. Otherwise (for example) - * when we do a mostly-static build on OSX 10.7, the resulting binary won't - * work on OSX 10.6. */ - return *_NSGetEnviron(); -#else /* !(defined(HAVE__NSGETENVIRON)) */ - return environ; -#endif /* defined(HAVE__NSGETENVIRON) */ -} - -/** Get name of current host and write it to <b>name</b> array, whose - * length is specified by <b>namelen</b> argument. Return 0 upon - * successful completion; otherwise return return -1. (Currently, - * this function is merely a mockable wrapper for POSIX gethostname().) - */ -MOCK_IMPL(int, -tor_gethostname,(char *name, size_t namelen)) -{ - return gethostname(name,namelen); -} - -/** Set *addr to the IP address (in dotted-quad notation) stored in *str. - * Return 1 on success, 0 if *str is badly formatted. - * (Like inet_aton(str,addr), but works on Windows and Solaris.) - */ -int -tor_inet_aton(const char *str, struct in_addr* addr) -{ - unsigned a,b,c,d; - char more; - if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) - return 0; - if (a > 255) return 0; - if (b > 255) return 0; - if (c > 255) return 0; - if (d > 255) return 0; - addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); - return 1; -} - -/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or - * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the - * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns - * <b>dst</b> on success, NULL on failure. - * - * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it: - * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6 - * support.) */ -const char * -tor_inet_ntop(int af, const void *src, char *dst, size_t len) -{ - if (af == AF_INET) { - if (tor_inet_ntoa(src, dst, len) < 0) - return NULL; - else - return dst; - } else if (af == AF_INET6) { - const struct in6_addr *addr = src; - char buf[64], *cp; - int longestGapLen = 0, longestGapPos = -1, i, - curGapPos = -1, curGapLen = 0; - uint16_t words[8]; - for (i = 0; i < 8; ++i) { - words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1]; - } - if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && - words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) || - (words[5] == 0xffff))) { - /* This is an IPv4 address. */ - if (words[5] == 0) { - tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d", - addr->s6_addr[12], addr->s6_addr[13], - addr->s6_addr[14], addr->s6_addr[15]); - } else { - tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5], - addr->s6_addr[12], addr->s6_addr[13], - addr->s6_addr[14], addr->s6_addr[15]); - } - if ((strlen(buf) + 1) > len) /* +1 for \0 */ - return NULL; - strlcpy(dst, buf, len); - return dst; - } - i = 0; - while (i < 8) { - if (words[i] == 0) { - curGapPos = i++; - curGapLen = 1; - while (i<8 && words[i] == 0) { - ++i; ++curGapLen; - } - if (curGapLen > longestGapLen) { - longestGapPos = curGapPos; - longestGapLen = curGapLen; - } - } else { - ++i; - } - } - if (longestGapLen<=1) - longestGapPos = -1; - - cp = buf; - for (i = 0; i < 8; ++i) { - if (words[i] == 0 && longestGapPos == i) { - if (i == 0) - *cp++ = ':'; - *cp++ = ':'; - while (i < 8 && words[i] == 0) - ++i; - --i; /* to compensate for loop increment. */ - } else { - tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); - cp += strlen(cp); - if (i != 7) - *cp++ = ':'; - } - } - *cp = '\0'; - if ((strlen(buf) + 1) > len) /* +1 for \0 */ - return NULL; - strlcpy(dst, buf, len); - return dst; - } else { - return NULL; - } -} - -/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b> - * encoding an IPv4 address or IPv6 address correspondingly, try to parse the - * address and store the result in <b>dst</b> (which must have space for a - * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success, - * 0 on a bad parse, and -1 on a bad <b>af</b>. - * - * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor - * sometimes needs to format ipv6 addresses even on platforms without ipv6 - * support.) */ -int -tor_inet_pton(int af, const char *src, void *dst) -{ - if (af == AF_INET) { - return tor_inet_aton(src, dst); - } else if (af == AF_INET6) { - struct in6_addr *out = dst; - uint16_t words[8]; - int gapPos = -1, i, setWords=0; - const char *dot = strchr(src, '.'); - const char *eow; /* end of words. */ - memset(words, 0xf8, sizeof(words)); - if (dot == src) - return 0; - else if (!dot) - eow = src+strlen(src); - else { - unsigned byte1,byte2,byte3,byte4; - char more; - for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow) - ; - if (*eow != ':') - return 0; - ++eow; - - /* We use "scanf" because some platform inet_aton()s are too lax - * about IPv4 addresses of the form "1.2.3" */ - if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c", - &byte1,&byte2,&byte3,&byte4,&more) != 4) - return 0; - - if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255) - return 0; - - words[6] = (byte1<<8) | byte2; - words[7] = (byte3<<8) | byte4; - setWords += 2; - } - - i = 0; - while (src < eow) { - if (i > 7) - return 0; - if (TOR_ISXDIGIT(*src)) { - char *next; - ssize_t len; - long r = strtol(src, &next, 16); - if (next == NULL || next == src) { - /* The 'next == src' error case can happen on versions of openbsd - * which treat "0xfoo" as an error, rather than as "0" followed by - * "xfoo". */ - return 0; - } - - len = *next == '\0' ? eow - src : next - src; - if (len > 4) - return 0; - if (len > 1 && !TOR_ISXDIGIT(src[1])) - return 0; /* 0x is not valid */ - - tor_assert(r >= 0); - tor_assert(r < 65536); - words[i++] = (uint16_t)r; - setWords++; - src = next; - if (*src != ':' && src != eow) - return 0; - ++src; - } else if (*src == ':' && i > 0 && gapPos == -1) { - gapPos = i; - ++src; - } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' && - gapPos == -1) { - gapPos = i; - src += 2; - } else { - return 0; - } - } - - if (setWords > 8 || - (setWords == 8 && gapPos != -1) || - (setWords < 8 && gapPos == -1)) - return 0; - - if (gapPos >= 0) { - int nToMove = setWords - (dot ? 2 : 0) - gapPos; - int gapLen = 8 - setWords; - tor_assert(nToMove >= 0); - memmove(&words[gapPos+gapLen], &words[gapPos], - sizeof(uint16_t)*nToMove); - memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen); - } - for (i = 0; i < 8; ++i) { - out->s6_addr[2*i ] = words[i] >> 8; - out->s6_addr[2*i+1] = words[i] & 0xff; - } - - return 1; - } else { - return -1; - } -} - -/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set - * *<b>addr</b> to the proper IP address, in host byte order. Returns 0 - * on success, -1 on failure; 1 on transient failure. - * - * (This function exists because standard windows gethostbyname - * doesn't treat raw IP addresses properly.) - */ - -MOCK_IMPL(int, -tor_lookup_hostname,(const char *name, uint32_t *addr)) -{ - tor_addr_t myaddr; - int ret; - - if ((ret = tor_addr_lookup(name, AF_INET, &myaddr))) - return ret; - - if (tor_addr_family(&myaddr) == AF_INET) { - *addr = tor_addr_to_ipv4h(&myaddr); - return ret; - } - - return -1; -} - -/** Hold the result of our call to <b>uname</b>. */ -static char uname_result[256]; -/** True iff uname_result is set. */ -static int uname_result_is_set = 0; - -/** Return a pointer to a description of our platform. - */ -MOCK_IMPL(const char *, -get_uname,(void)) -{ -#ifdef HAVE_UNAME - struct utsname u; -#endif - if (!uname_result_is_set) { -#ifdef HAVE_UNAME - if (uname(&u) != -1) { - /* (Linux says 0 is success, Solaris says 1 is success) */ - strlcpy(uname_result, u.sysname, sizeof(uname_result)); - } else -#endif /* defined(HAVE_UNAME) */ - { -#ifdef _WIN32 - OSVERSIONINFOEX info; - int i; - const char *plat = NULL; - static struct { - unsigned major; unsigned minor; const char *version; - } win_version_table[] = { - { 6, 2, "Windows 8" }, - { 6, 1, "Windows 7" }, - { 6, 0, "Windows Vista" }, - { 5, 2, "Windows Server 2003" }, - { 5, 1, "Windows XP" }, - { 5, 0, "Windows 2000" }, - /* { 4, 0, "Windows NT 4.0" }, */ - { 4, 90, "Windows Me" }, - { 4, 10, "Windows 98" }, - /* { 4, 0, "Windows 95" } */ - { 3, 51, "Windows NT 3.51" }, - { 0, 0, NULL } - }; - memset(&info, 0, sizeof(info)); - info.dwOSVersionInfoSize = sizeof(info); - if (! GetVersionEx((LPOSVERSIONINFO)&info)) { - strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx" - " doesn't work.", sizeof(uname_result)); - uname_result_is_set = 1; - return uname_result; - } - if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) { - if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) - plat = "Windows NT 4.0"; - else - plat = "Windows 95"; - } else { - for (i=0; win_version_table[i].major>0; ++i) { - if (win_version_table[i].major == info.dwMajorVersion && - win_version_table[i].minor == info.dwMinorVersion) { - plat = win_version_table[i].version; - break; - } - } - } - if (plat) { - strlcpy(uname_result, plat, sizeof(uname_result)); - } else { - if (info.dwMajorVersion > 6 || - (info.dwMajorVersion==6 && info.dwMinorVersion>2)) - tor_snprintf(uname_result, sizeof(uname_result), - "Very recent version of Windows [major=%d,minor=%d]", - (int)info.dwMajorVersion,(int)info.dwMinorVersion); - else - tor_snprintf(uname_result, sizeof(uname_result), - "Unrecognized version of Windows [major=%d,minor=%d]", - (int)info.dwMajorVersion,(int)info.dwMinorVersion); - } -#ifdef VER_NT_SERVER - if (info.wProductType == VER_NT_SERVER || - info.wProductType == VER_NT_DOMAIN_CONTROLLER) { - strlcat(uname_result, " [server]", sizeof(uname_result)); - } -#endif /* defined(VER_NT_SERVER) */ -#else /* !(defined(_WIN32)) */ - /* LCOV_EXCL_START -- can't provoke uname failure */ - strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); - /* LCOV_EXCL_STOP */ -#endif /* defined(_WIN32) */ - } - uname_result_is_set = 1; - } - return uname_result; -} - -/* - * Process control - */ - -/** Implementation logic for compute_num_cpus(). */ -static int -compute_num_cpus_impl(void) -{ -#ifdef _WIN32 - SYSTEM_INFO info; - memset(&info, 0, sizeof(info)); - GetSystemInfo(&info); - if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX) - return (int)info.dwNumberOfProcessors; - else - return -1; -#elif defined(HAVE_SYSCONF) -#ifdef _SC_NPROCESSORS_CONF - long cpus_conf = sysconf(_SC_NPROCESSORS_CONF); -#else - long cpus_conf = -1; -#endif -#ifdef _SC_NPROCESSORS_ONLN - long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN); -#else - long cpus_onln = -1; -#endif - long cpus = -1; - - if (cpus_conf > 0 && cpus_onln < 0) { - cpus = cpus_conf; - } else if (cpus_onln > 0 && cpus_conf < 0) { - cpus = cpus_onln; - } else if (cpus_onln > 0 && cpus_conf > 0) { - if (cpus_onln < cpus_conf) { - log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " - "are available. Telling Tor to only use %ld. You can over" - "ride this with the NumCPUs option", - cpus_conf, cpus_onln, cpus_onln); - } - cpus = cpus_onln; - } - - if (cpus >= 1 && cpus < INT_MAX) - return (int)cpus; - else - return -1; -#else - return -1; -#endif /* defined(_WIN32) || ... */ -} - -#define MAX_DETECTABLE_CPUS 16 - -/** Return how many CPUs we are running with. We assume that nobody is - * using hot-swappable CPUs, so we don't recompute this after the first - * time. Return -1 if we don't know how to tell the number of CPUs on this - * system. - */ -int -compute_num_cpus(void) -{ - static int num_cpus = -2; - if (num_cpus == -2) { - num_cpus = compute_num_cpus_impl(); - tor_assert(num_cpus != -2); - if (num_cpus > MAX_DETECTABLE_CPUS) { - /* LCOV_EXCL_START */ - log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I " - "will not autodetect any more than %d, though. If you " - "want to configure more, set NumCPUs in your torrc", - num_cpus, MAX_DETECTABLE_CPUS); - num_cpus = MAX_DETECTABLE_CPUS; - /* LCOV_EXCL_STOP */ - } - } - return num_cpus; -} - -#if !defined(_WIN32) -/** Defined iff we need to add locks when defining fake versions of reentrant - * versions of time-related functions. */ -#define TIME_FNS_NEED_LOCKS -#endif - -/** Helper: Deal with confused or out-of-bounds values from localtime_r and - * friends. (On some platforms, they can give out-of-bounds values or can - * return NULL.) If <b>islocal</b>, this is a localtime result; otherwise - * it's from gmtime. The function returns <b>r</b>, when given <b>timep</b> - * as its input. If we need to store new results, store them in - * <b>resultbuf</b>. */ -static struct tm * -correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, - struct tm *r) -{ - const char *outcome; - - if (PREDICT_LIKELY(r)) { - /* We can't strftime dates after 9999 CE, and we want to avoid dates - * before 1 CE (avoiding the year 0 issue and negative years). */ - if (r->tm_year > 8099) { - r->tm_year = 8099; - r->tm_mon = 11; - r->tm_mday = 31; - r->tm_yday = 364; - r->tm_wday = 6; - r->tm_hour = 23; - r->tm_min = 59; - r->tm_sec = 59; - } else if (r->tm_year < (1-1900)) { - r->tm_year = (1-1900); - r->tm_mon = 0; - r->tm_mday = 1; - r->tm_yday = 0; - r->tm_wday = 0; - r->tm_hour = 0; - r->tm_min = 0; - r->tm_sec = 0; - } - return r; - } - - /* If we get here, gmtime or localtime returned NULL. It might have done - * this because of overrun or underrun, or it might have done it because of - * some other weird issue. */ - if (timep) { - if (*timep < 0) { - r = resultbuf; - r->tm_year = 70; /* 1970 CE */ - r->tm_mon = 0; - r->tm_mday = 1; - r->tm_yday = 0; - r->tm_wday = 0; - r->tm_hour = 0; - r->tm_min = 0 ; - r->tm_sec = 0; - outcome = "Rounding up to 1970"; - goto done; - } else if (*timep >= INT32_MAX) { - /* Rounding down to INT32_MAX isn't so great, but keep in mind that we - * only do it if gmtime/localtime tells us NULL. */ - r = resultbuf; - r->tm_year = 137; /* 2037 CE */ - r->tm_mon = 11; - r->tm_mday = 31; - r->tm_yday = 364; - r->tm_wday = 6; - r->tm_hour = 23; - r->tm_min = 59; - r->tm_sec = 59; - outcome = "Rounding down to 2037"; - goto done; - } - } - - /* If we get here, then gmtime/localtime failed without getting an extreme - * value for *timep */ - /* LCOV_EXCL_START */ - tor_fragile_assert(); - r = resultbuf; - memset(resultbuf, 0, sizeof(struct tm)); - outcome="can't recover"; - /* LCOV_EXCL_STOP */ - done: - log_warn(LD_BUG, "%s("I64_FORMAT") failed with error %s: %s", - islocal?"localtime":"gmtime", - timep?I64_PRINTF_ARG(*timep):0, - strerror(errno), - outcome); - return r; -} - -/** @{ */ -/** As localtime_r, but defined for platforms that don't have it: - * - * Convert *<b>timep</b> to a struct tm in local time, and store the value in - * *<b>result</b>. Return the result on success, or NULL on failure. - */ -#ifdef HAVE_LOCALTIME_R -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - r = localtime_r(timep, result); - return correct_tm(1, timep, result, r); -} -#elif defined(TIME_FNS_NEED_LOCKS) -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - static tor_mutex_t *m=NULL; - if (!m) { m=tor_mutex_new(); } - tor_assert(result); - tor_mutex_acquire(m); - r = localtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - tor_mutex_release(m); - return correct_tm(1, timep, result, r); -} -#else -struct tm * -tor_localtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - tor_assert(result); - r = localtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - return correct_tm(1, timep, result, r); -} -#endif /* defined(HAVE_LOCALTIME_R) || ... */ -/** @} */ - -/** @{ */ -/** As gmtime_r, but defined for platforms that don't have it: - * - * Convert *<b>timep</b> to a struct tm in UTC, and store the value in - * *<b>result</b>. Return the result on success, or NULL on failure. - */ -#ifdef HAVE_GMTIME_R -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - r = gmtime_r(timep, result); - return correct_tm(0, timep, result, r); -} -#elif defined(TIME_FNS_NEED_LOCKS) -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - static tor_mutex_t *m=NULL; - if (!m) { m=tor_mutex_new(); } - tor_assert(result); - tor_mutex_acquire(m); - r = gmtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - tor_mutex_release(m); - return correct_tm(0, timep, result, r); -} -#else -struct tm * -tor_gmtime_r(const time_t *timep, struct tm *result) -{ - struct tm *r; - tor_assert(result); - r = gmtime(timep); - if (r) - memcpy(result, r, sizeof(struct tm)); - return correct_tm(0, timep, result, r); -} -#endif /* defined(HAVE_GMTIME_R) || ... */ - -#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) -#define HAVE_UNIX_MLOCKALL -#endif - -#ifdef HAVE_UNIX_MLOCKALL -/** Attempt to raise the current and max rlimit to infinity for our process. - * This only needs to be done once and can probably only be done when we have - * not already dropped privileges. - */ -static int -tor_set_max_memlock(void) -{ - /* Future consideration for Windows is probably SetProcessWorkingSetSize - * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK - * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx - */ - - struct rlimit limit; - - /* RLIM_INFINITY is -1 on some platforms. */ - limit.rlim_cur = RLIM_INFINITY; - limit.rlim_max = RLIM_INFINITY; - - if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) { - if (errno == EPERM) { - log_warn(LD_GENERAL, "You appear to lack permissions to change memory " - "limits. Are you root?"); - } - log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s", - strerror(errno)); - return -1; - } - - return 0; -} -#endif /* defined(HAVE_UNIX_MLOCKALL) */ - -/** Attempt to lock all current and all future memory pages. - * This should only be called once and while we're privileged. - * Like mlockall() we return 0 when we're successful and -1 when we're not. - * Unlike mlockall() we return 1 if we've already attempted to lock memory. - */ -int -tor_mlockall(void) -{ - static int memory_lock_attempted = 0; - - if (memory_lock_attempted) { - return 1; - } - - memory_lock_attempted = 1; - - /* - * Future consideration for Windows may be VirtualLock - * VirtualLock appears to implement mlock() but not mlockall() - * - * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx - */ - -#ifdef HAVE_UNIX_MLOCKALL - if (tor_set_max_memlock() == 0) { - log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY."); - } - - if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) { - log_info(LD_GENERAL, "Insecure OS paging is effectively disabled."); - return 0; - } else { - if (errno == ENOSYS) { - /* Apple - it's 2009! I'm looking at you. Grrr. */ - log_notice(LD_GENERAL, "It appears that mlockall() is not available on " - "your platform."); - } else if (errno == EPERM) { - log_notice(LD_GENERAL, "It appears that you lack the permissions to " - "lock memory. Are you root?"); - } - log_notice(LD_GENERAL, "Unable to lock all current and future memory " - "pages: %s", strerror(errno)); - return -1; - } -#else /* !(defined(HAVE_UNIX_MLOCKALL)) */ - log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?"); - return -1; -#endif /* defined(HAVE_UNIX_MLOCKALL) */ -} - -/** - * On Windows, WSAEWOULDBLOCK is not always correct: when you see it, - * you need to ask the socket for its actual errno. Also, you need to - * get your errors from WSAGetLastError, not errno. (If you supply a - * socket of -1, we check WSAGetLastError, but don't correct - * WSAEWOULDBLOCKs.) - * - * The upshot of all of this is that when a socket call fails, you - * should call tor_socket_errno <em>at most once</em> on the failing - * socket to get the error. - */ -#if defined(_WIN32) -int -tor_socket_errno(tor_socket_t sock) -{ - int optval, optvallen=sizeof(optval); - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK && SOCKET_OK(sock)) { - if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen)) - return err; - if (optval) - return optval; - } - return err; -} -#endif /* defined(_WIN32) */ - -#if defined(_WIN32) -#define E(code, s) { code, (s " [" #code " ]") } -struct { int code; const char *msg; } windows_socket_errors[] = { - E(WSAEINTR, "Interrupted function call"), - E(WSAEACCES, "Permission denied"), - E(WSAEFAULT, "Bad address"), - E(WSAEINVAL, "Invalid argument"), - E(WSAEMFILE, "Too many open files"), - E(WSAEWOULDBLOCK, "Resource temporarily unavailable"), - E(WSAEINPROGRESS, "Operation now in progress"), - E(WSAEALREADY, "Operation already in progress"), - E(WSAENOTSOCK, "Socket operation on nonsocket"), - E(WSAEDESTADDRREQ, "Destination address required"), - E(WSAEMSGSIZE, "Message too long"), - E(WSAEPROTOTYPE, "Protocol wrong for socket"), - E(WSAENOPROTOOPT, "Bad protocol option"), - E(WSAEPROTONOSUPPORT, "Protocol not supported"), - E(WSAESOCKTNOSUPPORT, "Socket type not supported"), - /* What's the difference between NOTSUPP and NOSUPPORT? :) */ - E(WSAEOPNOTSUPP, "Operation not supported"), - E(WSAEPFNOSUPPORT, "Protocol family not supported"), - E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"), - E(WSAEADDRINUSE, "Address already in use"), - E(WSAEADDRNOTAVAIL, "Cannot assign requested address"), - E(WSAENETDOWN, "Network is down"), - E(WSAENETUNREACH, "Network is unreachable"), - E(WSAENETRESET, "Network dropped connection on reset"), - E(WSAECONNABORTED, "Software caused connection abort"), - E(WSAECONNRESET, "Connection reset by peer"), - E(WSAENOBUFS, "No buffer space available"), - E(WSAEISCONN, "Socket is already connected"), - E(WSAENOTCONN, "Socket is not connected"), - E(WSAESHUTDOWN, "Cannot send after socket shutdown"), - E(WSAETIMEDOUT, "Connection timed out"), - E(WSAECONNREFUSED, "Connection refused"), - E(WSAEHOSTDOWN, "Host is down"), - E(WSAEHOSTUNREACH, "No route to host"), - E(WSAEPROCLIM, "Too many processes"), - /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */ - E(WSASYSNOTREADY, "Network subsystem is unavailable"), - E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"), - E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"), - E(WSAEDISCON, "Graceful shutdown now in progress"), -#ifdef WSATYPE_NOT_FOUND - E(WSATYPE_NOT_FOUND, "Class type not found"), -#endif - E(WSAHOST_NOT_FOUND, "Host not found"), - E(WSATRY_AGAIN, "Nonauthoritative host not found"), - E(WSANO_RECOVERY, "This is a nonrecoverable error"), - E(WSANO_DATA, "Valid name, no data record of requested type)"), - - /* There are some more error codes whose numeric values are marked - * <b>OS dependent</b>. They start with WSA_, apparently for the same - * reason that practitioners of some craft traditions deliberately - * introduce imperfections into their baskets and rugs "to allow the - * evil spirits to escape." If we catch them, then our binaries - * might not report consistent results across versions of Windows. - * Thus, I'm going to let them all fall through. - */ - { -1, NULL }, -}; -/** There does not seem to be a strerror equivalent for Winsock errors. - * Naturally, we have to roll our own. - */ -const char * -tor_socket_strerror(int e) -{ - int i; - for (i=0; windows_socket_errors[i].code >= 0; ++i) { - if (e == windows_socket_errors[i].code) - return windows_socket_errors[i].msg; - } - return strerror(e); -} -#endif /* defined(_WIN32) */ - -/** Called before we make any calls to network-related functions. - * (Some operating systems require their network libraries to be - * initialized.) */ -int -network_init(void) -{ -#ifdef _WIN32 - /* This silly exercise is necessary before windows will allow - * gethostbyname to work. */ - WSADATA WSAData; - int r; - r = WSAStartup(0x101,&WSAData); - if (r) { - log_warn(LD_NET,"Error initializing windows network layer: code was %d",r); - return -1; - } - if (sizeof(SOCKET) != sizeof(tor_socket_t)) { - log_warn(LD_BUG,"The tor_socket_t type does not match SOCKET in size; Tor " - "might not work. (Sizes are %d and %d respectively.)", - (int)sizeof(tor_socket_t), (int)sizeof(SOCKET)); - } - /* WSAData.iMaxSockets might show the max sockets we're allowed to use. - * We might use it to complain if we're trying to be a server but have - * too few sockets available. */ -#endif /* defined(_WIN32) */ - return 0; -} - -#ifdef _WIN32 -/** Return a newly allocated string describing the windows system error code - * <b>err</b>. Note that error codes are different from errno. Error codes - * come from GetLastError() when a winapi call fails. errno is set only when - * ANSI functions fail. Whee. */ -char * -format_win32_error(DWORD err) -{ - TCHAR *str = NULL; - char *result; - DWORD n; - - /* Somebody once decided that this interface was better than strerror(). */ - n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, - MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), - (LPVOID)&str, - 0, NULL); - - if (str && n) { -#ifdef UNICODE - size_t len; - if (n > 128*1024) - len = (128 * 1024) * 2 + 1; /* This shouldn't be possible, but let's - * make sure. */ - else - len = n * 2 + 1; - result = tor_malloc(len); - wcstombs(result,str,len); - result[len-1] = '\0'; -#else /* !(defined(UNICODE)) */ - result = tor_strdup(str); -#endif /* defined(UNICODE) */ - } else { - result = tor_strdup("<unformattable error>"); - } - if (str) { - LocalFree(str); /* LocalFree != free() */ - } - return result; -} -#endif /* defined(_WIN32) */ - -#if defined(HW_PHYSMEM64) -/* This appears to be an OpenBSD thing */ -#define INT64_HW_MEM HW_PHYSMEM64 -#elif defined(HW_MEMSIZE) -/* OSX defines this one */ -#define INT64_HW_MEM HW_MEMSIZE -#endif /* defined(HW_PHYSMEM64) || ... */ - -/** - * Helper: try to detect the total system memory, and return it. On failure, - * return 0. - */ -static uint64_t -get_total_system_memory_impl(void) -{ -#if defined(__linux__) - /* On linux, sysctl is deprecated. Because proc is so awesome that you - * shouldn't _want_ to write portable code, I guess? */ - unsigned long long result=0; - int fd = -1; - char *s = NULL; - const char *cp; - size_t file_size=0; - if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0))) - return 0; - s = read_file_to_str_until_eof(fd, 65536, &file_size); - if (!s) - goto err; - cp = strstr(s, "MemTotal:"); - if (!cp) - goto err; - /* Use the system sscanf so that space will match a wider number of space */ - if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1) - goto err; - - close(fd); - tor_free(s); - return result * 1024; - - /* LCOV_EXCL_START Can't reach this unless proc is broken. */ - err: - tor_free(s); - close(fd); - return 0; - /* LCOV_EXCL_STOP */ -#elif defined (_WIN32) - /* Windows has MEMORYSTATUSEX; pretty straightforward. */ - MEMORYSTATUSEX ms; - memset(&ms, 0, sizeof(ms)); - ms.dwLength = sizeof(ms); - if (! GlobalMemoryStatusEx(&ms)) - return 0; - - return ms.ullTotalPhys; - -#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM) - /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better - * variant if we know about it. */ - uint64_t memsize = 0; - size_t len = sizeof(memsize); - int mib[2] = {CTL_HW, INT64_HW_MEM}; - if (sysctl(mib,2,&memsize,&len,NULL,0)) - return 0; - - return memsize; - -#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM) - /* On some systems (like FreeBSD I hope) you can use a size_t with - * HW_PHYSMEM. */ - size_t memsize=0; - size_t len = sizeof(memsize); - int mib[2] = {CTL_HW, HW_USERMEM}; - if (sysctl(mib,2,&memsize,&len,NULL,0)) - return 0; - - return memsize; - -#else - /* I have no clue. */ - return 0; -#endif /* defined(__linux__) || ... */ -} - -/** - * Try to find out how much physical memory the system has. On success, - * return 0 and set *<b>mem_out</b> to that value. On failure, return -1. - */ -MOCK_IMPL(int, -get_total_system_memory, (size_t *mem_out)) -{ - static size_t mem_cached=0; - uint64_t m = get_total_system_memory_impl(); - if (0 == m) { - /* LCOV_EXCL_START -- can't make this happen without mocking. */ - /* We couldn't find our memory total */ - if (0 == mem_cached) { - /* We have no cached value either */ - *mem_out = 0; - return -1; - } - - *mem_out = mem_cached; - return 0; - /* LCOV_EXCL_STOP */ - } - -#if SIZE_MAX != UINT64_MAX - if (m > SIZE_MAX) { - /* I think this could happen if we're a 32-bit Tor running on a 64-bit - * system: we could have more system memory than would fit in a - * size_t. */ - m = SIZE_MAX; - } -#endif /* SIZE_MAX != UINT64_MAX */ - - *mem_out = mem_cached = (size_t) m; - - return 0; -} - -/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b> - * bytes of passphrase into <b>output</b>. Return the number of bytes in - * the passphrase, excluding terminating NUL. - */ -ssize_t -tor_getpass(const char *prompt, char *output, size_t buflen) -{ - tor_assert(buflen <= SSIZE_MAX); - tor_assert(buflen >= 1); -#if defined(HAVE_READPASSPHRASE) - char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF); - if (pwd == NULL) - return -1; - return strlen(pwd); -#elif defined(_WIN32) - int r = -1; - while (*prompt) { - _putch(*prompt++); - } - - tor_assert(buflen <= INT_MAX); - wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t)); - - wchar_t *ptr = buf, *lastch = buf + buflen - 1; - while (ptr < lastch) { - wint_t ch = _getwch(); - switch (ch) { - case '\r': - case '\n': - case WEOF: - goto done_reading; - case 3: - goto done; /* Can't actually read ctrl-c this way. */ - case '\b': - if (ptr > buf) - --ptr; - continue; - case 0: - case 0xe0: - ch = _getwch(); /* Ignore; this is a function or arrow key */ - break; - default: - *ptr++ = ch; - break; - } - } - done_reading: - ; - -#ifndef WC_ERR_INVALID_CHARS -#define WC_ERR_INVALID_CHARS 0x80 -#endif - - /* Now convert it to UTF-8 */ - r = WideCharToMultiByte(CP_UTF8, - WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS, - buf, (int)(ptr-buf), - output, (int)(buflen-1), - NULL, NULL); - if (r <= 0) { - r = -1; - goto done; - } - - tor_assert(r < (int)buflen); - - output[r] = 0; - - done: - SecureZeroMemory(buf, sizeof(wchar_t)*buflen); - tor_free(buf); - return r; -#else -#error "No implementation for tor_getpass found!" -#endif /* defined(HAVE_READPASSPHRASE) || ... */ -} - -/** Return the amount of free disk space we have permission to use, in - * bytes. Return -1 if the amount of free space can't be determined. */ -int64_t -tor_get_avail_disk_space(const char *path) -{ -#ifdef HAVE_STATVFS - struct statvfs st; - int r; - memset(&st, 0, sizeof(st)); - - r = statvfs(path, &st); - if (r < 0) - return -1; - - int64_t result = st.f_bavail; - if (st.f_frsize) { - result *= st.f_frsize; - } else if (st.f_bsize) { - result *= st.f_bsize; - } else { - return -1; - } - - return result; -#elif defined(_WIN32) - ULARGE_INTEGER freeBytesAvail; - BOOL ok; - - ok = GetDiskFreeSpaceEx(path, &freeBytesAvail, NULL, NULL); - if (!ok) { - return -1; - } - return (int64_t)freeBytesAvail.QuadPart; -#else - (void)path; - errno = ENOSYS; - return -1; -#endif /* defined(HAVE_STATVFS) || ... */ -} - diff --git a/src/common/compat.h b/src/common/compat.h deleted file mode 100644 index c7e7f8d9ef..0000000000 --- a/src/common/compat.h +++ /dev/null @@ -1,757 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_COMPAT_H -#define TOR_COMPAT_H - -#include "orconfig.h" -#ifdef _WIN32 -#include <winsock2.h> -#include <ws2tcpip.h> -#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY -#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b -#endif -#endif -#include "torint.h" -#include "testsupport.h" -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif -#include <stdarg.h> -#ifdef HAVE_SYS_RESOURCE_H -#include <sys/resource.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_NETINET6_IN6_H -#include <netinet6/in6.h> -#endif - -#include "compat_time.h" - -#if defined(__has_feature) -# if __has_feature(address_sanitizer) -/* Some of the fancy glibc strcmp() macros include references to memory that - * clang rejects because it is off the end of a less-than-3. Clang hates this, - * even though those references never actually happen. */ -# undef strcmp -#endif /* __has_feature(address_sanitizer) */ -#endif /* defined(__has_feature) */ - -#include <stdio.h> -#include <errno.h> - -#ifndef NULL_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent NULL as zero. We can't cope." -#endif - -#ifndef DOUBLE_0_REP_IS_ZERO_BYTES -#error "It seems your platform does not represent 0.0 as zeros. We can't cope." -#endif - -#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32 -#error "It seems that you encode characters in something other than ASCII." -#endif - -/* ===== Compiler compatibility */ - -/* GCC can check printf and scanf types on arbitrary functions. */ -#ifdef __GNUC__ -#define CHECK_PRINTF(formatIdx, firstArg) \ - __attribute__ ((format(printf, formatIdx, firstArg))) -#else -#define CHECK_PRINTF(formatIdx, firstArg) -#endif /* defined(__GNUC__) */ -#ifdef __GNUC__ -#define CHECK_SCANF(formatIdx, firstArg) \ - __attribute__ ((format(scanf, formatIdx, firstArg))) -#else -#define CHECK_SCANF(formatIdx, firstArg) -#endif /* defined(__GNUC__) */ - -/* What GCC do we have? */ -#ifdef __GNUC__ -#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#else -#define GCC_VERSION 0 -#endif - -/* Temporarily enable and disable warnings. */ -#ifdef __GNUC__ -# define PRAGMA_STRINGIFY_(s) #s -# define PRAGMA_JOIN_STRINGIFY_(a,b) PRAGMA_STRINGIFY_(a ## b) -/* Support for macro-generated pragmas (c99) */ -# define PRAGMA_(x) _Pragma (#x) -# ifdef __clang__ -# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(clang diagnostic x) -# else -# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(GCC diagnostic x) -# endif -# if defined(__clang__) || GCC_VERSION >= 406 -/* we have push/pop support */ -# define DISABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(push) \ - PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -# define ENABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(pop) -#else /* !(defined(__clang__) || GCC_VERSION >= 406) */ -/* older version of gcc: no push/pop support. */ -# define DISABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -# define ENABLE_GCC_WARNING(warningopt) \ - PRAGMA_DIAGNOSTIC_(warning PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) -#endif /* defined(__clang__) || GCC_VERSION >= 406 */ -#else /* !(defined(__GNUC__)) */ -/* not gcc at all */ -# define DISABLE_GCC_WARNING(warning) -# define ENABLE_GCC_WARNING(warning) -#endif /* defined(__GNUC__) */ - -/* inline is __inline on windows. */ -#ifdef _WIN32 -#define inline __inline -#endif - -/* Try to get a reasonable __func__ substitute in place. */ -#if defined(_MSC_VER) - -#define __func__ __FUNCTION__ - -#else -/* For platforms where autoconf works, make sure __func__ is defined - * sanely. */ -#ifndef HAVE_MACRO__func__ -#ifdef HAVE_MACRO__FUNCTION__ -#define __func__ __FUNCTION__ -#elif HAVE_MACRO__FUNC__ -#define __func__ __FUNC__ -#else -#define __func__ "???" -#endif /* defined(HAVE_MACRO__FUNCTION__) || ... */ -#endif /* !defined(HAVE_MACRO__func__) */ -#endif /* defined(_MSC_VER) */ - -#define U64_TO_DBL(x) ((double) (x)) -#define DBL_TO_U64(x) ((uint64_t) (x)) - -#ifdef ENUM_VALS_ARE_SIGNED -#define ENUM_BF(t) unsigned -#else -/** Wrapper for having a bitfield of an enumerated type. Where possible, we - * just use the enumerated type (so the compiler can help us and notice - * problems), but if enumerated types are unsigned, we must use unsigned, - * so that the loss of precision doesn't make large values negative. */ -#define ENUM_BF(t) t -#endif /* defined(ENUM_VALS_ARE_SIGNED) */ - -/* GCC has several useful attributes. */ -#if defined(__GNUC__) && __GNUC__ >= 3 -#define ATTR_NORETURN __attribute__((noreturn)) -#define ATTR_CONST __attribute__((const)) -#define ATTR_MALLOC __attribute__((malloc)) -#define ATTR_NORETURN __attribute__((noreturn)) -#define ATTR_WUR __attribute__((warn_unused_result)) -/* Alas, nonnull is not at present a good idea for us. We'd like to get - * warnings when we pass NULL where we shouldn't (which nonnull does, albeit - * spottily), but we don't want to tell the compiler to make optimizations - * with the assumption that the argument can't be NULL (since this would make - * many of our checks go away, and make our code less robust against - * programming errors). Unfortunately, nonnull currently does both of these - * things, and there's no good way to split them up. - * - * #define ATTR_NONNULL(x) __attribute__((nonnull x)) */ -#define ATTR_NONNULL(x) -#define ATTR_UNUSED __attribute__ ((unused)) - -/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value - * of <b>exp</b> will probably be true. - * - * In other words, "if (PREDICT_LIKELY(foo))" is the same as "if (foo)", - * except that it tells the compiler that the branch will be taken most of the - * time. This can generate slightly better code with some CPUs. - */ -#define PREDICT_LIKELY(exp) __builtin_expect(!!(exp), 1) -/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value - * of <b>exp</b> will probably be false. - * - * In other words, "if (PREDICT_UNLIKELY(foo))" is the same as "if (foo)", - * except that it tells the compiler that the branch will usually not be - * taken. This can generate slightly better code with some CPUs. - */ -#define PREDICT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) -#else /* !(defined(__GNUC__) && __GNUC__ >= 3) */ -#define ATTR_NORETURN -#define ATTR_CONST -#define ATTR_MALLOC -#define ATTR_NORETURN -#define ATTR_NONNULL(x) -#define ATTR_UNUSED -#define ATTR_WUR -#define PREDICT_LIKELY(exp) (exp) -#define PREDICT_UNLIKELY(exp) (exp) -#endif /* defined(__GNUC__) && __GNUC__ >= 3 */ - -/** Expands to a syntactically valid empty statement. */ -#define STMT_NIL (void)0 - -/** Expands to a syntactically valid empty statement, explicitly (void)ing its - * argument. */ -#define STMT_VOID(a) while (0) { (void)(a); } - -#ifdef __GNUC__ -/** STMT_BEGIN and STMT_END are used to wrap blocks inside macros so that - * the macro can be used as if it were a single C statement. */ -#define STMT_BEGIN (void) ({ -#define STMT_END }) -#elif defined(sun) || defined(__sun__) -#define STMT_BEGIN if (1) { -#define STMT_END } else STMT_NIL -#else -#define STMT_BEGIN do { -#define STMT_END } while (0) -#endif /* defined(__GNUC__) || ... */ - -/* Some tools (like coccinelle) don't like to see operators as macro - * arguments. */ -#define OP_LT < -#define OP_GT > -#define OP_GE >= -#define OP_LE <= -#define OP_EQ == -#define OP_NE != - -/* ===== String compatibility */ -#ifdef _WIN32 -/* Windows names string functions differently from most other platforms. */ -#define strncasecmp _strnicmp -#define strcasecmp _stricmp -#endif - -#if defined __APPLE__ -/* On OSX 10.9 and later, the overlap-checking code for strlcat would - * appear to have a severe bug that can sometimes cause aborts in Tor. - * Instead, use the non-checking variants. This is sad. - * - * See https://trac.torproject.org/projects/tor/ticket/15205 - */ -#undef strlcat -#undef strlcpy -#endif /* defined __APPLE__ */ - -#ifndef HAVE_STRLCAT -size_t strlcat(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); -#endif -#ifndef HAVE_STRLCPY -size_t strlcpy(char *dst, const char *src, size_t siz) ATTR_NONNULL((1,2)); -#endif - -#ifdef _MSC_VER -/** Casts the uint64_t value in <b>a</b> to the right type for an argument - * to printf. */ -#define U64_PRINTF_ARG(a) (a) -/** Casts the uint64_t* value in <b>a</b> to the right type for an argument - * to scanf. */ -#define U64_SCANF_ARG(a) (a) -/** Expands to a literal uint64_t-typed constant for the value <b>n</b>. */ -#define U64_LITERAL(n) (n ## ui64) -#define I64_PRINTF_ARG(a) (a) -#define I64_SCANF_ARG(a) (a) -#define I64_LITERAL(n) (n ## i64) -#else /* !(defined(_MSC_VER)) */ -#define U64_PRINTF_ARG(a) ((long long unsigned int)(a)) -#define U64_SCANF_ARG(a) ((long long unsigned int*)(a)) -#define U64_LITERAL(n) (n ## llu) -#define I64_PRINTF_ARG(a) ((long long signed int)(a)) -#define I64_SCANF_ARG(a) ((long long signed int*)(a)) -#define I64_LITERAL(n) (n ## ll) -#endif /* defined(_MSC_VER) */ - -#if defined(__MINGW32__) || defined(__MINGW64__) -#define MINGW_ANY -#endif - -#if defined(_MSC_VER) || defined(MINGW_ANY) -/** The formatting string used to put a uint64_t value in a printf() or - * scanf() function. See also U64_PRINTF_ARG and U64_SCANF_ARG. */ -#define U64_FORMAT "%I64u" -#define I64_FORMAT "%I64d" -#else /* !(defined(_MSC_VER) || defined(MINGW_ANY)) */ -#define U64_FORMAT "%llu" -#define I64_FORMAT "%lld" -#endif /* defined(_MSC_VER) || defined(MINGW_ANY) */ - -#if (SIZEOF_INTPTR_T == SIZEOF_INT) -#define INTPTR_T_FORMAT "%d" -#define INTPTR_PRINTF_ARG(x) ((int)(x)) -#elif (SIZEOF_INTPTR_T == SIZEOF_LONG) -#define INTPTR_T_FORMAT "%ld" -#define INTPTR_PRINTF_ARG(x) ((long)(x)) -#elif (SIZEOF_INTPTR_T == 8) -#define INTPTR_T_FORMAT I64_FORMAT -#define INTPTR_PRINTF_ARG(x) I64_PRINTF_ARG(x) -#else -#error Unknown: SIZEOF_INTPTR_T -#endif /* (SIZEOF_INTPTR_T == SIZEOF_INT) || ... */ - -/** Represents an mmaped file. Allocated via tor_mmap_file; freed with - * tor_munmap_file. */ -typedef struct tor_mmap_t { - const char *data; /**< Mapping of the file's contents. */ - size_t size; /**< Size of the file. */ - - /* None of the fields below should be accessed from outside compat.c */ -#ifdef HAVE_MMAP - size_t mapping_size; /**< Size of the actual mapping. (This is this file - * size, rounded up to the nearest page.) */ -#elif defined _WIN32 - HANDLE mmap_handle; -#endif /* defined(HAVE_MMAP) || ... */ - -} tor_mmap_t; - -tor_mmap_t *tor_mmap_file(const char *filename) ATTR_NONNULL((1)); -int tor_munmap_file(tor_mmap_t *handle) ATTR_NONNULL((1)); - -int tor_snprintf(char *str, size_t size, const char *format, ...) - CHECK_PRINTF(3,4) ATTR_NONNULL((1,3)); -int tor_vsnprintf(char *str, size_t size, const char *format, va_list args) - CHECK_PRINTF(3,0) ATTR_NONNULL((1,3)); - -int tor_asprintf(char **strp, const char *fmt, ...) - CHECK_PRINTF(2,3); -int tor_vasprintf(char **strp, const char *fmt, va_list args) - CHECK_PRINTF(2,0); - -const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, - size_t nlen) ATTR_NONNULL((1,3)); -static const void *tor_memstr(const void *haystack, size_t hlen, - const char *needle) ATTR_NONNULL((1,3)); -static inline const void * -tor_memstr(const void *haystack, size_t hlen, const char *needle) -{ - return tor_memmem(haystack, hlen, needle, strlen(needle)); -} - -/* Much of the time when we're checking ctypes, we're doing spec compliance, - * which all assumes we're doing ASCII. */ -#define DECLARE_CTYPE_FN(name) \ - static int TOR_##name(char c); \ - extern const uint32_t TOR_##name##_TABLE[]; \ - static inline int TOR_##name(char c) { \ - uint8_t u = c; \ - return !!(TOR_##name##_TABLE[(u >> 5) & 7] & (1u << (u & 31))); \ - } -DECLARE_CTYPE_FN(ISALPHA) -DECLARE_CTYPE_FN(ISALNUM) -DECLARE_CTYPE_FN(ISSPACE) -DECLARE_CTYPE_FN(ISDIGIT) -DECLARE_CTYPE_FN(ISXDIGIT) -DECLARE_CTYPE_FN(ISPRINT) -DECLARE_CTYPE_FN(ISLOWER) -DECLARE_CTYPE_FN(ISUPPER) -extern const uint8_t TOR_TOUPPER_TABLE[]; -extern const uint8_t TOR_TOLOWER_TABLE[]; -#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c]) -#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c]) - -char *tor_strtok_r_impl(char *str, const char *sep, char **lasts); -#ifdef HAVE_STRTOK_R -#define tor_strtok_r(str, sep, lasts) strtok_r(str, sep, lasts) -#else -#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts) -#endif - -#ifdef _WIN32 -#define SHORT_FILE__ (tor_fix_source_file(__FILE__)) -const char *tor_fix_source_file(const char *fname); -#else -#define SHORT_FILE__ (__FILE__) -#define tor_fix_source_file(s) (s) -#endif /* defined(_WIN32) */ - -/* ===== Time compatibility */ - -struct tm *tor_localtime_r(const time_t *timep, struct tm *result); -struct tm *tor_gmtime_r(const time_t *timep, struct tm *result); - -#ifndef timeradd -/** Replacement for timeradd on platforms that do not have it: sets tvout to - * the sum of tv1 and tv2. */ -#define timeradd(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ - if ((tvout)->tv_usec >= 1000000) { \ - (tvout)->tv_usec -= 1000000; \ - (tvout)->tv_sec++; \ - } \ - } while (0) -#endif /* !defined(timeradd) */ - -#ifndef timersub -/** Replacement for timersub on platforms that do not have it: sets tvout to - * tv1 minus tv2. */ -#define timersub(tv1,tv2,tvout) \ - do { \ - (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ - (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ - if ((tvout)->tv_usec < 0) { \ - (tvout)->tv_usec += 1000000; \ - (tvout)->tv_sec--; \ - } \ - } while (0) -#endif /* !defined(timersub) */ - -#ifndef timercmp -/** Replacement for timercmp on platforms that do not have it: returns true - * iff the relational operator "op" makes the expression tv1 op tv2 true. - * - * Note that while this definition should work for all boolean operators, some - * platforms' native timercmp definitions do not support >=, <=, or ==. So - * don't use those. - */ -#define timercmp(tv1,tv2,op) \ - (((tv1)->tv_sec == (tv2)->tv_sec) ? \ - ((tv1)->tv_usec op (tv2)->tv_usec) : \ - ((tv1)->tv_sec op (tv2)->tv_sec)) -#endif /* !defined(timercmp) */ - -/* ===== File compatibility */ -int tor_open_cloexec(const char *path, int flags, unsigned mode); -FILE *tor_fopen_cloexec(const char *path, const char *mode); -int tor_rename(const char *path_old, const char *path_new); - -int replace_file(const char *from, const char *to); -int touch_file(const char *fname); - -typedef struct tor_lockfile_t tor_lockfile_t; -tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking, - int *locked_out); -void tor_lockfile_unlock(tor_lockfile_t *lockfile); - -off_t tor_fd_getpos(int fd); -int tor_fd_setpos(int fd, off_t pos); -int tor_fd_seekend(int fd); -int tor_ftruncate(int fd); - -int64_t tor_get_avail_disk_space(const char *path); - -#ifdef _WIN32 -#define PATH_SEPARATOR "\\" -#else -#define PATH_SEPARATOR "/" -#endif - -/* ===== Net compatibility */ - -#if (SIZEOF_SOCKLEN_T == 0) -typedef int socklen_t; -#endif - -#ifdef _WIN32 -/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that - * any inadvertent checks for the socket being <= 0 or > 0 will probably - * still work. */ -#define tor_socket_t intptr_t -#define TOR_SOCKET_T_FORMAT INTPTR_T_FORMAT -#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET) -#define TOR_INVALID_SOCKET INVALID_SOCKET -#else /* !(defined(_WIN32)) */ -/** Type used for a network socket. */ -#define tor_socket_t int -#define TOR_SOCKET_T_FORMAT "%d" -/** Macro: true iff 's' is a possible value for a valid initialized socket. */ -#define SOCKET_OK(s) ((s) >= 0) -/** Error/uninitialized value for a tor_socket_t. */ -#define TOR_INVALID_SOCKET (-1) -#endif /* defined(_WIN32) */ - -int tor_close_socket_simple(tor_socket_t s); -MOCK_DECL(int, tor_close_socket, (tor_socket_t s)); -void tor_take_socket_ownership(tor_socket_t s); -tor_socket_t tor_open_socket_with_extensions( - int domain, int type, int protocol, - int cloexec, int nonblock); -MOCK_DECL(tor_socket_t, -tor_open_socket,(int domain, int type, int protocol)); -tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol); -tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, - socklen_t *len); -tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd, - struct sockaddr *addr, - socklen_t *len); -tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd, - struct sockaddr *addr, - socklen_t *len, - int cloexec, int nonblock); -MOCK_DECL(tor_socket_t, -tor_connect_socket,(tor_socket_t socket,const struct sockaddr *address, - socklen_t address_len)); -int get_n_open_sockets(void); - -MOCK_DECL(int, -tor_getsockname,(tor_socket_t socket, struct sockaddr *address, - socklen_t *address_len)); -struct tor_addr_t; -int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock); - -#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags) -#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags) - -/** Implementation of struct in6_addr for platforms that do not have it. - * Generally, these platforms are ones without IPv6 support, but we want to - * have a working in6_addr there anyway, so we can use it to parse IPv6 - * addresses. */ -#if !defined(HAVE_STRUCT_IN6_ADDR) -struct in6_addr -{ - union { - uint8_t u6_addr8[16]; - uint16_t u6_addr16[8]; - uint32_t u6_addr32[4]; - } in6_u; -#define s6_addr in6_u.u6_addr8 -#define s6_addr16 in6_u.u6_addr16 -#define s6_addr32 in6_u.u6_addr32 -}; -#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */ - -/** @{ */ -/** Many BSD variants seem not to define these. */ -#if defined(__APPLE__) || defined(__darwin__) || \ - defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -#ifndef s6_addr16 -#define s6_addr16 __u6_addr.__u6_addr16 -#endif -#ifndef s6_addr32 -#define s6_addr32 __u6_addr.__u6_addr32 -#endif -#endif /* defined(__APPLE__) || defined(__darwin__) || ... */ -/** @} */ - -#ifndef HAVE_SA_FAMILY_T -typedef uint16_t sa_family_t; -#endif - -/** @{ */ -/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these - * macros get you a pointer to s6_addr32 or local equivalent. */ -#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32 -#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32) -#else -#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr)) -#endif -#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16 -#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16) -#else -#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr)) -#endif -/** @} */ - -/** Implementation of struct sockaddr_in6 on platforms that do not have - * it. See notes on struct in6_addr. */ -#if !defined(HAVE_STRUCT_SOCKADDR_IN6) -struct sockaddr_in6 { - sa_family_t sin6_family; - uint16_t sin6_port; - // uint32_t sin6_flowinfo; - struct in6_addr sin6_addr; - // uint32_t sin6_scope_id; -}; -#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */ - -MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen)); -int tor_inet_aton(const char *cp, struct in_addr *addr) ATTR_NONNULL((1,2)); -const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); -int tor_inet_pton(int af, const char *src, void *dst); -MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr)); -int set_socket_nonblocking(tor_socket_t socket); -int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]); -int network_init(void); - -/* For stupid historical reasons, windows sockets have an independent - * set of errnos, and an independent way to get them. Also, you can't - * always believe WSAEWOULDBLOCK. Use the macros below to compare - * errnos against expected values, and use tor_socket_errno to find - * the actual errno after a socket operation fails. - */ -#if defined(_WIN32) -/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */ -#define SOCK_ERRNO(e) WSA##e -/** Return true if e is EAGAIN or the local equivalent. */ -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK) -/** Return true if e is EINPROGRESS or the local equivalent. */ -#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS) -/** Return true if e is EINPROGRESS or the local equivalent as returned by - * a call to connect(). */ -#define ERRNO_IS_CONN_EINPROGRESS(e) \ - ((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK) -/** Return true if e is EAGAIN or another error indicating that a call to - * accept() has no pending connections to return. */ -#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e) -/** Return true if e is EMFILE or another error indicating that a call to - * accept() has failed because we're out of fds or something. */ -#define ERRNO_IS_RESOURCE_LIMIT(e) \ - ((e) == WSAEMFILE || (e) == WSAENOBUFS) -/** Return true if e is EADDRINUSE or the local equivalent. */ -#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE) -/** Return true if e is EINTR or the local equivalent */ -#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0) -int tor_socket_errno(tor_socket_t sock); -const char *tor_socket_strerror(int e); -#else /* !(defined(_WIN32)) */ -#define SOCK_ERRNO(e) e -#if EAGAIN == EWOULDBLOCK -/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */ -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0) -#else -#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) -#endif /* EAGAIN == EWOULDBLOCK */ -#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0) -#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0) -#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0) -#define ERRNO_IS_ACCEPT_EAGAIN(e) \ - (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED) -#define ERRNO_IS_RESOURCE_LIMIT(e) \ - ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM) -#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0) -#define tor_socket_errno(sock) (errno) -#define tor_socket_strerror(e) strerror(e) -#endif /* defined(_WIN32) */ - -/** Specified SOCKS5 status codes. */ -typedef enum { - SOCKS5_SUCCEEDED = 0x00, - SOCKS5_GENERAL_ERROR = 0x01, - SOCKS5_NOT_ALLOWED = 0x02, - SOCKS5_NET_UNREACHABLE = 0x03, - SOCKS5_HOST_UNREACHABLE = 0x04, - SOCKS5_CONNECTION_REFUSED = 0x05, - SOCKS5_TTL_EXPIRED = 0x06, - SOCKS5_COMMAND_NOT_SUPPORTED = 0x07, - SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08, -} socks5_reply_status_t; - -/* ===== OS compatibility */ -MOCK_DECL(const char *, get_uname, (void)); - -uint16_t get_uint16(const void *cp) ATTR_NONNULL((1)); -uint32_t get_uint32(const void *cp) ATTR_NONNULL((1)); -uint64_t get_uint64(const void *cp) ATTR_NONNULL((1)); -void set_uint16(void *cp, uint16_t v) ATTR_NONNULL((1)); -void set_uint32(void *cp, uint32_t v) ATTR_NONNULL((1)); -void set_uint64(void *cp, uint64_t v) ATTR_NONNULL((1)); - -/* These uint8 variants are defined to make the code more uniform. */ -#define get_uint8(cp) (*(const uint8_t*)(cp)) -static void set_uint8(void *cp, uint8_t v); -static inline void -set_uint8(void *cp, uint8_t v) -{ - *(uint8_t*)cp = v; -} - -#if !defined(HAVE_RLIM_T) -typedef unsigned long rlim_t; -#endif -int get_max_sockets(void); -int set_max_file_descriptors(rlim_t limit, int *max); -int tor_disable_debugger_attach(void); - -#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_SET_PROC) -#define HAVE_LINUX_CAPABILITIES -#endif - -int have_capability_support(void); - -/** Flag for switch_id; see switch_id() for documentation */ -#define SWITCH_ID_KEEP_BINDLOW (1<<0) -/** Flag for switch_id; see switch_id() for documentation */ -#define SWITCH_ID_WARN_IF_NO_CAPS (1<<1) -int switch_id(const char *user, unsigned flags); -#ifdef HAVE_PWD_H -char *get_user_homedir(const char *username); -#endif - -#ifndef _WIN32 -const struct passwd *tor_getpwnam(const char *username); -const struct passwd *tor_getpwuid(uid_t uid); -#endif - -int get_parent_directory(char *fname); -char *make_path_absolute(char *fname); - -char **get_environment(void); - -MOCK_DECL(int, get_total_system_memory, (size_t *mem_out)); - -int compute_num_cpus(void); - -int tor_mlockall(void); - -/** Macros for MIN/MAX. Never use these when the arguments could have - * side-effects. - * {With GCC extensions we could probably define a safer MIN/MAX. But - * depending on that safety would be dangerous, since not every platform - * has it.} - **/ -#ifndef MAX -#define MAX(a,b) ( ((a)<(b)) ? (b) : (a) ) -#endif -#ifndef MIN -#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) ) -#endif - -/* Platform-specific helpers. */ -#ifdef _WIN32 -char *format_win32_error(DWORD err); -#endif - -/*for some reason my compiler doesn't have these version flags defined - a nice homework assignment for someone one day is to define the rest*/ -//these are the values as given on MSDN -#ifdef _WIN32 - -#ifndef VER_SUITE_EMBEDDEDNT -#define VER_SUITE_EMBEDDEDNT 0x00000040 -#endif - -#ifndef VER_SUITE_SINGLEUSERTS -#define VER_SUITE_SINGLEUSERTS 0x00000100 -#endif - -#endif /* defined(_WIN32) */ - -#ifdef COMPAT_PRIVATE -#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS) -#define NEED_ERSATZ_SOCKETPAIR -STATIC int tor_ersatz_socketpair(int family, int type, int protocol, - tor_socket_t fd[2]); -#endif -#endif /* defined(COMPAT_PRIVATE) */ - -ssize_t tor_getpass(const char *prompt, char *output, size_t buflen); - -/* This needs some of the declarations above so we include it here. */ -#include "compat_threads.h" - -#endif /* !defined(TOR_COMPAT_H) */ - diff --git a/src/common/container.c b/src/common/container.c deleted file mode 100644 index 5386e6458b..0000000000 --- a/src/common/container.c +++ /dev/null @@ -1,1542 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file container.c - * \brief Implements a smartlist (a resizable array) along - * with helper functions to use smartlists. Also includes - * hash table implementations of a string-to-void* map, and of - * a digest-to-void* map. - **/ - -#include "compat.h" -#include "util.h" -#include "torlog.h" -#include "container.h" -#include "crypto_digest.h" - -#include <stdlib.h> -#include <string.h> -#include <assert.h> - -#include "ht.h" - -/** All newly allocated smartlists have this capacity. */ -#define SMARTLIST_DEFAULT_CAPACITY 16 - -/** Allocate and return an empty smartlist. - */ -MOCK_IMPL(smartlist_t *, -smartlist_new,(void)) -{ - smartlist_t *sl = tor_malloc(sizeof(smartlist_t)); - sl->num_used = 0; - sl->capacity = SMARTLIST_DEFAULT_CAPACITY; - sl->list = tor_calloc(sizeof(void *), sl->capacity); - return sl; -} - -/** Deallocate a smartlist. Does not release storage associated with the - * list's elements. - */ -MOCK_IMPL(void, -smartlist_free_,(smartlist_t *sl)) -{ - if (!sl) - return; - tor_free(sl->list); - tor_free(sl); -} - -/** Remove all elements from the list. - */ -void -smartlist_clear(smartlist_t *sl) -{ - memset(sl->list, 0, sizeof(void *) * sl->num_used); - sl->num_used = 0; -} - -#if SIZE_MAX < INT_MAX -#error "We don't support systems where size_t is smaller than int." -#endif - -/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */ -static inline void -smartlist_ensure_capacity(smartlist_t *sl, size_t size) -{ - /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */ -#if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX -#define MAX_CAPACITY (INT_MAX) -#else -#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*)))) -#endif - - tor_assert(size <= MAX_CAPACITY); - - if (size > (size_t) sl->capacity) { - size_t higher = (size_t) sl->capacity; - if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) { - higher = MAX_CAPACITY; - } else { - while (size > higher) - higher *= 2; - } - sl->list = tor_reallocarray(sl->list, sizeof(void *), - ((size_t)higher)); - memset(sl->list + sl->capacity, 0, - sizeof(void *) * (higher - sl->capacity)); - sl->capacity = (int) higher; - } -#undef ASSERT_CAPACITY -#undef MAX_CAPACITY -} - -/** Append element to the end of the list. */ -void -smartlist_add(smartlist_t *sl, void *element) -{ - smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); - sl->list[sl->num_used++] = element; -} - -/** Append each element from S2 to the end of S1. */ -void -smartlist_add_all(smartlist_t *s1, const smartlist_t *s2) -{ - size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used; - tor_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */ - smartlist_ensure_capacity(s1, new_size); - memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*)); - tor_assert(new_size <= INT_MAX); /* redundant. */ - s1->num_used = (int) new_size; -} - -/** Remove all elements E from sl such that E==element. Preserve - * the order of any elements before E, but elements after E can be - * rearranged. - */ -void -smartlist_remove(smartlist_t *sl, const void *element) -{ - int i; - if (element == NULL) - return; - for (i=0; i < sl->num_used; i++) - if (sl->list[i] == element) { - sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl->list[sl->num_used] = NULL; - } -} - -/** As <b>smartlist_remove</b>, but do not change the order of - * any elements not removed */ -void -smartlist_remove_keeporder(smartlist_t *sl, const void *element) -{ - int i, j, num_used_orig = sl->num_used; - if (element == NULL) - return; - - for (i=j=0; j < num_used_orig; ++j) { - if (sl->list[j] == element) { - --sl->num_used; - } else { - sl->list[i++] = sl->list[j]; - } - } -} - -/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise, - * return NULL. */ -void * -smartlist_pop_last(smartlist_t *sl) -{ - tor_assert(sl); - if (sl->num_used) { - void *tmp = sl->list[--sl->num_used]; - sl->list[sl->num_used] = NULL; - return tmp; - } else - return NULL; -} - -/** Reverse the order of the items in <b>sl</b>. */ -void -smartlist_reverse(smartlist_t *sl) -{ - int i, j; - void *tmp; - tor_assert(sl); - for (i = 0, j = sl->num_used-1; i < j; ++i, --j) { - tmp = sl->list[i]; - sl->list[i] = sl->list[j]; - sl->list[j] = tmp; - } -} - -/** If there are any strings in sl equal to element, remove and free them. - * Does not preserve order. */ -void -smartlist_string_remove(smartlist_t *sl, const char *element) -{ - int i; - tor_assert(sl); - tor_assert(element); - for (i = 0; i < sl->num_used; ++i) { - if (!strcmp(element, sl->list[i])) { - tor_free(sl->list[i]); - sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl->list[sl->num_used] = NULL; - } - } -} - -/** Return true iff some element E of sl has E==element. - */ -int -smartlist_contains(const smartlist_t *sl, const void *element) -{ - int i; - for (i=0; i < sl->num_used; i++) - if (sl->list[i] == element) - return 1; - return 0; -} - -/** Return true iff <b>sl</b> has some element E such that - * !strcmp(E,<b>element</b>) - */ -int -smartlist_contains_string(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (strcmp((const char*)sl->list[i],element)==0) - return 1; - return 0; -} - -/** If <b>element</b> is equal to an element of <b>sl</b>, return that - * element's index. Otherwise, return -1. */ -int -smartlist_string_pos(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return -1; - for (i=0; i < sl->num_used; i++) - if (strcmp((const char*)sl->list[i],element)==0) - return i; - return -1; -} - -/** If <b>element</b> is the same pointer as an element of <b>sl</b>, return - * that element's index. Otherwise, return -1. */ -int -smartlist_pos(const smartlist_t *sl, const void *element) -{ - int i; - if (!sl) return -1; - for (i=0; i < sl->num_used; i++) - if (element == sl->list[i]) - return i; - return -1; -} - -/** Return true iff <b>sl</b> has some element E such that - * !strcasecmp(E,<b>element</b>) - */ -int -smartlist_contains_string_case(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (strcasecmp((const char*)sl->list[i],element)==0) - return 1; - return 0; -} - -/** Return true iff <b>sl</b> has some element E such that E is equal - * to the decimal encoding of <b>num</b>. - */ -int -smartlist_contains_int_as_string(const smartlist_t *sl, int num) -{ - char buf[32]; /* long enough for 64-bit int, and then some. */ - tor_snprintf(buf,sizeof(buf),"%d", num); - return smartlist_contains_string(sl, buf); -} - -/** Return true iff the two lists contain the same strings in the same - * order, or if they are both NULL. */ -int -smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) -{ - if (sl1 == NULL) - return sl2 == NULL; - if (sl2 == NULL) - return 0; - if (smartlist_len(sl1) != smartlist_len(sl2)) - return 0; - SMARTLIST_FOREACH(sl1, const char *, cp1, { - const char *cp2 = smartlist_get(sl2, cp1_sl_idx); - if (strcmp(cp1, cp2)) - return 0; - }); - return 1; -} - -/** Return true iff the two lists contain the same int pointer values in - * the same order, or if they are both NULL. */ -int -smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) -{ - if (sl1 == NULL) - return sl2 == NULL; - if (sl2 == NULL) - return 0; - if (smartlist_len(sl1) != smartlist_len(sl2)) - return 0; - SMARTLIST_FOREACH(sl1, int *, cp1, { - int *cp2 = smartlist_get(sl2, cp1_sl_idx); - if (*cp1 != *cp2) - return 0; - }); - return 1; -} - -/** Return true iff <b>sl</b> has some element E such that - * tor_memeq(E,<b>element</b>,DIGEST_LEN) - */ -int -smartlist_contains_digest(const smartlist_t *sl, const char *element) -{ - int i; - if (!sl) return 0; - for (i=0; i < sl->num_used; i++) - if (tor_memeq((const char*)sl->list[i],element,DIGEST_LEN)) - return 1; - return 0; -} - -/** Return true iff some element E of sl2 has smartlist_contains(sl1,E). - */ -int -smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl2->num_used; i++) - if (smartlist_contains(sl1, sl2->list[i])) - return 1; - return 0; -} - -/** Remove every element E of sl1 such that !smartlist_contains(sl2,E). - * Does not preserve the order of sl1. - */ -void -smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl1->num_used; i++) - if (!smartlist_contains(sl2, sl1->list[i])) { - sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */ - i--; /* so we process the new i'th element */ - sl1->list[sl1->num_used] = NULL; - } -} - -/** Remove every element E of sl1 such that smartlist_contains(sl2,E). - * Does not preserve the order of sl1. - */ -void -smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) -{ - int i; - for (i=0; i < sl2->num_used; i++) - smartlist_remove(sl1, sl2->list[i]); -} - -/** Remove the <b>idx</b>th element of sl; if idx is not the last - * element, swap the last element of sl into the <b>idx</b>th space. - */ -void -smartlist_del(smartlist_t *sl, int idx) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx < sl->num_used); - sl->list[idx] = sl->list[--sl->num_used]; - sl->list[sl->num_used] = NULL; -} - -/** Remove the <b>idx</b>th element of sl; if idx is not the last element, - * moving all subsequent elements back one space. Return the old value - * of the <b>idx</b>th element. - */ -void -smartlist_del_keeporder(smartlist_t *sl, int idx) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx < sl->num_used); - --sl->num_used; - if (idx < sl->num_used) - memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); - sl->list[sl->num_used] = NULL; -} - -/** Insert the value <b>val</b> as the new <b>idx</b>th element of - * <b>sl</b>, moving all items previously at <b>idx</b> or later - * forward one space. - */ -void -smartlist_insert(smartlist_t *sl, int idx, void *val) -{ - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(idx <= sl->num_used); - if (idx == sl->num_used) { - smartlist_add(sl, val); - } else { - smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); - /* Move other elements away */ - if (idx < sl->num_used) - memmove(sl->list + idx + 1, sl->list + idx, - sizeof(void*)*(sl->num_used-idx)); - sl->num_used++; - sl->list[idx] = val; - } -} - -/** - * Split a string <b>str</b> along all occurrences of <b>sep</b>, - * appending the (newly allocated) split strings, in order, to - * <b>sl</b>. Return the number of strings added to <b>sl</b>. - * - * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and - * trailing space from each entry. - * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries - * of length 0. - * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each - * split string. - * - * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If - * <b>sep</b> is NULL, split on any sequence of horizontal space. - */ -int -smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, - int flags, int max) -{ - const char *cp, *end, *next; - int n = 0; - - tor_assert(sl); - tor_assert(str); - - cp = str; - while (1) { - if (flags&SPLIT_SKIP_SPACE) { - while (TOR_ISSPACE(*cp)) ++cp; - } - - if (max>0 && n == max-1) { - end = strchr(cp,'\0'); - } else if (sep) { - end = strstr(cp,sep); - if (!end) - end = strchr(cp,'\0'); - } else { - for (end = cp; *end && *end != '\t' && *end != ' '; ++end) - ; - } - - tor_assert(end); - - if (!*end) { - next = NULL; - } else if (sep) { - next = end+strlen(sep); - } else { - next = end+1; - while (*next == '\t' || *next == ' ') - ++next; - } - - if (flags&SPLIT_SKIP_SPACE) { - while (end > cp && TOR_ISSPACE(*(end-1))) - --end; - } - if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) { - char *string = tor_strndup(cp, end-cp); - if (flags&SPLIT_STRIP_SPACE) - tor_strstrip(string, " "); - smartlist_add(sl, string); - ++n; - } - if (!next) - break; - cp = next; - } - - return n; -} - -/** Allocate and return a new string containing the concatenation of - * the elements of <b>sl</b>, in order, separated by <b>join</b>. If - * <b>terminate</b> is true, also terminate the string with <b>join</b>. - * If <b>len_out</b> is not NULL, set <b>len_out</b> to the length of - * the returned string. Requires that every element of <b>sl</b> is - * NUL-terminated string. - */ -char * -smartlist_join_strings(smartlist_t *sl, const char *join, - int terminate, size_t *len_out) -{ - return smartlist_join_strings2(sl,join,strlen(join),terminate,len_out); -} - -/** As smartlist_join_strings, but instead of separating/terminated with a - * NUL-terminated string <b>join</b>, uses the <b>join_len</b>-byte sequence - * at <b>join</b>. (Useful for generating a sequence of NUL-terminated - * strings.) - */ -char * -smartlist_join_strings2(smartlist_t *sl, const char *join, - size_t join_len, int terminate, size_t *len_out) -{ - int i; - size_t n = 0; - char *r = NULL, *dst, *src; - - tor_assert(sl); - tor_assert(join); - - if (terminate) - n = join_len; - - for (i = 0; i < sl->num_used; ++i) { - n += strlen(sl->list[i]); - if (i+1 < sl->num_used) /* avoid double-counting the last one */ - n += join_len; - } - dst = r = tor_malloc(n+1); - for (i = 0; i < sl->num_used; ) { - for (src = sl->list[i]; *src; ) - *dst++ = *src++; - if (++i < sl->num_used) { - memcpy(dst, join, join_len); - dst += join_len; - } - } - if (terminate) { - memcpy(dst, join, join_len); - dst += join_len; - } - *dst = '\0'; - - if (len_out) - *len_out = dst-r; - return r; -} - -/** Sort the members of <b>sl</b> into an order defined by - * the ordering function <b>compare</b>, which returns less then 0 if a - * precedes b, greater than 0 if b precedes a, and 0 if a 'equals' b. - */ -void -smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)) -{ - if (!sl->num_used) - return; - qsort(sl->list, sl->num_used, sizeof(void*), - (int (*)(const void *,const void*))compare); -} - -/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>, - * return the most frequent member in the list. Break ties in favor of - * later elements. If the list is empty, return NULL. If count_out is - * non-null, set it to the count of the most frequent member. - */ -void * -smartlist_get_most_frequent_(const smartlist_t *sl, - int (*compare)(const void **a, const void **b), - int *count_out) -{ - const void *most_frequent = NULL; - int most_frequent_count = 0; - - const void *cur = NULL; - int i, count=0; - - if (!sl->num_used) { - if (count_out) - *count_out = 0; - return NULL; - } - for (i = 0; i < sl->num_used; ++i) { - const void *item = sl->list[i]; - if (cur && 0 == compare(&cur, &item)) { - ++count; - } else { - if (cur && count >= most_frequent_count) { - most_frequent = cur; - most_frequent_count = count; - } - cur = item; - count = 1; - } - } - if (cur && count >= most_frequent_count) { - most_frequent = cur; - most_frequent_count = count; - } - if (count_out) - *count_out = most_frequent_count; - return (void*)most_frequent; -} - -/** Given a sorted smartlist <b>sl</b> and the comparison function used to - * sort it, remove all duplicate members. If free_fn is provided, calls - * free_fn on each duplicate. Otherwise, just removes them. Preserves order. - */ -void -smartlist_uniq(smartlist_t *sl, - int (*compare)(const void **a, const void **b), - void (*free_fn)(void *a)) -{ - int i; - for (i=1; i < sl->num_used; ++i) { - if (compare((const void **)&(sl->list[i-1]), - (const void **)&(sl->list[i])) == 0) { - if (free_fn) - free_fn(sl->list[i]); - smartlist_del_keeporder(sl, i--); - } - } -} - -/** Assuming the members of <b>sl</b> are in order, return a pointer to the - * member that matches <b>key</b>. Ordering and matching are defined by a - * <b>compare</b> function that returns 0 on a match; less than 0 if key is - * less than member, and greater than 0 if key is greater then member. - */ -void * -smartlist_bsearch(smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member)) -{ - int found, idx; - idx = smartlist_bsearch_idx(sl, key, compare, &found); - return found ? smartlist_get(sl, idx) : NULL; -} - -/** Assuming the members of <b>sl</b> are in order, return the index of the - * member that matches <b>key</b>. If no member matches, return the index of - * the first member greater than <b>key</b>, or smartlist_len(sl) if no member - * is greater than <b>key</b>. Set <b>found_out</b> to true on a match, to - * false otherwise. Ordering and matching are defined by a <b>compare</b> - * function that returns 0 on a match; less than 0 if key is less than member, - * and greater than 0 if key is greater then member. - */ -int -smartlist_bsearch_idx(const smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member), - int *found_out) -{ - int hi, lo, cmp, mid, len, diff; - - tor_assert(sl); - tor_assert(compare); - tor_assert(found_out); - - len = smartlist_len(sl); - - /* Check for the trivial case of a zero-length list */ - if (len == 0) { - *found_out = 0; - /* We already know smartlist_len(sl) is 0 in this case */ - return 0; - } - - /* Okay, we have a real search to do */ - tor_assert(len > 0); - lo = 0; - hi = len - 1; - - /* - * These invariants are always true: - * - * For all i such that 0 <= i < lo, sl[i] < key - * For all i such that hi < i <= len, sl[i] > key - */ - - while (lo <= hi) { - diff = hi - lo; - /* - * We want mid = (lo + hi) / 2, but that could lead to overflow, so - * instead diff = hi - lo (non-negative because of loop condition), and - * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2). - */ - mid = lo + (diff / 2); - cmp = compare(key, (const void**) &(sl->list[mid])); - if (cmp == 0) { - /* sl[mid] == key; we found it */ - *found_out = 1; - return mid; - } else if (cmp > 0) { - /* - * key > sl[mid] and an index i such that sl[i] == key must - * have i > mid if it exists. - */ - - /* - * Since lo <= mid <= hi, hi can only decrease on each iteration (by - * being set to mid - 1) and hi is initially len - 1, mid < len should - * always hold, and this is not symmetric with the left end of list - * mid > 0 test below. A key greater than the right end of the list - * should eventually lead to lo == hi == mid == len - 1, and then - * we set lo to len below and fall out to the same exit we hit for - * a key in the middle of the list but not matching. Thus, we just - * assert for consistency here rather than handle a mid == len case. - */ - tor_assert(mid < len); - /* Move lo to the element immediately after sl[mid] */ - lo = mid + 1; - } else { - /* This should always be true in this case */ - tor_assert(cmp < 0); - - /* - * key < sl[mid] and an index i such that sl[i] == key must - * have i < mid if it exists. - */ - - if (mid > 0) { - /* Normal case, move hi to the element immediately before sl[mid] */ - hi = mid - 1; - } else { - /* These should always be true in this case */ - tor_assert(mid == lo); - tor_assert(mid == 0); - /* - * We were at the beginning of the list and concluded that every - * element e compares e > key. - */ - *found_out = 0; - return 0; - } - } - } - - /* - * lo > hi; we have no element matching key but we have elements falling - * on both sides of it. The lo index points to the first element > key. - */ - tor_assert(lo == hi + 1); /* All other cases should have been handled */ - tor_assert(lo >= 0); - tor_assert(lo <= len); - tor_assert(hi >= 0); - tor_assert(hi <= len); - - if (lo < len) { - cmp = compare(key, (const void **) &(sl->list[lo])); - tor_assert(cmp < 0); - } else { - cmp = compare(key, (const void **) &(sl->list[len-1])); - tor_assert(cmp > 0); - } - - *found_out = 0; - return lo; -} - -/** Helper: compare two const char **s. */ -static int -compare_string_ptrs_(const void **_a, const void **_b) -{ - return strcmp((const char*)*_a, (const char*)*_b); -} - -/** Sort a smartlist <b>sl</b> containing strings into lexically ascending - * order. */ -void -smartlist_sort_strings(smartlist_t *sl) -{ - smartlist_sort(sl, compare_string_ptrs_); -} - -/** Return the most frequent string in the sorted list <b>sl</b> */ -const char * -smartlist_get_most_frequent_string(smartlist_t *sl) -{ - return smartlist_get_most_frequent(sl, compare_string_ptrs_); -} - -/** Return the most frequent string in the sorted list <b>sl</b>. - * If <b>count_out</b> is provided, set <b>count_out</b> to the - * number of times that string appears. - */ -const char * -smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) -{ - return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out); -} - -/** Remove duplicate strings from a sorted list, and free them with tor_free(). - */ -void -smartlist_uniq_strings(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_string_ptrs_, tor_free_); -} - -/** Helper: compare two pointers. */ -static int -compare_ptrs_(const void **_a, const void **_b) -{ - const void *a = *_a, *b = *_b; - if (a<b) - return -1; - else if (a==b) - return 0; - else - return 1; -} - -/** Sort <b>sl</b> in ascending order of the pointers it contains. */ -void -smartlist_sort_pointers(smartlist_t *sl) -{ - smartlist_sort(sl, compare_ptrs_); -} - -/* Heap-based priority queue implementation for O(lg N) insert and remove. - * Recall that the heap property is that, for every index I, h[I] < - * H[LEFT_CHILD[I]] and h[I] < H[RIGHT_CHILD[I]]. - * - * For us to remove items other than the topmost item, each item must store - * its own index within the heap. When calling the pqueue functions, tell - * them about the offset of the field that stores the index within the item. - * - * Example: - * - * typedef struct timer_t { - * struct timeval tv; - * int heap_index; - * } timer_t; - * - * static int compare(const void *p1, const void *p2) { - * const timer_t *t1 = p1, *t2 = p2; - * if (t1->tv.tv_sec < t2->tv.tv_sec) { - * return -1; - * } else if (t1->tv.tv_sec > t2->tv.tv_sec) { - * return 1; - * } else { - * return t1->tv.tv_usec - t2->tv_usec; - * } - * } - * - * void timer_heap_insert(smartlist_t *heap, timer_t *timer) { - * smartlist_pqueue_add(heap, compare, offsetof(timer_t, heap_index), - * timer); - * } - * - * void timer_heap_pop(smartlist_t *heap) { - * return smartlist_pqueue_pop(heap, compare, - * offsetof(timer_t, heap_index)); - * } - */ - -/** @{ */ -/** Functions to manipulate heap indices to find a node's parent and children. - * - * For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x] - * = 2*x + 1. But this is C, so we have to adjust a little. */ - -/* MAX_PARENT_IDX is the largest IDX in the smartlist which might have - * children whose indices fit inside an int. - * LEFT_CHILD(MAX_PARENT_IDX) == INT_MAX-2; - * RIGHT_CHILD(MAX_PARENT_IDX) == INT_MAX-1; - * LEFT_CHILD(MAX_PARENT_IDX + 1) == INT_MAX // impossible, see max list size. - */ -#define MAX_PARENT_IDX ((INT_MAX - 2) / 2) -/* If this is true, then i is small enough to potentially have children - * in the smartlist, and it is save to use LEFT_CHILD/RIGHT_CHILD on it. */ -#define IDX_MAY_HAVE_CHILDREN(i) ((i) <= MAX_PARENT_IDX) -#define LEFT_CHILD(i) ( 2*(i) + 1 ) -#define RIGHT_CHILD(i) ( 2*(i) + 2 ) -#define PARENT(i) ( ((i)-1) / 2 ) -/** }@ */ - -/** @{ */ -/** Helper macros for heaps: Given a local variable <b>idx_field_offset</b> - * set to the offset of an integer index within the heap element structure, - * IDX_OF_ITEM(p) gives you the index of p, and IDXP(p) gives you a pointer to - * where p's index is stored. Given additionally a local smartlist <b>sl</b>, - * UPDATE_IDX(i) sets the index of the element at <b>i</b> to the correct - * value (that is, to <b>i</b>). - */ -#define IDXP(p) ((int*)STRUCT_VAR_P(p, idx_field_offset)) - -#define UPDATE_IDX(i) do { \ - void *updated = sl->list[i]; \ - *IDXP(updated) = i; \ - } while (0) - -#define IDX_OF_ITEM(p) (*IDXP(p)) -/** @} */ - -/** Helper. <b>sl</b> may have at most one violation of the heap property: - * the item at <b>idx</b> may be greater than one or both of its children. - * Restore the heap property. */ -static inline void -smartlist_heapify(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - int idx) -{ - while (1) { - if (! IDX_MAY_HAVE_CHILDREN(idx)) { - /* idx is so large that it cannot have any children, since doing so - * would mean the smartlist was over-capacity. Therefore it cannot - * violate the heap property by being greater than a child (since it - * doesn't have any). */ - return; - } - - int left_idx = LEFT_CHILD(idx); - int best_idx; - - if (left_idx >= sl->num_used) - return; - if (compare(sl->list[idx],sl->list[left_idx]) < 0) - best_idx = idx; - else - best_idx = left_idx; - if (left_idx+1 < sl->num_used && - compare(sl->list[left_idx+1],sl->list[best_idx]) < 0) - best_idx = left_idx + 1; - - if (best_idx == idx) { - return; - } else { - void *tmp = sl->list[idx]; - sl->list[idx] = sl->list[best_idx]; - sl->list[best_idx] = tmp; - UPDATE_IDX(idx); - UPDATE_IDX(best_idx); - - idx = best_idx; - } - } -} - -/** Insert <b>item</b> into the heap stored in <b>sl</b>, where order is - * determined by <b>compare</b> and the offset of the item in the heap is - * stored in an int-typed field at position <b>idx_field_offset</b> within - * item. - */ -void -smartlist_pqueue_add(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item) -{ - int idx; - smartlist_add(sl,item); - UPDATE_IDX(sl->num_used-1); - - for (idx = sl->num_used - 1; idx; ) { - int parent = PARENT(idx); - if (compare(sl->list[idx], sl->list[parent]) < 0) { - void *tmp = sl->list[parent]; - sl->list[parent] = sl->list[idx]; - sl->list[idx] = tmp; - UPDATE_IDX(parent); - UPDATE_IDX(idx); - idx = parent; - } else { - return; - } - } -} - -/** Remove and return the top-priority item from the heap stored in <b>sl</b>, - * where order is determined by <b>compare</b> and the item's position is - * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must - * not be empty. */ -void * -smartlist_pqueue_pop(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset) -{ - void *top; - tor_assert(sl->num_used); - - top = sl->list[0]; - *IDXP(top)=-1; - if (--sl->num_used) { - sl->list[0] = sl->list[sl->num_used]; - sl->list[sl->num_used] = NULL; - UPDATE_IDX(0); - smartlist_heapify(sl, compare, idx_field_offset, 0); - } - sl->list[sl->num_used] = NULL; - return top; -} - -/** Remove the item <b>item</b> from the heap stored in <b>sl</b>, - * where order is determined by <b>compare</b> and the item's position is - * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must - * not be empty. */ -void -smartlist_pqueue_remove(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item) -{ - int idx = IDX_OF_ITEM(item); - tor_assert(idx >= 0); - tor_assert(sl->list[idx] == item); - --sl->num_used; - *IDXP(item) = -1; - if (idx == sl->num_used) { - sl->list[sl->num_used] = NULL; - return; - } else { - sl->list[idx] = sl->list[sl->num_used]; - sl->list[sl->num_used] = NULL; - UPDATE_IDX(idx); - smartlist_heapify(sl, compare, idx_field_offset, idx); - } -} - -/** Assert that the heap property is correctly maintained by the heap stored - * in <b>sl</b>, where order is determined by <b>compare</b>. */ -void -smartlist_pqueue_assert_ok(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset) -{ - int i; - for (i = sl->num_used - 1; i >= 0; --i) { - if (i>0) - tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0); - tor_assert(IDX_OF_ITEM(sl->list[i]) == i); - } -} - -/** Helper: compare two DIGEST_LEN digests. */ -static int -compare_digests_(const void **_a, const void **_b) -{ - return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN); -} - -/** Sort the list of DIGEST_LEN-byte digests into ascending order. */ -void -smartlist_sort_digests(smartlist_t *sl) -{ - smartlist_sort(sl, compare_digests_); -} - -/** Remove duplicate digests from a sorted list, and free them with tor_free(). - */ -void -smartlist_uniq_digests(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_digests_, tor_free_); -} - -/** Helper: compare two DIGEST256_LEN digests. */ -static int -compare_digests256_(const void **_a, const void **_b) -{ - return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN); -} - -/** Sort the list of DIGEST256_LEN-byte digests into ascending order. */ -void -smartlist_sort_digests256(smartlist_t *sl) -{ - smartlist_sort(sl, compare_digests256_); -} - -/** Return the most frequent member of the sorted list of DIGEST256_LEN - * digests in <b>sl</b> */ -const uint8_t * -smartlist_get_most_frequent_digest256(smartlist_t *sl) -{ - return smartlist_get_most_frequent(sl, compare_digests256_); -} - -/** Remove duplicate 256-bit digests from a sorted list, and free them with - * tor_free(). - */ -void -smartlist_uniq_digests256(smartlist_t *sl) -{ - smartlist_uniq(sl, compare_digests256_, tor_free_); -} - -/** Helper: Declare an entry type and a map type to implement a mapping using - * ht.h. The map type will be called <b>maptype</b>. The key part of each - * entry is declared using the C declaration <b>keydecl</b>. All functions - * and types associated with the map get prefixed with <b>prefix</b> */ -#define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \ - typedef struct prefix ## entry_t { \ - HT_ENTRY(prefix ## entry_t) node; \ - void *val; \ - keydecl; \ - } prefix ## entry_t; \ - struct maptype { \ - HT_HEAD(prefix ## impl, prefix ## entry_t) head; \ - } - -DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_); -DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_); -DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_); - -/** Helper: compare strmap_entry_t objects by key value. */ -static inline int -strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b) -{ - return !strcmp(a->key, b->key); -} - -/** Helper: return a hash value for a strmap_entry_t. */ -static inline unsigned int -strmap_entry_hash(const strmap_entry_t *a) -{ - return (unsigned) siphash24g(a->key, strlen(a->key)); -} - -/** Helper: compare digestmap_entry_t objects by key value. */ -static inline int -digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b) -{ - return tor_memeq(a->key, b->key, DIGEST_LEN); -} - -/** Helper: return a hash value for a digest_map_t. */ -static inline unsigned int -digestmap_entry_hash(const digestmap_entry_t *a) -{ - return (unsigned) siphash24g(a->key, DIGEST_LEN); -} - -/** Helper: compare digestmap_entry_t objects by key value. */ -static inline int -digest256map_entries_eq(const digest256map_entry_t *a, - const digest256map_entry_t *b) -{ - return tor_memeq(a->key, b->key, DIGEST256_LEN); -} - -/** Helper: return a hash value for a digest_map_t. */ -static inline unsigned int -digest256map_entry_hash(const digest256map_entry_t *a) -{ - return (unsigned) siphash24g(a->key, DIGEST256_LEN); -} - -HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq) -HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash, - strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq) -HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, - digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node, - digest256map_entry_hash, - digest256map_entries_eq) -HT_GENERATE2(digest256map_impl, digest256map_entry_t, node, - digest256map_entry_hash, - digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_) - -#define strmap_entry_free(ent) \ - FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent)) -#define digestmap_entry_free(ent) \ - FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent)) -#define digest256map_entry_free(ent) \ - FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent)) - -static inline void -strmap_entry_free_(strmap_entry_t *ent) -{ - tor_free(ent->key); - tor_free(ent); -} -static inline void -digestmap_entry_free_(digestmap_entry_t *ent) -{ - tor_free(ent); -} -static inline void -digest256map_entry_free_(digest256map_entry_t *ent) -{ - tor_free(ent); -} - -static inline void -strmap_assign_tmp_key(strmap_entry_t *ent, const char *key) -{ - ent->key = (char*)key; -} -static inline void -digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key) -{ - memcpy(ent->key, key, DIGEST_LEN); -} -static inline void -digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key) -{ - memcpy(ent->key, key, DIGEST256_LEN); -} -static inline void -strmap_assign_key(strmap_entry_t *ent, const char *key) -{ - ent->key = tor_strdup(key); -} -static inline void -digestmap_assign_key(digestmap_entry_t *ent, const char *key) -{ - memcpy(ent->key, key, DIGEST_LEN); -} -static inline void -digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key) -{ - memcpy(ent->key, key, DIGEST256_LEN); -} - -/** - * Macro: implement all the functions for a map that are declared in - * container.h by the DECLARE_MAP_FNS() macro. You must additionally define a - * prefix_entry_free_() function to free entries (and their keys), a - * prefix_assign_tmp_key() function to temporarily set a stack-allocated - * entry to hold a key, and a prefix_assign_key() function to set a - * heap-allocated entry to hold a key. - */ -#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \ - /** Create and return a new empty map. */ \ - MOCK_IMPL(maptype *, \ - prefix##_new,(void)) \ - { \ - maptype *result; \ - result = tor_malloc(sizeof(maptype)); \ - HT_INIT(prefix##_impl, &result->head); \ - return result; \ - } \ - \ - /** Return the item from <b>map</b> whose key matches <b>key</b>, or \ - * NULL if no such value exists. */ \ - void * \ - prefix##_get(const maptype *map, const keytype key) \ - { \ - prefix ##_entry_t *resolve; \ - prefix ##_entry_t search; \ - tor_assert(map); \ - tor_assert(key); \ - prefix ##_assign_tmp_key(&search, key); \ - resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ - if (resolve) { \ - return resolve->val; \ - } else { \ - return NULL; \ - } \ - } \ - \ - /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \ - * return the previous value, or NULL if no such value existed. */ \ - void * \ - prefix##_set(maptype *map, const keytype key, void *val) \ - { \ - prefix##_entry_t search; \ - void *oldval; \ - tor_assert(map); \ - tor_assert(key); \ - tor_assert(val); \ - prefix##_assign_tmp_key(&search, key); \ - /* We a lot of our time in this function, so the code below is */ \ - /* meant to optimize the check/alloc/set cycle by avoiding the two */\ - /* trips to the hash table that we would do in the unoptimized */ \ - /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ - /* HT_SET_HASH and HT_FIND_P.) */ \ - HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ - &(map->head), \ - prefix##_entry_t, &search, ptr, \ - { \ - /* we found an entry. */ \ - oldval = (*ptr)->val; \ - (*ptr)->val = val; \ - return oldval; \ - }, \ - { \ - /* We didn't find the entry. */ \ - prefix##_entry_t *newent = \ - tor_malloc_zero(sizeof(prefix##_entry_t)); \ - prefix##_assign_key(newent, key); \ - newent->val = val; \ - HT_FOI_INSERT_(node, &(map->head), \ - &search, newent, ptr); \ - return NULL; \ - }); \ - } \ - \ - /** Remove the value currently associated with <b>key</b> from the map. \ - * Return the value if one was set, or NULL if there was no entry for \ - * <b>key</b>. \ - * \ - * Note: you must free any storage associated with the returned value. \ - */ \ - void * \ - prefix##_remove(maptype *map, const keytype key) \ - { \ - prefix##_entry_t *resolve; \ - prefix##_entry_t search; \ - void *oldval; \ - tor_assert(map); \ - tor_assert(key); \ - prefix##_assign_tmp_key(&search, key); \ - resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \ - if (resolve) { \ - oldval = resolve->val; \ - prefix##_entry_free(resolve); \ - return oldval; \ - } else { \ - return NULL; \ - } \ - } \ - \ - /** Return the number of elements in <b>map</b>. */ \ - int \ - prefix##_size(const maptype *map) \ - { \ - return HT_SIZE(&map->head); \ - } \ - \ - /** Return true iff <b>map</b> has no entries. */ \ - int \ - prefix##_isempty(const maptype *map) \ - { \ - return HT_EMPTY(&map->head); \ - } \ - \ - /** Assert that <b>map</b> is not corrupt. */ \ - void \ - prefix##_assert_ok(const maptype *map) \ - { \ - tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \ - } \ - \ - /** Remove all entries from <b>map</b>, and deallocate storage for \ - * those entries. If free_val is provided, invoked it every value in \ - * <b>map</b>. */ \ - MOCK_IMPL(void, \ - prefix##_free_, (maptype *map, void (*free_val)(void*))) \ - { \ - prefix##_entry_t **ent, **next, *this; \ - if (!map) \ - return; \ - for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ - ent = next) { \ - this = *ent; \ - next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ - if (free_val) \ - free_val(this->val); \ - prefix##_entry_free(this); \ - } \ - tor_assert(HT_EMPTY(&map->head)); \ - HT_CLEAR(prefix##_impl, &map->head); \ - tor_free(map); \ - } \ - \ - /** return an <b>iterator</b> pointer to the front of a map. \ - * \ - * Iterator example: \ - * \ - * \code \ - * // uppercase values in "map", removing empty values. \ - * \ - * strmap_iter_t *iter; \ - * const char *key; \ - * void *val; \ - * char *cp; \ - * \ - * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \ - * strmap_iter_get(iter, &key, &val); \ - * cp = (char*)val; \ - * if (!*cp) { \ - * iter = strmap_iter_next_rmv(map,iter); \ - * free(val); \ - * } else { \ - * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \ - */ \ - prefix##_iter_t * \ - prefix##_iter_init(maptype *map) \ - { \ - tor_assert(map); \ - return HT_START(prefix##_impl, &map->head); \ - } \ - \ - /** Advance <b>iter</b> a single step to the next entry, and return \ - * its new value. */ \ - prefix##_iter_t * \ - prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \ - { \ - tor_assert(map); \ - tor_assert(iter); \ - return HT_NEXT(prefix##_impl, &map->head, iter); \ - } \ - /** Advance <b>iter</b> a single step to the next entry, removing the \ - * current entry, and return its new value. */ \ - prefix##_iter_t * \ - prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \ - { \ - prefix##_entry_t *rmv; \ - tor_assert(map); \ - tor_assert(iter); \ - tor_assert(*iter); \ - rmv = *iter; \ - iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \ - prefix##_entry_free(rmv); \ - return iter; \ - } \ - /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \ - * to by iter. */ \ - void \ - prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \ - void **valp) \ - { \ - tor_assert(iter); \ - tor_assert(*iter); \ - tor_assert(keyp); \ - tor_assert(valp); \ - *keyp = (*iter)->key; \ - *valp = (*iter)->val; \ - } \ - /** Return true iff <b>iter</b> has advanced past the last entry of \ - * <b>map</b>. */ \ - int \ - prefix##_iter_done(prefix##_iter_t *iter) \ - { \ - return iter == NULL; \ - } - -IMPLEMENT_MAP_FNS(strmap_t, char *, strmap) -IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap) -IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map) - -/** Same as strmap_set, but first converts <b>key</b> to lowercase. */ -void * -strmap_set_lc(strmap_t *map, const char *key, void *val) -{ - /* We could be a little faster by using strcasecmp instead, and a separate - * type, but I don't think it matters. */ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_set(map,lc_key,val); - tor_free(lc_key); - return v; -} - -/** Same as strmap_get, but first converts <b>key</b> to lowercase. */ -void * -strmap_get_lc(const strmap_t *map, const char *key) -{ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_get(map,lc_key); - tor_free(lc_key); - return v; -} - -/** Same as strmap_remove, but first converts <b>key</b> to lowercase */ -void * -strmap_remove_lc(strmap_t *map, const char *key) -{ - void *v; - char *lc_key = tor_strdup(key); - tor_strlower(lc_key); - v = strmap_remove(map,lc_key); - tor_free(lc_key); - return v; -} - -/** Declare a function called <b>funcname</b> that acts as a find_nth_FOO - * function for an array of type <b>elt_t</b>*. - * - * NOTE: The implementation kind of sucks: It's O(n log n), whereas finding - * the kth element of an n-element list can be done in O(n). Then again, this - * implementation is not in critical path, and it is obviously correct. */ -#define IMPLEMENT_ORDER_FUNC(funcname, elt_t) \ - static int \ - _cmp_ ## elt_t(const void *_a, const void *_b) \ - { \ - const elt_t *a = _a, *b = _b; \ - if (*a<*b) \ - return -1; \ - else if (*a>*b) \ - return 1; \ - else \ - return 0; \ - } \ - elt_t \ - funcname(elt_t *array, int n_elements, int nth) \ - { \ - tor_assert(nth >= 0); \ - tor_assert(nth < n_elements); \ - qsort(array, n_elements, sizeof(elt_t), _cmp_ ##elt_t); \ - return array[nth]; \ - } - -IMPLEMENT_ORDER_FUNC(find_nth_int, int) -IMPLEMENT_ORDER_FUNC(find_nth_time, time_t) -IMPLEMENT_ORDER_FUNC(find_nth_double, double) -IMPLEMENT_ORDER_FUNC(find_nth_uint32, uint32_t) -IMPLEMENT_ORDER_FUNC(find_nth_int32, int32_t) -IMPLEMENT_ORDER_FUNC(find_nth_long, long) - -/** Return a newly allocated digestset_t, optimized to hold a total of - * <b>max_elements</b> digests with a reasonably low false positive weight. */ -digestset_t * -digestset_new(int max_elements) -{ - /* The probability of false positives is about P=(1 - exp(-kn/m))^k, where k - * is the number of hash functions per entry, m is the bits in the array, - * and n is the number of elements inserted. For us, k==4, n<=max_elements, - * and m==n_bits= approximately max_elements*32. This gives - * P<(1-exp(-4*n/(32*n)))^4 == (1-exp(1/-8))^4 == .00019 - * - * It would be more optimal in space vs false positives to get this false - * positive rate by going for k==13, and m==18.5n, but we also want to - * conserve CPU, and k==13 is pretty big. - */ - int n_bits = 1u << (tor_log2(max_elements)+5); - digestset_t *r = tor_malloc(sizeof(digestset_t)); - r->mask = n_bits - 1; - r->ba = bitarray_init_zero(n_bits); - return r; -} - -/** Free all storage held in <b>set</b>. */ -void -digestset_free_(digestset_t *set) -{ - if (!set) - return; - bitarray_free(set->ba); - tor_free(set); -} - diff --git a/src/common/container.h b/src/common/container.h deleted file mode 100644 index 5d2dce5416..0000000000 --- a/src/common/container.h +++ /dev/null @@ -1,742 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_CONTAINER_H -#define TOR_CONTAINER_H - -#include "util.h" -#include "siphash.h" - -/** A resizeable list of pointers, with associated helpful functionality. - * - * The members of this struct are exposed only so that macros and inlines can - * use them; all access to smartlist internals should go through the functions - * and macros defined here. - **/ -typedef struct smartlist_t { - /** @{ */ - /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements - * before it needs to be resized. Only the first <b>num_used</b> (\<= - * capacity) elements point to valid data. - */ - void **list; - int num_used; - int capacity; - /** @} */ -} smartlist_t; - -MOCK_DECL(smartlist_t *, smartlist_new, (void)); -MOCK_DECL(void, smartlist_free_, (smartlist_t *sl)); -#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl)) - -void smartlist_clear(smartlist_t *sl); -void smartlist_add(smartlist_t *sl, void *element); -void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); -void smartlist_remove(smartlist_t *sl, const void *element); -void smartlist_remove_keeporder(smartlist_t *sl, const void *element); -void *smartlist_pop_last(smartlist_t *sl); -void smartlist_reverse(smartlist_t *sl); -void smartlist_string_remove(smartlist_t *sl, const char *element); -int smartlist_contains(const smartlist_t *sl, const void *element); -int smartlist_contains_string(const smartlist_t *sl, const char *element); -int smartlist_pos(const smartlist_t *sl, const void *element); -int smartlist_string_pos(const smartlist_t *, const char *elt); -int smartlist_contains_string_case(const smartlist_t *sl, const char *element); -int smartlist_contains_int_as_string(const smartlist_t *sl, int num); -int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2); -int smartlist_contains_digest(const smartlist_t *sl, const char *element); -int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2); -int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); -void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); -void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); - -/* smartlist_choose() is defined in crypto.[ch] */ -#ifdef DEBUG_SMARTLIST -/** Return the number of items in sl. - */ -static inline int smartlist_len(const smartlist_t *sl); -static inline int smartlist_len(const smartlist_t *sl) { - tor_assert(sl); - return (sl)->num_used; -} -/** Return the <b>idx</b>th element of sl. - */ -static inline void *smartlist_get(const smartlist_t *sl, int idx); -static inline void *smartlist_get(const smartlist_t *sl, int idx) { - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(sl->num_used > idx); - return sl->list[idx]; -} -static inline void smartlist_set(smartlist_t *sl, int idx, void *val) { - tor_assert(sl); - tor_assert(idx>=0); - tor_assert(sl->num_used > idx); - sl->list[idx] = val; -} -#else /* !(defined(DEBUG_SMARTLIST)) */ -#define smartlist_len(sl) ((sl)->num_used) -#define smartlist_get(sl, idx) ((sl)->list[idx]) -#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val)) -#endif /* defined(DEBUG_SMARTLIST) */ - -/** Exchange the elements at indices <b>idx1</b> and <b>idx2</b> of the - * smartlist <b>sl</b>. */ -static inline void smartlist_swap(smartlist_t *sl, int idx1, int idx2) -{ - if (idx1 != idx2) { - void *elt = smartlist_get(sl, idx1); - smartlist_set(sl, idx1, smartlist_get(sl, idx2)); - smartlist_set(sl, idx2, elt); - } -} - -void smartlist_del(smartlist_t *sl, int idx); -void smartlist_del_keeporder(smartlist_t *sl, int idx); -void smartlist_insert(smartlist_t *sl, int idx, void *val); -void smartlist_sort(smartlist_t *sl, - int (*compare)(const void **a, const void **b)); -void *smartlist_get_most_frequent_(const smartlist_t *sl, - int (*compare)(const void **a, const void **b), - int *count_out); -#define smartlist_get_most_frequent(sl, compare) \ - smartlist_get_most_frequent_((sl), (compare), NULL) -void smartlist_uniq(smartlist_t *sl, - int (*compare)(const void **a, const void **b), - void (*free_fn)(void *elt)); - -void smartlist_sort_strings(smartlist_t *sl); -void smartlist_sort_digests(smartlist_t *sl); -void smartlist_sort_digests256(smartlist_t *sl); -void smartlist_sort_pointers(smartlist_t *sl); - -const char *smartlist_get_most_frequent_string(smartlist_t *sl); -const char *smartlist_get_most_frequent_string_(smartlist_t *sl, - int *count_out); -const uint8_t *smartlist_get_most_frequent_digest256(smartlist_t *sl); - -void smartlist_uniq_strings(smartlist_t *sl); -void smartlist_uniq_digests(smartlist_t *sl); -void smartlist_uniq_digests256(smartlist_t *sl); -void *smartlist_bsearch(smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member)); -int smartlist_bsearch_idx(const smartlist_t *sl, const void *key, - int (*compare)(const void *key, const void **member), - int *found_out); - -void smartlist_pqueue_add(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item); -void *smartlist_pqueue_pop(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset); -void smartlist_pqueue_remove(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset, - void *item); -void smartlist_pqueue_assert_ok(smartlist_t *sl, - int (*compare)(const void *a, const void *b), - int idx_field_offset); - -#define SPLIT_SKIP_SPACE 0x01 -#define SPLIT_IGNORE_BLANK 0x02 -#define SPLIT_STRIP_SPACE 0x04 -int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, - int flags, int max); -char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, - size_t *len_out) ATTR_MALLOC; -char *smartlist_join_strings2(smartlist_t *sl, const char *join, - size_t join_len, int terminate, size_t *len_out) - ATTR_MALLOC; - -/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item, - * assign it to a new local variable of type <b>type</b> named <b>var</b>, and - * execute the statements inside the loop body. Inside the loop, the loop - * index can be accessed as <b>var</b>_sl_idx and the length of the list can - * be accessed as <b>var</b>_sl_len. - * - * NOTE: Do not change the length of the list while the loop is in progress, - * unless you adjust the _sl_len variable correspondingly. See second example - * below. - * - * Example use: - * <pre> - * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); - * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { - * printf("%d: %s\n", cp_sl_idx, cp); - * tor_free(cp); - * } SMARTLIST_FOREACH_END(cp); - * smartlist_free(list); - * </pre> - * - * Example use (advanced): - * <pre> - * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { - * if (!strcmp(cp, "junk")) { - * tor_free(cp); - * SMARTLIST_DEL_CURRENT(list, cp); - * } - * } SMARTLIST_FOREACH_END(cp); - * </pre> - */ -/* Note: these macros use token pasting, and reach into smartlist internals. - * This can make them a little daunting. Here's the approximate unpacking of - * the above examples, for entertainment value: - * - * <pre> - * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); - * { - * int cp_sl_idx, cp_sl_len = smartlist_len(list); - * char *cp; - * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { - * cp = smartlist_get(list, cp_sl_idx); - * printf("%d: %s\n", cp_sl_idx, cp); - * tor_free(cp); - * } - * } - * smartlist_free(list); - * </pre> - * - * <pre> - * { - * int cp_sl_idx, cp_sl_len = smartlist_len(list); - * char *cp; - * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { - * cp = smartlist_get(list, cp_sl_idx); - * if (!strcmp(cp, "junk")) { - * tor_free(cp); - * smartlist_del(list, cp_sl_idx); - * --cp_sl_idx; - * --cp_sl_len; - * } - * } - * } - * </pre> - */ -#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \ - STMT_BEGIN \ - int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ - type var; \ - for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \ - ++var ## _sl_idx) { \ - var = (sl)->list[var ## _sl_idx]; - -#define SMARTLIST_FOREACH_END(var) \ - var = NULL; \ - (void) var ## _sl_idx; \ - } STMT_END - -/** - * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using - * <b>cmd</b> as the loop body. This wrapper is here for convenience with - * very short loops. - * - * By convention, we do not use this for loops which nest, or for loops over - * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those. - */ -#define SMARTLIST_FOREACH(sl, type, var, cmd) \ - SMARTLIST_FOREACH_BEGIN(sl,type,var) { \ - cmd; \ - } SMARTLIST_FOREACH_END(var) - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, remove the current element in a way that - * won't confuse the loop. */ -#define SMARTLIST_DEL_CURRENT(sl, var) \ - STMT_BEGIN \ - smartlist_del(sl, var ## _sl_idx); \ - --var ## _sl_idx; \ - --var ## _sl_len; \ - STMT_END - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, remove the current element in a way that - * won't confuse the loop. */ -#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \ - STMT_BEGIN \ - smartlist_del_keeporder(sl, var ## _sl_idx); \ - --var ## _sl_idx; \ - --var ## _sl_len; \ - STMT_END - -/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed - * with the variable <b>var</b>, replace the current element with <b>val</b>. - * Does not deallocate the current value of <b>var</b>. - */ -#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \ - STMT_BEGIN \ - smartlist_set(sl, var ## _sl_idx, val); \ - STMT_END - -/* Helper: Given two lists of items, possibly of different types, such that - * both lists are sorted on some common field (as determined by a comparison - * expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no - * duplicates on the common field, loop through the lists in lockstep, and - * execute <b>unmatched_var2</b> on items in var2 that do not appear in - * var1. - * - * WARNING: It isn't safe to add remove elements from either list while the - * loop is in progress. - * - * Example use: - * SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs, - * routerinfo_list, routerinfo_t *, ri, - * tor_memcmp(rs->identity_digest, ri->identity_digest, 20), - * log_info(LD_GENERAL,"No match for %s", ri->nickname)) { - * log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs); - * } SMARTLIST_FOREACH_JOIN_END(rs, ri); - **/ -/* The example above unpacks (approximately) to: - * int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list); - * int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list); - * int rs_ri_cmp; - * routerstatus_t *rs; - * routerinfo_t *ri; - * for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) { - * ri = smartlist_get(routerinfo_list, ri_sl_idx); - * while (rs_sl_idx < rs_sl_len) { - * rs = smartlist_get(routerstatus_list, rs_sl_idx); - * rs_ri_cmp = tor_memcmp(rs->identity_digest, ri->identity_digest, 20); - * if (rs_ri_cmp > 0) { - * break; - * } else if (rs_ri_cmp == 0) { - * goto matched_ri; - * } else { - * ++rs_sl_idx; - * } - * } - * log_info(LD_GENERAL,"No match for %s", ri->nickname); - * continue; - * matched_ri: { - * log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs); - * } - * } - */ -#define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2, \ - cmpexpr, unmatched_var2) \ - STMT_BEGIN \ - int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used; \ - int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used; \ - int var1 ## _ ## var2 ## _cmp; \ - type1 var1; \ - type2 var2; \ - for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) { \ - var2 = (sl2)->list[var2##_sl_idx]; \ - while (var1##_sl_idx < var1##_sl_len) { \ - var1 = (sl1)->list[var1##_sl_idx]; \ - var1##_##var2##_cmp = (cmpexpr); \ - if (var1##_##var2##_cmp > 0) { \ - break; \ - } else if (var1##_##var2##_cmp == 0) { \ - goto matched_##var2; \ - } else { \ - ++var1##_sl_idx; \ - } \ - } \ - /* Ran out of v1, or no match for var2. */ \ - unmatched_var2; \ - continue; \ - matched_##var2: ; \ - -#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \ - } \ - STMT_END - -#define DECLARE_MAP_FNS(maptype, keytype, prefix) \ - typedef struct maptype maptype; \ - typedef struct prefix##entry_t *prefix##iter_t; \ - MOCK_DECL(maptype*, prefix##new, (void)); \ - void* prefix##set(maptype *map, keytype key, void *val); \ - void* prefix##get(const maptype *map, keytype key); \ - void* prefix##remove(maptype *map, keytype key); \ - MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \ - int prefix##isempty(const maptype *map); \ - int prefix##size(const maptype *map); \ - prefix##iter_t *prefix##iter_init(maptype *map); \ - prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \ - prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \ - void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \ - int prefix##iter_done(prefix##iter_t *iter); \ - void prefix##assert_ok(const maptype *map) - -/* Map from const char * to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(strmap_t, const char *, strmap_); -/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */ -DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_); -/* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash - * table. */ -DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); - -#define MAP_FREE_AND_NULL(maptype, map, fn) \ - do { \ - maptype ## _free_((map), (fn)); \ - (map) = NULL; \ - } while (0) - -#define strmap_free(map, fn) MAP_FREE_AND_NULL(strmap, (map), (fn)) -#define digestmap_free(map, fn) MAP_FREE_AND_NULL(digestmap, (map), (fn)) -#define digest256map_free(map, fn) MAP_FREE_AND_NULL(digest256map, (map), (fn)) - -#undef DECLARE_MAP_FNS - -/** Iterates over the key-value pairs in a map <b>map</b> in order. - * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_). - * The map's keys and values are of type keytype and valtype respectively; - * each iteration assigns them to keyvar and valvar. - * - * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { - * // use k and r - * } MAP_FOREACH_END. - */ -/* Unpacks to, approximately: - * { - * digestmap_iter_t *k_iter; - * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); - * k_iter = digestmap_iter_next(m, k_iter)) { - * const char *k; - * void *r_voidp; - * routerinfo_t *r; - * digestmap_iter_get(k_iter, &k, &r_voidp); - * r = r_voidp; - * // use k and r - * } - * } - */ -#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \ - STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ - keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \ - keytype keyvar; \ - void *valvar##_voidp; \ - valtype valvar; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ - valvar = valvar##_voidp; - -/** As MAP_FOREACH, except allows members to be removed from the map - * during the iteration via MAP_DEL_CURRENT. Example use: - * - * Example use: - * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { - * if (is_very_old(r)) - * MAP_DEL_CURRENT(k); - * } MAP_FOREACH_END. - **/ -/* Unpacks to, approximately: - * { - * digestmap_iter_t *k_iter; - * int k_del=0; - * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); - * k_iter = k_del ? digestmap_iter_next(m, k_iter) - * : digestmap_iter_next_rmv(m, k_iter)) { - * const char *k; - * void *r_voidp; - * routerinfo_t *r; - * k_del=0; - * digestmap_iter_get(k_iter, &k, &r_voidp); - * r = r_voidp; - * if (is_very_old(r)) { - * k_del = 1; - * } - * } - * } - */ -#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \ - STMT_BEGIN \ - prefix##iter_t *keyvar##_iter; \ - int keyvar##_del=0; \ - for (keyvar##_iter = prefix##iter_init(map); \ - !prefix##iter_done(keyvar##_iter); \ - keyvar##_iter = keyvar##_del ? \ - prefix##iter_next_rmv(map, keyvar##_iter) : \ - prefix##iter_next(map, keyvar##_iter)) { \ - keytype keyvar; \ - void *valvar##_voidp; \ - valtype valvar; \ - keyvar##_del=0; \ - prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ - valvar = valvar##_voidp; - -/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon - * member of the map. */ -#define MAP_DEL_CURRENT(keyvar) \ - STMT_BEGIN \ - keyvar##_del = 1; \ - STMT_END - -/** Used to end a MAP_FOREACH() block. */ -#define MAP_FOREACH_END } STMT_END ; - -/** As MAP_FOREACH, but does not require declaration of prefix or keytype. - * Example use: - * DIGESTMAP_FOREACH(m, k, routerinfo_t *, r) { - * // use k and r - * } DIGESTMAP_FOREACH_END. - */ -#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar) - -/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or - * keytype. - * Example use: - * DIGESTMAP_FOREACH_MODIFY(m, k, routerinfo_t *, r) { - * if (is_very_old(r)) - * MAP_DEL_CURRENT(k); - * } DIGESTMAP_FOREACH_END. - */ -#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar) -/** Used to end a DIGESTMAP_FOREACH() block. */ -#define DIGESTMAP_FOREACH_END MAP_FOREACH_END - -#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar) -#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \ - keyvar, valtype, valvar) -#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END - -#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \ - MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar) -#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ - MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar) -#define STRMAP_FOREACH_END MAP_FOREACH_END - -void* strmap_set_lc(strmap_t *map, const char *key, void *val); -void* strmap_get_lc(const strmap_t *map, const char *key); -void* strmap_remove_lc(strmap_t *map, const char *key); - -#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \ - typedef struct maptype maptype; \ - typedef struct prefix##iter_t *prefix##iter_t; \ - ATTR_UNUSED static inline maptype* \ - prefix##new(void) \ - { \ - return (maptype*)digestmap_new(); \ - } \ - ATTR_UNUSED static inline digestmap_t* \ - prefix##to_digestmap(maptype *map) \ - { \ - return (digestmap_t*)map; \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##get(maptype *map, const char *key) \ - { \ - return (valtype*)digestmap_get((digestmap_t*)map, key); \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##set(maptype *map, const char *key, valtype *val) \ - { \ - return (valtype*)digestmap_set((digestmap_t*)map, key, val); \ - } \ - ATTR_UNUSED static inline valtype* \ - prefix##remove(maptype *map, const char *key) \ - { \ - return (valtype*)digestmap_remove((digestmap_t*)map, key); \ - } \ - ATTR_UNUSED static inline void \ - prefix##f##ree_(maptype *map, void (*free_val)(void*)) \ - { \ - digestmap_free_((digestmap_t*)map, free_val); \ - } \ - ATTR_UNUSED static inline int \ - prefix##isempty(maptype *map) \ - { \ - return digestmap_isempty((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline int \ - prefix##size(maptype *map) \ - { \ - return digestmap_size((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_init(maptype *map) \ - { \ - return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \ - } \ - ATTR_UNUSED static inline \ - prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \ - { \ - return (prefix##iter_t*) digestmap_iter_next( \ - (digestmap_t*)map, (digestmap_iter_t*)iter); \ - } \ - ATTR_UNUSED static inline prefix##iter_t* \ - prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \ - { \ - return (prefix##iter_t*) digestmap_iter_next_rmv( \ - (digestmap_t*)map, (digestmap_iter_t*)iter); \ - } \ - ATTR_UNUSED static inline void \ - prefix##iter_get(prefix##iter_t *iter, \ - const char **keyp, \ - valtype **valp) \ - { \ - void *v; \ - digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \ - *valp = v; \ - } \ - ATTR_UNUSED static inline int \ - prefix##iter_done(prefix##iter_t *iter) \ - { \ - return digestmap_iter_done((digestmap_iter_t*)iter); \ - } - -#if SIZEOF_INT == 4 -#define BITARRAY_SHIFT 5 -#elif SIZEOF_INT == 8 -#define BITARRAY_SHIFT 6 -#else -#error "int is neither 4 nor 8 bytes. I can't deal with that." -#endif /* SIZEOF_INT == 4 || ... */ -#define BITARRAY_MASK ((1u<<BITARRAY_SHIFT)-1) - -/** A random-access array of one-bit-wide elements. */ -typedef unsigned int bitarray_t; -/** Create a new bit array that can hold <b>n_bits</b> bits. */ -static inline bitarray_t * -bitarray_init_zero(unsigned int n_bits) -{ - /* round up to the next int. */ - size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT; - return tor_calloc(sz, sizeof(unsigned int)); -} -/** Expand <b>ba</b> from holding <b>n_bits_old</b> to <b>n_bits_new</b>, - * clearing all new bits. Returns a possibly changed pointer to the - * bitarray. */ -static inline bitarray_t * -bitarray_expand(bitarray_t *ba, - unsigned int n_bits_old, unsigned int n_bits_new) -{ - size_t sz_old = (n_bits_old+BITARRAY_MASK) >> BITARRAY_SHIFT; - size_t sz_new = (n_bits_new+BITARRAY_MASK) >> BITARRAY_SHIFT; - char *ptr; - if (sz_new <= sz_old) - return ba; - ptr = tor_reallocarray(ba, sz_new, sizeof(unsigned int)); - /* This memset does nothing to the older excess bytes. But they were - * already set to 0 by bitarry_init_zero. */ - memset(ptr+sz_old*sizeof(unsigned int), 0, - (sz_new-sz_old)*sizeof(unsigned int)); - return (bitarray_t*) ptr; -} -/** Free the bit array <b>ba</b>. */ -static inline void -bitarray_free_(bitarray_t *ba) -{ - tor_free(ba); -} -#define bitarray_free(ba) FREE_AND_NULL(bitarray_t, bitarray_free_, (ba)) - -/** Set the <b>bit</b>th bit in <b>b</b> to 1. */ -static inline void -bitarray_set(bitarray_t *b, int bit) -{ - b[bit >> BITARRAY_SHIFT] |= (1u << (bit & BITARRAY_MASK)); -} -/** Set the <b>bit</b>th bit in <b>b</b> to 0. */ -static inline void -bitarray_clear(bitarray_t *b, int bit) -{ - b[bit >> BITARRAY_SHIFT] &= ~ (1u << (bit & BITARRAY_MASK)); -} -/** Return true iff <b>bit</b>th bit in <b>b</b> is nonzero. NOTE: does - * not necessarily return 1 on true. */ -static inline unsigned int -bitarray_is_set(bitarray_t *b, int bit) -{ - return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK)); -} - -/** A set of digests, implemented as a Bloom filter. */ -typedef struct { - int mask; /**< One less than the number of bits in <b>ba</b>; always one less - * than a power of two. */ - bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ -} digestset_t; - -#define BIT(n) ((n) & set->mask) -/** Add the digest <b>digest</b> to <b>set</b>. */ -static inline void -digestset_add(digestset_t *set, const char *digest) -{ - const uint64_t x = siphash24g(digest, 20); - const uint32_t d1 = (uint32_t) x; - const uint32_t d2 = (uint32_t)( (x>>16) + x); - const uint32_t d3 = (uint32_t)( (x>>32) + x); - const uint32_t d4 = (uint32_t)( (x>>48) + x); - bitarray_set(set->ba, BIT(d1)); - bitarray_set(set->ba, BIT(d2)); - bitarray_set(set->ba, BIT(d3)); - bitarray_set(set->ba, BIT(d4)); -} - -/** If <b>digest</b> is in <b>set</b>, return nonzero. Otherwise, - * <em>probably</em> return zero. */ -static inline int -digestset_contains(const digestset_t *set, const char *digest) -{ - const uint64_t x = siphash24g(digest, 20); - const uint32_t d1 = (uint32_t) x; - const uint32_t d2 = (uint32_t)( (x>>16) + x); - const uint32_t d3 = (uint32_t)( (x>>32) + x); - const uint32_t d4 = (uint32_t)( (x>>48) + x); - return bitarray_is_set(set->ba, BIT(d1)) && - bitarray_is_set(set->ba, BIT(d2)) && - bitarray_is_set(set->ba, BIT(d3)) && - bitarray_is_set(set->ba, BIT(d4)); -} -#undef BIT - -digestset_t *digestset_new(int max_elements); -void digestset_free_(digestset_t* set); -#define digestset_free(set) FREE_AND_NULL(digestset_t, digestset_free_, (set)) - -/* These functions, given an <b>array</b> of <b>n_elements</b>, return the - * <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element; - * <b>n_elements</b>-1 gives the highest; and (<b>n_elements</b>-1) / 2 gives - * the median. As a side effect, the elements of <b>array</b> are sorted. */ -int find_nth_int(int *array, int n_elements, int nth); -time_t find_nth_time(time_t *array, int n_elements, int nth); -double find_nth_double(double *array, int n_elements, int nth); -int32_t find_nth_int32(int32_t *array, int n_elements, int nth); -uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth); -long find_nth_long(long *array, int n_elements, int nth); -static inline int -median_int(int *array, int n_elements) -{ - return find_nth_int(array, n_elements, (n_elements-1)/2); -} -static inline time_t -median_time(time_t *array, int n_elements) -{ - return find_nth_time(array, n_elements, (n_elements-1)/2); -} -static inline double -median_double(double *array, int n_elements) -{ - return find_nth_double(array, n_elements, (n_elements-1)/2); -} -static inline uint32_t -median_uint32(uint32_t *array, int n_elements) -{ - return find_nth_uint32(array, n_elements, (n_elements-1)/2); -} -static inline int32_t -median_int32(int32_t *array, int n_elements) -{ - return find_nth_int32(array, n_elements, (n_elements-1)/2); -} - -static inline uint32_t -third_quartile_uint32(uint32_t *array, int n_elements) -{ - return find_nth_uint32(array, n_elements, (n_elements*3)/4); -} - -#endif /* !defined(TOR_CONTAINER_H) */ - diff --git a/src/common/crypto.c b/src/common/crypto.c deleted file mode 100644 index d5b7c96916..0000000000 --- a/src/common/crypto.c +++ /dev/null @@ -1,1118 +0,0 @@ -/* Copyright (c) 2001, Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file crypto.c - * \brief Wrapper functions to present a consistent interface to - * public-key and symmetric cryptography operations from OpenSSL and - * other places. - **/ - -#include "orconfig.h" - -#ifdef _WIN32 -#include <winsock2.h> -#include <windows.h> -#include <wincrypt.h> -/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually - * use either definition. */ -#undef OCSP_RESPONSE -#endif /* defined(_WIN32) */ - -#define CRYPTO_PRIVATE -#include "compat_openssl.h" -#include "crypto.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_rsa.h" -#include "crypto_util.h" - -DISABLE_GCC_WARNING(redundant-decls) - -#include <openssl/err.h> -#include <openssl/evp.h> -#include <openssl/engine.h> -#include <openssl/bn.h> -#include <openssl/dh.h> -#include <openssl/conf.h> -#include <openssl/hmac.h> -#include <openssl/ssl.h> - -ENABLE_GCC_WARNING(redundant-decls) - -#if __GNUC__ && GCC_VERSION >= 402 -#if GCC_VERSION >= 406 -#pragma GCC diagnostic pop -#else -#pragma GCC diagnostic warning "-Wredundant-decls" -#endif -#endif /* __GNUC__ && GCC_VERSION >= 402 */ - -#ifdef HAVE_CTYPE_H -#include <ctype.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#include "torlog.h" -#include "torint.h" -#include "aes.h" -#include "util.h" -#include "container.h" -#include "compat.h" -#include "sandbox.h" -#include "util_format.h" - -#include "keccak-tiny/keccak-tiny.h" - -/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake - * while we're waiting for the second.*/ -struct crypto_dh_t { - DH *dh; /**< The openssl DH object */ -}; - -static int tor_check_dh_key(int severity, const BIGNUM *bn); - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_early_initialized_ = 0; - -/** Boolean: has OpenSSL's crypto been initialized? */ -static int crypto_global_initialized_ = 0; - -/** Log all pending crypto errors at level <b>severity</b>. Use - * <b>doing</b> to describe our current activities. - */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - while ((err = ERR_get_error()) != 0) { - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (BUG(!doing)) doing = "(null)"; - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } -} - -#ifndef DISABLE_ENGINES -/** Log any OpenSSL engines we're using at NOTICE. */ -static void -log_engine(const char *fn, ENGINE *e) -{ - if (e) { - const char *name, *id; - name = ENGINE_get_name(e); - id = ENGINE_get_id(e); - log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]", - fn, name?name:"?", id?id:"?"); - } else { - log_info(LD_CRYPTO, "Using default implementation for %s", fn); - } -} -#endif /* !defined(DISABLE_ENGINES) */ - -#ifndef DISABLE_ENGINES -/** Try to load an engine in a shared library via fully qualified path. - */ -static ENGINE * -try_load_engine(const char *path, const char *engine) -{ - ENGINE *e = ENGINE_by_id("dynamic"); - if (e) { - if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) || - !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) || - !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { - ENGINE_free(e); - e = NULL; - } - } - return e; -} -#endif /* !defined(DISABLE_ENGINES) */ - -static int have_seeded_siphash = 0; - -/** Set up the siphash key if we haven't already done so. */ -int -crypto_init_siphash_key(void) -{ - struct sipkey key; - if (have_seeded_siphash) - return 0; - - crypto_rand((char*) &key, sizeof(key)); - siphash_set_global_key(&key); - have_seeded_siphash = 1; - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_early_init(void) -{ - if (!crypto_early_initialized_) { - - crypto_early_initialized_ = 1; - -#ifdef OPENSSL_1_1_API - OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | - OPENSSL_INIT_LOAD_CRYPTO_STRINGS | - OPENSSL_INIT_ADD_ALL_CIPHERS | - OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); -#else - ERR_load_crypto_strings(); - OpenSSL_add_all_algorithms(); -#endif - - setup_openssl_threading(); - - unsigned long version_num = OpenSSL_version_num(); - const char *version_str = OpenSSL_version(OPENSSL_VERSION); - if (version_num == OPENSSL_VERSION_NUMBER && - !strcmp(version_str, OPENSSL_VERSION_TEXT)) { - log_info(LD_CRYPTO, "OpenSSL version matches version from headers " - "(%lx: %s).", version_num, version_str); - } else { - log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " - "version we're running with. If you get weird crashes, that " - "might be why. (Compiled with %lx: %s; running with %lx: %s).", - (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, - version_num, version_str); - } - - crypto_force_rand_ssleay(); - - if (crypto_seed_rng() < 0) - return -1; - if (crypto_init_siphash_key() < 0) - return -1; - - curve25519_init(); - ed25519_init(); - } - return 0; -} - -/** Initialize the crypto library. Return 0 on success, -1 on failure. - */ -int -crypto_global_init(int useAccel, const char *accelName, const char *accelDir) -{ - if (!crypto_global_initialized_) { - if (crypto_early_init() < 0) - return -1; - - crypto_global_initialized_ = 1; - - if (useAccel > 0) { -#ifdef DISABLE_ENGINES - (void)accelName; - (void)accelDir; - log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled."); -#else - ENGINE *e = NULL; - - log_info(LD_CRYPTO, "Initializing OpenSSL engine support."); - ENGINE_load_builtin_engines(); - ENGINE_register_all_complete(); - - if (accelName) { - if (accelDir) { - log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\"" - " via path \"%s\".", accelName, accelDir); - e = try_load_engine(accelName, accelDir); - } else { - log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\"" - " acceleration support.", accelName); - e = ENGINE_by_id(accelName); - } - if (!e) { - log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".", - accelName); - } else { - log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".", - accelName); - } - } - if (e) { - log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine," - " setting default ciphers."); - ENGINE_set_default(e, ENGINE_METHOD_ALL); - } - /* Log, if available, the intersection of the set of algorithms - used by Tor and the set of algorithms available in the engine */ - log_engine("RSA", ENGINE_get_default_RSA()); - log_engine("DH", ENGINE_get_default_DH()); -#ifdef OPENSSL_1_1_API - log_engine("EC", ENGINE_get_default_EC()); -#else - log_engine("ECDH", ENGINE_get_default_ECDH()); - log_engine("ECDSA", ENGINE_get_default_ECDSA()); -#endif /* defined(OPENSSL_1_1_API) */ - log_engine("RAND", ENGINE_get_default_RAND()); - log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); - log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); - log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); - log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); - log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); -#ifdef NID_aes_128_ctr - log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); -#endif -#ifdef NID_aes_128_gcm - log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); -#endif - log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); -#ifdef NID_aes_256_gcm - log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); -#endif - -#endif /* defined(DISABLE_ENGINES) */ - } else { - log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); - } - - if (crypto_force_rand_ssleay()) { - if (crypto_seed_rng() < 0) - return -1; - } - - evaluate_evp_for_aes(-1); - evaluate_ctr_for_aes(); - } - return 0; -} - -/** Free crypto resources held by this thread. */ -void -crypto_thread_cleanup(void) -{ -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -} - -/** Used by tortls.c: Get the DH* from a crypto_dh_t. - */ -DH * -crypto_dh_get_dh_(crypto_dh_t *dh) -{ - return dh->dh; -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. Key length must be 128, 192, or 256 */ -crypto_cipher_t * -crypto_cipher_new_with_iv_and_bits(const uint8_t *key, - const uint8_t *iv, - int bits) -{ - tor_assert(key); - tor_assert(iv); - - return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits); -} - -/** Allocate and return a new symmetric cipher using the provided key and iv. - * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both - * must be provided. - */ -crypto_cipher_t * -crypto_cipher_new_with_iv(const char *key, const char *iv) -{ - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv, - 128); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all - * zero bytes and key length <b>bits</b>. Key length must be 128, 192, or - * 256. */ -crypto_cipher_t * -crypto_cipher_new_with_bits(const char *key, int bits) -{ - char zeroiv[CIPHER_IV_LEN]; - memset(zeroiv, 0, sizeof(zeroiv)); - return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv, - bits); -} - -/** Return a new crypto_cipher_t with the provided <b>key</b> (of - * CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */ -crypto_cipher_t * -crypto_cipher_new(const char *key) -{ - return crypto_cipher_new_with_bits(key, 128); -} - -/** Free a symmetric cipher. - */ -void -crypto_cipher_free_(crypto_cipher_t *env) -{ - if (!env) - return; - - aes_cipher_free(env); -} - -/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces - * every four characters. */ -void -crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) -{ - int n = 0; - char *end = out+outlen; - tor_assert(outlen < SIZE_T_CEILING); - - while (*in && out<end) { - *out++ = *in++; - if (++n == 4 && *in && out<end) { - n = 0; - *out++ = ' '; - } - } - tor_assert(out<end); - *out = '\0'; -} - -/* symmetric crypto */ - -/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_encrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(env); - tor_assert(from); - tor_assert(fromlen); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher - * <b>env</b>; on success, store the result to <b>to</b> and return 0. - * Does not check for failure. - */ -int -crypto_cipher_decrypt(crypto_cipher_t *env, char *to, - const char *from, size_t fromlen) -{ - tor_assert(env); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < SIZE_T_CEILING); - - memcpy(to, from, fromlen); - aes_crypt_inplace(env, to, fromlen); - return 0; -} - -/** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; - * on success. Does not check for failure. - */ -void -crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) -{ - tor_assert(len < SIZE_T_CEILING); - aes_crypt_inplace(env, buf, len); -} - -/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in - * <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_encrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen < 1) - return -1; - if (tolen < fromlen + CIPHER_IV_LEN) - return -1; - - char iv[CIPHER_IV_LEN]; - crypto_rand(iv, sizeof(iv)); - cipher = crypto_cipher_new_with_iv(key, iv); - - memcpy(to, iv, CIPHER_IV_LEN); - crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); - crypto_cipher_free(cipher); - memwipe(iv, 0, sizeof(iv)); - return (int)(fromlen + CIPHER_IV_LEN); -} - -/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b> - * with the key in <b>key</b> to the buffer in <b>to</b> of length - * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus - * CIPHER_IV_LEN bytes for the initialization vector. On success, return the - * number of bytes written, on failure, return -1. - */ -int -crypto_cipher_decrypt_with_iv(const char *key, - char *to, size_t tolen, - const char *from, size_t fromlen) -{ - crypto_cipher_t *cipher; - tor_assert(key); - tor_assert(from); - tor_assert(to); - tor_assert(fromlen < INT_MAX); - - if (fromlen <= CIPHER_IV_LEN) - return -1; - if (tolen < fromlen - CIPHER_IV_LEN) - return -1; - - cipher = crypto_cipher_new_with_iv(key, from); - - crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN); - crypto_cipher_free(cipher); - return (int)(fromlen - CIPHER_IV_LEN); -} - -/* DH */ - -/** Our DH 'g' parameter */ -#define DH_GENERATOR 2 - -/** Shared P parameter for our circuit-crypto DH key exchanges. */ -static BIGNUM *dh_param_p = NULL; -/** Shared P parameter for our TLS DH key exchanges. */ -static BIGNUM *dh_param_p_tls = NULL; -/** Shared G parameter for our DH key exchanges. */ -static BIGNUM *dh_param_g = NULL; - -/** Validate a given set of Diffie-Hellman parameters. This is moderately - * computationally expensive (milliseconds), so should only be called when - * the DH parameters change. Returns 0 on success, * -1 on failure. - */ -static int -crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) -{ - DH *dh = NULL; - int ret = -1; - - /* Copy into a temporary DH object, just so that DH_check() can be called. */ - if (!(dh = DH_new())) - goto out; -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p, *dh_g; - if (!(dh_p = BN_dup(p))) - goto out; - if (!(dh_g = BN_dup(g))) - goto out; - if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) - goto out; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (!(dh->p = BN_dup(p))) - goto out; - if (!(dh->g = BN_dup(g))) - goto out; -#endif /* defined(OPENSSL_1_1_API) */ - - /* Perform the validation. */ - int codes = 0; - if (!DH_check(dh, &codes)) - goto out; - if (BN_is_word(g, DH_GENERATOR_2)) { - /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters - * - * OpenSSL checks the prime is congruent to 11 when g = 2; while the - * IETF's primes are congruent to 23 when g = 2. - */ - BN_ULONG residue = BN_mod_word(p, 24); - if (residue == 11 || residue == 23) - codes &= ~DH_NOT_SUITABLE_GENERATOR; - } - if (codes != 0) /* Specifics on why the params suck is irrelevant. */ - goto out; - - /* Things are probably not evil. */ - ret = 0; - - out: - if (dh) - DH_free(dh); - return ret; -} - -/** Set the global Diffie-Hellman generator, used for both TLS and internal - * DH stuff. - */ -static void -crypto_set_dh_generator(void) -{ - BIGNUM *generator; - int r; - - if (dh_param_g) - return; - - generator = BN_new(); - tor_assert(generator); - - r = BN_set_word(generator, DH_GENERATOR); - tor_assert(r); - - dh_param_g = generator; -} - -/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH - * modulus. */ -void -crypto_set_tls_dh_prime(void) -{ - BIGNUM *tls_prime = NULL; - int r; - - /* If the space is occupied, free the previous TLS DH prime */ - if (BUG(dh_param_p_tls)) { - /* LCOV_EXCL_START - * - * We shouldn't be calling this twice. - */ - BN_clear_free(dh_param_p_tls); - dh_param_p_tls = NULL; - /* LCOV_EXCL_STOP */ - } - - tls_prime = BN_new(); - tor_assert(tls_prime); - - /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see - * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this - * prime. - */ - r = BN_hex2bn(&tls_prime, - "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" - "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" - "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" - "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" - "B0E7393E0F24218EB3"); - tor_assert(r); - - tor_assert(tls_prime); - - dh_param_p_tls = tls_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g)); -} - -/** Initialize dh_param_p and dh_param_g if they are not already - * set. */ -static void -init_dh_param(void) -{ - BIGNUM *circuit_dh_prime; - int r; - if (BUG(dh_param_p && dh_param_g)) - return; // LCOV_EXCL_LINE This function isn't supposed to be called twice. - - circuit_dh_prime = BN_new(); - tor_assert(circuit_dh_prime); - - /* This is from rfc2409, section 6.2. It's a safe prime, and - supposedly it equals: - 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. - */ - r = BN_hex2bn(&circuit_dh_prime, - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" - "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" - "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" - "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" - "49286651ECE65381FFFFFFFFFFFFFFFF"); - tor_assert(r); - - /* Set the new values as the global DH parameters. */ - dh_param_p = circuit_dh_prime; - crypto_set_dh_generator(); - tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g)); - - if (!dh_param_p_tls) { - crypto_set_tls_dh_prime(); - } -} - -/** Number of bits to use when choosing the x or y value in a Diffie-Hellman - * handshake. Since we exponentiate by this value, choosing a smaller one - * lets our handhake go faster. - */ -#define DH_PRIVATE_KEY_BITS 320 - -/** Allocate and return a new DH object for a key exchange. Returns NULL on - * failure. - */ -crypto_dh_t * -crypto_dh_new(int dh_type) -{ - crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t)); - - tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS || - dh_type == DH_TYPE_REND); - - if (!dh_param_p) - init_dh_param(); - - if (!(res->dh = DH_new())) - goto err; - -#ifdef OPENSSL_1_1_API - BIGNUM *dh_p = NULL, *dh_g = NULL; - - if (dh_type == DH_TYPE_TLS) { - dh_p = BN_dup(dh_param_p_tls); - } else { - dh_p = BN_dup(dh_param_p); - } - if (!dh_p) - goto err; - - dh_g = BN_dup(dh_param_g); - if (!dh_g) { - BN_free(dh_p); - goto err; - } - - if (!DH_set0_pqg(res->dh, dh_p, NULL, dh_g)) { - goto err; - } - - if (!DH_set_length(res->dh, DH_PRIVATE_KEY_BITS)) - goto err; -#else /* !(defined(OPENSSL_1_1_API)) */ - if (dh_type == DH_TYPE_TLS) { - if (!(res->dh->p = BN_dup(dh_param_p_tls))) - goto err; - } else { - if (!(res->dh->p = BN_dup(dh_param_p))) - goto err; - } - - if (!(res->dh->g = BN_dup(dh_param_g))) - goto err; - - res->dh->length = DH_PRIVATE_KEY_BITS; -#endif /* defined(OPENSSL_1_1_API) */ - - return res; - - /* LCOV_EXCL_START - * This error condition is only reached when an allocation fails */ - err: - crypto_log_errors(LOG_WARN, "creating DH object"); - if (res->dh) DH_free(res->dh); /* frees p and g too */ - tor_free(res); - return NULL; - /* LCOV_EXCL_STOP */ -} - -/** Return a copy of <b>dh</b>, sharing its internal state. */ -crypto_dh_t * -crypto_dh_dup(const crypto_dh_t *dh) -{ - crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); - tor_assert(dh); - tor_assert(dh->dh); - dh_new->dh = dh->dh; - DH_up_ref(dh->dh); - return dh_new; -} - -/** Return the length of the DH key in <b>dh</b>, in bytes. - */ -int -crypto_dh_get_bytes(crypto_dh_t *dh) -{ - tor_assert(dh); - return DH_size(dh->dh); -} - -/** Generate \<x,g^x\> for our part of the key exchange. Return 0 on - * success, -1 on failure. - */ -int -crypto_dh_generate_public(crypto_dh_t *dh) -{ -#ifndef OPENSSL_1_1_API - again: -#endif - if (!DH_generate_key(dh->dh)) { - /* LCOV_EXCL_START - * To test this we would need some way to tell openssl to break DH. */ - crypto_log_errors(LOG_WARN, "generating DH key"); - return -1; - /* LCOV_EXCL_STOP */ - } -#ifdef OPENSSL_1_1_API - /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without - * recreating the DH object. I have no idea what sort of aliasing madness - * can occur here, so do the check, and just bail on failure. - */ - const BIGNUM *pub_key, *priv_key; - DH_get0_key(dh->dh, &pub_key, &priv_key); - if (tor_check_dh_key(LOG_WARN, pub_key)<0) { - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Treating as a failure."); - return -1; - } -#else /* !(defined(OPENSSL_1_1_API)) */ - if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { - /* LCOV_EXCL_START - * If this happens, then openssl's DH implementation is busted. */ - log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" - "the-universe chances really do happen. Trying again."); - /* Free and clear the keys, so OpenSSL will actually try again. */ - BN_clear_free(dh->dh->pub_key); - BN_clear_free(dh->dh->priv_key); - dh->dh->pub_key = dh->dh->priv_key = NULL; - goto again; - /* LCOV_EXCL_STOP */ - } -#endif /* defined(OPENSSL_1_1_API) */ - return 0; -} - -/** Generate g^x as necessary, and write the g^x for the key exchange - * as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on - * success, -1 on failure. <b>pubkey_len</b> must be \>= DH_BYTES. - */ -int -crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) -{ - int bytes; - tor_assert(dh); - - const BIGNUM *dh_pub; - -#ifdef OPENSSL_1_1_API - const BIGNUM *dh_priv; - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif /* defined(OPENSSL_1_1_API) */ - - if (!dh_pub) { - if (crypto_dh_generate_public(dh)<0) - return -1; - else { -#ifdef OPENSSL_1_1_API - DH_get0_key(dh->dh, &dh_pub, &dh_priv); -#else - dh_pub = dh->dh->pub_key; -#endif - } - } - - tor_assert(dh_pub); - bytes = BN_num_bytes(dh_pub); - tor_assert(bytes >= 0); - if (pubkey_len < (size_t)bytes) { - log_warn(LD_CRYPTO, - "Weird! pubkey_len (%d) was smaller than DH_BYTES (%d)", - (int) pubkey_len, bytes); - return -1; - } - - memset(pubkey, 0, pubkey_len); - BN_bn2bin(dh_pub, (unsigned char*)(pubkey+(pubkey_len-bytes))); - - return 0; -} - -/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is - * okay (in the subgroup [2,p-2]), or -1 if it's bad. - * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. - */ -static int -tor_check_dh_key(int severity, const BIGNUM *bn) -{ - BIGNUM *x; - char *s; - tor_assert(bn); - x = BN_new(); - tor_assert(x); - if (BUG(!dh_param_p)) - init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this. - BN_set_word(x, 1); - if (BN_cmp(bn,x)<=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); - goto err; - } - BN_copy(x,dh_param_p); - BN_sub_word(x, 1); - if (BN_cmp(bn,x)>=0) { - log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); - goto err; - } - BN_clear_free(x); - return 0; - err: - BN_clear_free(x); - s = BN_bn2hex(bn); - log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); - OPENSSL_free(s); - return -1; -} - -/** Given a DH key exchange object, and our peer's value of g^y (as a - * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate - * <b>secret_bytes_out</b> bytes of shared key material and write them - * to <b>secret_out</b>. Return the number of bytes generated on success, - * or -1 on failure. - * - * (We generate key material by computing - * SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ... - * where || is concatenation.) - */ -ssize_t -crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_bytes_out) -{ - char *secret_tmp = NULL; - BIGNUM *pubkey_bn = NULL; - size_t secret_len=0, secret_tmp_len=0; - int result=0; - tor_assert(dh); - tor_assert(secret_bytes_out/DIGEST_LEN <= 255); - tor_assert(pubkey_len < INT_MAX); - - if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, - (int)pubkey_len, NULL))) - goto error; - if (tor_check_dh_key(severity, pubkey_bn)<0) { - /* Check for invalid public keys. */ - log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); - goto error; - } - secret_tmp_len = crypto_dh_get_bytes(dh); - secret_tmp = tor_malloc(secret_tmp_len); - result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh); - if (result < 0) { - log_warn(LD_CRYPTO,"DH_compute_key() failed."); - goto error; - } - secret_len = result; - if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len, - (uint8_t*)secret_out, secret_bytes_out)<0) - goto error; - secret_len = secret_bytes_out; - - goto done; - error: - result = -1; - done: - crypto_log_errors(LOG_WARN, "completing DH handshake"); - if (pubkey_bn) - BN_clear_free(pubkey_bn); - if (secret_tmp) { - memwipe(secret_tmp, 0, secret_tmp_len); - tor_free(secret_tmp); - } - if (result < 0) - return result; - else - return secret_len; -} - -/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b> - * ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in - * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of - * H(K | [00]) | H(K | [01]) | .... - * - * This is the key expansion algorithm used in the "TAP" circuit extension - * mechanism; it shouldn't be used for new protocols. - * - * Return 0 on success, -1 on failure. - */ -int -crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, - uint8_t *key_out, size_t key_out_len) -{ - int i, r = -1; - uint8_t *cp, *tmp = tor_malloc(key_in_len+1); - uint8_t digest[DIGEST_LEN]; - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST_LEN*256); - - memcpy(tmp, key_in, key_in_len); - for (cp = key_out, i=0; cp < key_out+key_out_len; - ++i, cp += DIGEST_LEN) { - tmp[key_in_len] = i; - if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) - goto exit; - memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); - } - - r = 0; - exit: - memwipe(tmp, 0, key_in_len+1); - tor_free(tmp); - memwipe(digest, 0, sizeof(digest)); - return r; -} - -/** Expand some secret key material according to RFC5869, using SHA256 as the - * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the - * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the - * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" - * and "info" parameters respectively. On success, write <b>key_out_len</b> - * bytes to <b>key_out</b> and return 0. Assert on failure. - */ -int -crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len) -{ - uint8_t prk[DIGEST256_LEN]; - uint8_t tmp[DIGEST256_LEN + 128 + 1]; - uint8_t mac[DIGEST256_LEN]; - int i; - uint8_t *outp; - size_t tmp_len; - - crypto_hmac_sha256((char*)prk, - (const char*)salt_in, salt_in_len, - (const char*)key_in, key_in_len); - - /* If we try to get more than this amount of key data, we'll repeat blocks.*/ - tor_assert(key_out_len <= DIGEST256_LEN * 256); - tor_assert(info_in_len <= 128); - memset(tmp, 0, sizeof(tmp)); - outp = key_out; - i = 1; - - while (key_out_len) { - size_t n; - if (i > 1) { - memcpy(tmp, mac, DIGEST256_LEN); - memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); - tmp[DIGEST256_LEN+info_in_len] = i; - tmp_len = DIGEST256_LEN + info_in_len + 1; - } else { - memcpy(tmp, info_in, info_in_len); - tmp[info_in_len] = i; - tmp_len = info_in_len + 1; - } - crypto_hmac_sha256((char*)mac, - (const char*)prk, DIGEST256_LEN, - (const char*)tmp, tmp_len); - n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; - memcpy(outp, mac, n); - key_out_len -= n; - outp += n; - ++i; - } - - memwipe(tmp, 0, sizeof(tmp)); - memwipe(mac, 0, sizeof(mac)); - return 0; -} - -/** Free a DH key exchange object. - */ -void -crypto_dh_free_(crypto_dh_t *dh) -{ - if (!dh) - return; - tor_assert(dh->dh); - DH_free(dh->dh); - tor_free(dh); -} - -/** @{ */ -/** Uninitialize the crypto library. Return 0 on success. Does not detect - * failure. - */ -int -crypto_global_cleanup(void) -{ -#ifndef OPENSSL_1_1_API - EVP_cleanup(); -#endif -#ifndef NEW_THREAD_API - ERR_remove_thread_state(NULL); -#endif -#ifndef OPENSSL_1_1_API - ERR_free_strings(); -#endif - - if (dh_param_p) - BN_clear_free(dh_param_p); - if (dh_param_p_tls) - BN_clear_free(dh_param_p_tls); - if (dh_param_g) - BN_clear_free(dh_param_g); - - dh_param_p = dh_param_p_tls = dh_param_g = NULL; - -#ifndef DISABLE_ENGINES -#ifndef OPENSSL_1_1_API - ENGINE_cleanup(); -#endif -#endif - - CONF_modules_unload(1); -#ifndef OPENSSL_1_1_API - CRYPTO_cleanup_all_ex_data(); -#endif - - crypto_openssl_free_all(); - - crypto_early_initialized_ = 0; - crypto_global_initialized_ = 0; - have_seeded_siphash = 0; - siphash_unset_global_key(); - - return 0; -} - -/** @} */ - -#ifdef USE_DMALLOC -/** Tell the crypto library to use Tor's allocation functions rather than - * calling libc's allocation functions directly. Return 0 on success, -1 - * on failure. */ -int -crypto_use_tor_alloc_functions(void) -{ - int r = CRYPTO_set_mem_ex_functions(tor_malloc_, tor_realloc_, tor_free_); - return r ? 0 : -1; -} -#endif /* defined(USE_DMALLOC) */ - diff --git a/src/common/include.am b/src/common/include.am deleted file mode 100644 index cfaf993674..0000000000 --- a/src/common/include.am +++ /dev/null @@ -1,213 +0,0 @@ - -noinst_LIBRARIES += \ - src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a \ - src/common/libor-event.a - -if UNITTESTS_ENABLED -noinst_LIBRARIES += \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-crypto-testing.a \ - src/common/libor-event-testing.a -endif - -EXTRA_DIST += src/common/Makefile.nmake - -#CFLAGS = -Wall -Wpointer-arith -O2 -AM_CPPFLAGS += -I$(srcdir)/src/common -Isrc/common -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel - -if USE_OPENBSD_MALLOC -libor_extra_source=src/ext/OpenBSD_malloc_Linux.c -else -libor_extra_source= -endif - -src_common_libcurve25519_donna_a_CFLAGS= - -if BUILD_CURVE25519_DONNA -src_common_libcurve25519_donna_a_SOURCES=\ - src/ext/curve25519_donna/curve25519-donna.c -# See bug 13538 -- this code is known to have signed overflow issues. -src_common_libcurve25519_donna_a_CFLAGS+=\ - @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@ -noinst_LIBRARIES+=src/common/libcurve25519_donna.a -LIBDONNA=src/common/libcurve25519_donna.a -else -if BUILD_CURVE25519_DONNA_C64 -src_common_libcurve25519_donna_a_CFLAGS+=@CFLAGS_CONSTTIME@ -src_common_libcurve25519_donna_a_SOURCES=\ - src/ext/curve25519_donna/curve25519-donna-c64.c -noinst_LIBRARIES+=src/common/libcurve25519_donna.a -LIBDONNA=src/common/libcurve25519_donna.a -else -LIBDONNA= -endif -endif - -LIBDONNA += $(LIBED25519_REF10) -LIBDONNA += $(LIBED25519_DONNA) - -if THREADS_PTHREADS -threads_impl_source=src/common/compat_pthreads.c -endif -if THREADS_WIN32 -threads_impl_source=src/common/compat_winthreads.c -endif - -if BUILD_READPASSPHRASE_C -readpassphrase_source=src/ext/readpassphrase.c -else -readpassphrase_source= -endif - -if ADD_MULODI4 -mulodi4_source=src/ext/mulodi/mulodi4.c -else -mulodi4_source= -endif - -LIBOR_CTIME_A_SRC = \ - $(mulodi4_source) \ - src/ext/csiphash.c \ - src/common/di_ops.c - -src_common_libor_ctime_a_SOURCES = $(LIBOR_CTIME_A_SRC) -if UNITTESTS_ENABLED -src_common_libor_ctime_testing_a_SOURCES = $(LIBOR_CTIME_A_SRC) -else -src_common_libor_ctime_testing_a_SOURCES = -endif -src_common_libor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ -src_common_libor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) - -LIBOR_A_SRC = \ - src/common/address.c \ - src/common/address_set.c \ - src/common/backtrace.c \ - src/common/buffers.c \ - src/common/compat.c \ - src/common/compat_threads.c \ - src/common/compat_time.c \ - src/common/confline.c \ - src/common/container.c \ - src/common/log.c \ - src/common/memarea.c \ - src/common/pubsub.c \ - src/common/util.c \ - src/common/util_bug.c \ - src/common/util_format.c \ - src/common/util_process.c \ - src/common/sandbox.c \ - src/common/storagedir.c \ - src/common/token_bucket.c \ - src/common/workqueue.c \ - $(libor_extra_source) \ - $(threads_impl_source) \ - $(readpassphrase_source) - -src/common/src_common_libor_testing_a-log.$(OBJEXT) \ - src/common/log.$(OBJEXT): micro-revision.i - -LIBOR_CRYPTO_A_SRC = \ - src/common/aes.c \ - src/common/buffers_tls.c \ - src/common/compress.c \ - src/common/compress_lzma.c \ - src/common/compress_none.c \ - src/common/compress_zlib.c \ - src/common/compress_zstd.c \ - src/common/crypto.c \ - src/common/crypto_digest.c \ - src/common/crypto_format.c \ - src/common/crypto_openssl_mgt.c \ - src/common/crypto_pwbox.c \ - src/common/crypto_rand.c \ - src/common/crypto_rsa.c \ - src/common/crypto_s2k.c \ - src/common/crypto_util.c \ - src/common/tortls.c \ - src/common/crypto_curve25519.c \ - src/common/crypto_ed25519.c - -LIBOR_EVENT_A_SRC = \ - src/common/compat_libevent.c \ - src/common/procmon.c \ - src/common/timers.c \ - src/ext/timeouts/timeout.c - -src_common_libor_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) -src_common_libor_event_a_SOURCES = $(LIBOR_EVENT_A_SRC) - -if UNITTESTS_ENABLED -src_common_libor_testing_a_SOURCES = $(LIBOR_A_SRC) -src_common_libor_crypto_testing_a_SOURCES = $(LIBOR_CRYPTO_A_SRC) -src_common_libor_event_testing_a_SOURCES = $(LIBOR_EVENT_A_SRC) -else -src_common_libor_testing_a_SOURCES = -src_common_libor_crypto_testing_a_SOURCES = -src_common_libor_event_testing_a_SOURCES = -endif - -src_common_libor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_crypto_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_event_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_common_libor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_common_libor_crypto_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_common_libor_event_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) - -COMMONHEADERS = \ - src/common/address.h \ - src/common/address_set.h \ - src/common/backtrace.h \ - src/common/buffers.h \ - src/common/buffers_tls.h \ - src/common/aes.h \ - src/common/ciphers.inc \ - src/common/compat.h \ - src/common/compat_libevent.h \ - src/common/compat_openssl.h \ - src/common/compat_threads.h \ - src/common/compat_time.h \ - src/common/compress.h \ - src/common/compress_lzma.h \ - src/common/compress_none.h \ - src/common/compress_zlib.h \ - src/common/compress_zstd.h \ - src/common/confline.h \ - src/common/container.h \ - src/common/crypto.h \ - src/common/crypto_digest.h \ - src/common/crypto_curve25519.h \ - src/common/crypto_ed25519.h \ - src/common/crypto_format.h \ - src/common/crypto_openssl_mgt.h \ - src/common/crypto_pwbox.h \ - src/common/crypto_rand.h \ - src/common/crypto_rsa.h \ - src/common/crypto_s2k.h \ - src/common/crypto_util.h \ - src/common/di_ops.h \ - src/common/handles.h \ - src/common/memarea.h \ - src/common/linux_syscalls.inc \ - src/common/procmon.h \ - src/common/pubsub.h \ - src/common/sandbox.h \ - src/common/storagedir.h \ - src/common/testsupport.h \ - src/common/timers.h \ - src/common/token_bucket.h \ - src/common/torint.h \ - src/common/torlog.h \ - src/common/tortls.h \ - src/common/util.h \ - src/common/util_bug.h \ - src/common/util_format.h \ - src/common/util_process.h \ - src/common/workqueue.h - -noinst_HEADERS+= $(COMMONHEADERS) - diff --git a/src/common/pubsub.c b/src/common/pubsub.c deleted file mode 100644 index 336e8a6e7f..0000000000 --- a/src/common/pubsub.c +++ /dev/null @@ -1,129 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file pubsub.c - * - * \brief DOCDOC - */ - -#include "orconfig.h" -#include "pubsub.h" -#include "container.h" - -/** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping - * them sorted in priority order. */ -static void -subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s) -{ - int i; - smartlist_t *sl = topic->subscribers; - for (i = 0; i < smartlist_len(sl); ++i) { - pubsub_subscriber_t *other = smartlist_get(sl, i); - if (s->priority < other->priority) { - break; - } - } - smartlist_insert(sl, i, s); -} - -/** - * Add a new subscriber to <b>topic</b>, where (when an event is triggered), - * we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>. - * Return a handle to the subscribe which can later be passed to - * pubsub_unsubscribe_(). - * - * Functions are called in priority order, from lowest to highest. - * - * See pubsub.h for <b>subscribe_flags</b>. - */ -const pubsub_subscriber_t * -pubsub_subscribe_(pubsub_topic_t *topic, - pubsub_subscriber_fn_t fn, - void *subscriber_data, - unsigned subscribe_flags, - unsigned priority) -{ - tor_assert(! topic->locked); - if (subscribe_flags & SUBSCRIBE_ATSTART) { - tor_assert(topic->n_events_fired == 0); - } - pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r)); - r->priority = priority; - r->subscriber_flags = subscribe_flags; - r->fn = fn; - r->subscriber_data = subscriber_data; - if (topic->subscribers == NULL) { - topic->subscribers = smartlist_new(); - } - subscriber_insert(topic, r); - return r; -} - -/** - * Remove the subscriber <b>s</b> from <b>topic</b>. After calling this - * function, <b>s</b> may no longer be used. - */ -int -pubsub_unsubscribe_(pubsub_topic_t *topic, - const pubsub_subscriber_t *s) -{ - tor_assert(! topic->locked); - smartlist_t *sl = topic->subscribers; - if (sl == NULL) - return -1; - int i = smartlist_pos(sl, s); - if (i == -1) - return -1; - pubsub_subscriber_t *tmp = smartlist_get(sl, i); - tor_assert(tmp == s); - smartlist_del_keeporder(sl, i); - tor_free(tmp); - return 0; -} - -/** - * For every subscriber s in <b>topic</b>, invoke notify_fn on s and - * event_data. Return 0 if there were no nonzero return values, and -1 if - * there were any. - */ -int -pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, - void *event_data, unsigned notify_flags) -{ - tor_assert(! topic->locked); - (void) notify_flags; - smartlist_t *sl = topic->subscribers; - int n_bad = 0; - ++topic->n_events_fired; - if (sl == NULL) - return -1; - topic->locked = 1; - SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { - int r = notify_fn(s, event_data); - if (r != 0) - ++n_bad; - } SMARTLIST_FOREACH_END(s); - topic->locked = 0; - return (n_bad == 0) ? 0 : -1; -} - -/** - * Release all storage held by <b>topic</b>. - */ -void -pubsub_clear_(pubsub_topic_t *topic) -{ - tor_assert(! topic->locked); - - smartlist_t *sl = topic->subscribers; - if (sl == NULL) - return; - SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) { - tor_free(s); - } SMARTLIST_FOREACH_END(s); - smartlist_free(sl); - topic->subscribers = NULL; - topic->n_events_fired = 0; -} - diff --git a/src/common/pubsub.h b/src/common/pubsub.h deleted file mode 100644 index 2bee3af085..0000000000 --- a/src/common/pubsub.h +++ /dev/null @@ -1,179 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file pubsub.h - * \brief Macros to implement publish/subscribe abstractions. - * - * To use these macros, call DECLARE_PUBSUB_TOPIC() with an identifier to use - * as your topic. Below, I'm going to assume you say DECLARE_PUBSUB_TOPIC(T). - * - * Doing this will declare the following types: - * typedef struct T_event_data_t T_event_data_t; // you define this struct - * typedef struct T_subscriber_data_t T_subscriber_data_t; // this one too. - * typedef struct T_subscriber_t T_subscriber_t; // opaque - * typedef int (*T_subscriber_fn_t)(T_event_data_t*, T_subscriber_data_t*); - * - * and it will declare the following functions: - * const T_subscriber_t *T_subscribe(T_subscriber_fn_t, - * T_subscriber_data_t *, - * unsigned flags, - * unsigned priority); - * int T_unsubscribe(const T_subscriber_t *) - * - * Elsewhere you can say DECLARE_NOTIFY_PUBSUB_TOPIC(static, T), which - * declares: - * - * static int T_notify(T_event_data_t *, unsigned notify_flags); - * static void T_clear(void); - * - * And in some C file, you would define these functions with: - * IMPLEMENT_PUBSUB_TOPIC(static, T). - * - * The implementations will be small typesafe wrappers over generic versions - * of the above functions. - * - * To use the typesafe functions, you add any number of subscribers with - * T_subscribe(). Each has an associated function pointer, data pointer, - * and priority. Later, you can invoke T_notify() to declare that the - * event has occurred. Each of the subscribers will be invoked once. - **/ - -#ifndef TOR_PUBSUB_H -#define TOR_PUBSUB_H - -#include "torint.h" - -/** - * Flag for T_subscribe: die with an assertion failure if the event - * have ever been published before. Used when a subscriber must absolutely - * never have missed an event. - */ -#define SUBSCRIBE_ATSTART (1u<<0) - -#define DECLARE_PUBSUB_STRUCT_TYPES(name) \ - /* You define this type. */ \ - typedef struct name ## _event_data_t name ## _event_data_t; \ - /* You define this type. */ \ - typedef struct name ## _subscriber_data_t name ## _subscriber_data_t; - -#define DECLARE_PUBSUB_TOPIC(name) \ - /* This type is opaque. */ \ - typedef struct name ## _subscriber_t name ## _subscriber_t; \ - /* You declare functions matching this type. */ \ - typedef int (*name ## _subscriber_fn_t)( \ - name ## _event_data_t *data, \ - name ## _subscriber_data_t *extra); \ - /* Call this function to subscribe to a topic. */ \ - const name ## _subscriber_t *name ## _subscribe( \ - name##_subscriber_fn_t subscriber, \ - name##_subscriber_data_t *extra_data, \ - unsigned flags, \ - unsigned priority); \ - /* Call this function to unsubscribe from a topic. */ \ - int name ## _unsubscribe(const name##_subscriber_t *s); - -#define DECLARE_NOTIFY_PUBSUB_TOPIC(linkage, name) \ - /* Call this function to notify all subscribers. Flags not yet used. */ \ - linkage int name ## _notify(name ## _event_data_t *data, unsigned flags); \ - /* Call this function to release storage held by the topic. */ \ - linkage void name ## _clear(void); - -/** - * Type used to hold a generic function for a subscriber. - * - * [Yes, it is safe to cast to this, so long as we cast back to the original - * type before calling. From C99: "A pointer to a function of one type may be - * converted to a pointer to a function of another type and back again; the - * result shall compare equal to the original pointer."] -*/ -typedef int (*pubsub_subscriber_fn_t)(void *, void *); - -/** - * Helper type to implement pubsub abstraction. Don't use this directly. - * It represents a subscriber. - */ -typedef struct pubsub_subscriber_t { - /** Function to invoke when the event triggers. */ - pubsub_subscriber_fn_t fn; - /** Data associated with this subscriber. */ - void *subscriber_data; - /** Priority for this subscriber. Low priorities happen first. */ - unsigned priority; - /** Flags set on this subscriber. Not yet used.*/ - unsigned subscriber_flags; -} pubsub_subscriber_t; - -/** - * Helper type to implement pubsub abstraction. Don't use this directly. - * It represents a topic, and keeps a record of subscribers. - */ -typedef struct pubsub_topic_t { - /** List of subscribers to this topic. May be NULL. */ - struct smartlist_t *subscribers; - /** Total number of times that pubsub_notify_() has ever been called on this - * topic. */ - uint64_t n_events_fired; - /** True iff we're running 'notify' on this topic, and shouldn't allow - * any concurrent modifications or events. */ - unsigned locked; -} pubsub_topic_t; - -const pubsub_subscriber_t *pubsub_subscribe_(pubsub_topic_t *topic, - pubsub_subscriber_fn_t fn, - void *subscriber_data, - unsigned subscribe_flags, - unsigned priority); -int pubsub_unsubscribe_(pubsub_topic_t *topic, const pubsub_subscriber_t *sub); -void pubsub_clear_(pubsub_topic_t *topic); -typedef int (*pubsub_notify_fn_t)(pubsub_subscriber_t *subscriber, - void *notify_data); -int pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn, - void *notify_data, unsigned notify_flags); - -#define IMPLEMENT_PUBSUB_TOPIC(notify_linkage, name) \ - static pubsub_topic_t name ## _topic_ = { NULL, 0, 0 }; \ - const name ## _subscriber_t * \ - name ## _subscribe(name##_subscriber_fn_t subscriber, \ - name##_subscriber_data_t *extra_data, \ - unsigned flags, \ - unsigned priority) \ - { \ - const pubsub_subscriber_t *s; \ - s = pubsub_subscribe_(&name##_topic_, \ - (pubsub_subscriber_fn_t)subscriber, \ - extra_data, \ - flags, \ - priority); \ - return (const name##_subscriber_t *)s; \ - } \ - int \ - name ## _unsubscribe(const name##_subscriber_t *subscriber) \ - { \ - return pubsub_unsubscribe_(&name##_topic_, \ - (const pubsub_subscriber_t *)subscriber); \ - } \ - static int \ - name##_call_the_notify_fn_(pubsub_subscriber_t *subscriber, \ - void *notify_data) \ - { \ - name ## _subscriber_fn_t fn; \ - fn = (name ## _subscriber_fn_t) subscriber->fn; \ - return fn(notify_data, subscriber->subscriber_data); \ - } \ - notify_linkage int \ - name ## _notify(name ## _event_data_t *event_data, unsigned flags) \ - { \ - return pubsub_notify_(&name##_topic_, \ - name##_call_the_notify_fn_, \ - event_data, \ - flags); \ - } \ - notify_linkage void \ - name ## _clear(void) \ - { \ - pubsub_clear_(&name##_topic_); \ - } - -#endif /* !defined(TOR_PUBSUB_H) */ - diff --git a/src/common/torint.h b/src/common/torint.h deleted file mode 100644 index fc7818fe2c..0000000000 --- a/src/common/torint.h +++ /dev/null @@ -1,379 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file torint.h - * \brief Header file to define uint32_t and friends - **/ - -#ifndef TOR_TORINT_H -#define TOR_TORINT_H - -#include "orconfig.h" - -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_LIMITS_H -#include <limits.h> -#endif -#ifdef HAVE_SYS_LIMITS_H -#include <sys/limits.h> -#endif -#ifdef HAVE_MACHINE_LIMITS_H -#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) - /* FreeBSD has a bug where it complains that this file is obsolete, - and I should migrate to using sys/limits. It complains even when - I include both. - __FreeBSD_kernel__ is defined by Debian GNU/kFreeBSD which - does the same thing (but doesn't defined __FreeBSD__). - */ -#include <machine/limits.h> -#endif /* !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */ -#endif /* defined(HAVE_MACHINE_LIMITS_H) */ -#ifdef HAVE_INTTYPES_H -#include <inttypes.h> -#endif - -#include <stdbool.h> - -#if (SIZEOF_INT8_T != 0) -#define HAVE_INT8_T -#endif -#if (SIZEOF_INT16_T != 0) -#define HAVE_INT16_T -#endif -#if (SIZEOF_INT32_T != 0) -#define HAVE_INT32_T -#endif -#if (SIZEOF_INT64_T != 0) -#define HAVE_INT64_T -#endif -#if (SIZEOF_UINT8_T != 0) -#define HAVE_UINT8_T -#endif -#if (SIZEOF_UINT16_T != 0) -#define HAVE_UINT16_T -#endif -#if (SIZEOF_UINT32_T != 0) -#define HAVE_UINT32_T -#endif -#if (SIZEOF_UINT64_T != 0) -#define HAVE_UINT64_T -#endif -#if (SIZEOF_INTPTR_T != 0) -#define HAVE_INTPTR_T -#endif -#if (SIZEOF_UINTPTR_T != 0) -#define HAVE_UINTPTR_T -#endif - -#if (SIZEOF_CHAR == 1) -#ifndef HAVE_INT8_T -typedef signed char int8_t; -#define HAVE_INT8_T -#endif -#ifndef HAVE_UINT8_T -typedef unsigned char uint8_t; -#define HAVE_UINT8_T -#endif -#endif /* (SIZEOF_CHAR == 1) */ - -#if (SIZEOF_SHORT == 2) -#ifndef HAVE_INT16_T -typedef signed short int16_t; -#define HAVE_INT16_T -#endif -#ifndef HAVE_UINT16_T -typedef unsigned short uint16_t; -#define HAVE_UINT16_T -#endif -#endif /* (SIZEOF_SHORT == 2) */ - -#if (SIZEOF_INT == 2) -#ifndef HAVE_INT16_T -typedef signed int int16_t; -#define HAVE_INT16_T -#endif -#ifndef HAVE_UINT16_T -typedef unsigned int uint16_t; -#define HAVE_UINT16_T -#endif -#elif (SIZEOF_INT == 4) -#ifndef HAVE_INT32_T -typedef signed int int32_t; -#define HAVE_INT32_T -#endif -#ifndef HAVE_UINT32_T -typedef unsigned int uint32_t; -#define HAVE_UINT32_T -#endif -#ifndef UINT16_MAX -#define UINT16_MAX 0xffffu -#endif -#ifndef INT16_MAX -#define INT16_MAX 0x7fff -#endif -#ifndef INT16_MIN -#define INT16_MIN (-INT16_MAX-1) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX 0xffffffffu -#endif -#ifndef INT32_MAX -#define INT32_MAX 0x7fffffff -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#endif /* (SIZEOF_INT == 2) || ... */ - -#if (SIZEOF_LONG == 4) -#ifndef HAVE_INT32_T -typedef signed long int32_t; -#define HAVE_INT32_T -#endif -#ifndef HAVE_UINT32_T -typedef unsigned long uint32_t; -#define HAVE_UINT32_T -#ifndef UINT32_MAX -#define UINT32_MAX 0xfffffffful -#endif -#endif /* !defined(HAVE_UINT32_T) */ -#elif (SIZEOF_LONG == 8) -#ifndef HAVE_INT64_T -typedef signed long int64_t; -#define HAVE_INT64_T -#endif -#ifndef HAVE_UINT32_T -typedef unsigned long uint64_t; -#define HAVE_UINT32_T -#endif -#ifndef UINT64_MAX -#define UINT64_MAX 0xfffffffffffffffful -#endif -#endif /* (SIZEOF_LONG == 4) || ... */ - -#if (SIZEOF_LONG_LONG == 8) -#ifndef HAVE_INT64_T -typedef signed long long int64_t; -#define HAVE_INT64_T -#endif -#ifndef HAVE_UINT64_T -typedef unsigned long long uint64_t; -#define HAVE_UINT64_T -#endif -#ifndef UINT64_MAX -#define UINT64_MAX 0xffffffffffffffffull -#endif -#ifndef INT64_MAX -#define INT64_MAX 0x7fffffffffffffffll -#endif -#endif /* (SIZEOF_LONG_LONG == 8) */ - -#if (SIZEOF___INT64 == 8) -#ifndef HAVE_INT64_T -typedef signed __int64 int64_t; -#define HAVE_INT64_T -#endif -#ifndef HAVE_UINT64_T -typedef unsigned __int64 uint64_t; -#define HAVE_UINT64_T -#endif -#ifndef UINT64_MAX -#define UINT64_MAX 0xffffffffffffffffui64 -#endif -#ifndef INT64_MAX -#define INT64_MAX 0x7fffffffffffffffi64 -#endif -#endif /* (SIZEOF___INT64 == 8) */ - -#ifndef INT64_MIN -#define INT64_MIN ((- INT64_MAX) - 1) -#endif - -#ifndef SIZE_MAX -#if SIZEOF_SIZE_T == 8 -#define SIZE_MAX UINT64_MAX -#elif SIZEOF_SIZE_T == 4 -#define SIZE_MAX UINT32_MAX -#else -#error "Can't define SIZE_MAX" -#endif /* SIZEOF_SIZE_T == 8 || ... */ -#endif /* !defined(SIZE_MAX) */ - -#ifndef HAVE_SSIZE_T -#if SIZEOF_SIZE_T == 8 -typedef int64_t ssize_t; -#elif SIZEOF_SIZE_T == 4 -typedef int32_t ssize_t; -#else -#error "Can't define ssize_t." -#endif /* SIZEOF_SIZE_T == 8 || ... */ -#endif /* !defined(HAVE_SSIZE_T) */ - -#if (SIZEOF_VOID_P > 4 && SIZEOF_VOID_P <= 8) -#ifndef HAVE_INTPTR_T -typedef int64_t intptr_t; -#define SIZEOF_INTPTR_T 8 -#endif -#ifndef HAVE_UINTPTR_T -typedef uint64_t uintptr_t; -#define SIZEOF_UINTPTR_T 8 -#endif -#elif (SIZEOF_VOID_P > 2 && SIZEOF_VOID_P <= 4) -#ifndef HAVE_INTPTR_T -typedef int32_t intptr_t; -#define SIZEOF_INTPTR_T 4 -#endif -#ifndef HAVE_UINTPTR_T -typedef uint32_t uintptr_t; -#define SIZEOF_UINTPTR_T 4 -#endif -#else -#error "void * is either >8 bytes or <= 2. In either case, I am confused." -#endif /* (SIZEOF_VOID_P > 4 && SIZEOF_VOID_P <= 8) || ... */ - -#ifndef HAVE_INT8_T -#error "Missing type int8_t" -#endif -#ifndef HAVE_UINT8_T -#error "Missing type uint8_t" -#endif -#ifndef HAVE_INT16_T -#error "Missing type int16_t" -#endif -#ifndef HAVE_UINT16_T -#error "Missing type uint16_t" -#endif -#ifndef HAVE_INT32_T -#error "Missing type int32_t" -#endif -#ifndef HAVE_UINT32_T -#error "Missing type uint32_t" -#endif -#ifndef HAVE_INT64_T -#error "Missing type int64_t" -#endif -#ifndef HAVE_UINT64_T -#error "Missing type uint64_t" -#endif - -/* This assumes a sane (2's-complement) representation. But if you - * aren't 2's complement, and you don't define LONG_MAX, then you're so - * bizarre that I want nothing to do with you. */ -#ifndef USING_TWOS_COMPLEMENT -#error "Seems that your platform doesn't use 2's complement arithmetic. Argh." -#endif -#ifndef LONG_MAX -#if (SIZEOF_LONG == 4) -#define LONG_MAX 0x7fffffffL -#elif (SIZEOF_LONG == 8) -#define LONG_MAX 0x7fffffffffffffffL -#else -#error "Can't define LONG_MAX" -#endif /* (SIZEOF_LONG == 4) || ... */ -#endif /* !defined(LONG_MAX) */ - -#ifndef INT_MAX -#if (SIZEOF_INT == 4) -#define INT_MAX 0x7fffffffL -#elif (SIZEOF_INT == 8) -#define INT_MAX 0x7fffffffffffffffL -#else -#error "Can't define INT_MAX" -#endif /* (SIZEOF_INT == 4) || ... */ -#endif /* !defined(INT_MAX) */ - -#ifndef UINT_MAX -#if (SIZEOF_INT == 2) -#define UINT_MAX 0xffffu -#elif (SIZEOF_INT == 4) -#define UINT_MAX 0xffffffffu -#elif (SIZEOF_INT == 8) -#define UINT_MAX 0xffffffffffffffffu -#else -#error "Can't define UINT_MAX" -#endif /* (SIZEOF_INT == 2) || ... */ -#endif /* !defined(UINT_MAX) */ - -#ifndef SHORT_MAX -#if (SIZEOF_SHORT == 2) -#define SHORT_MAX 0x7fff -#elif (SIZEOF_SHORT == 4) -#define SHORT_MAX 0x7fffffff -#else -#error "Can't define SHORT_MAX" -#endif /* (SIZEOF_SHORT == 2) || ... */ -#endif /* !defined(SHORT_MAX) */ - -#ifndef TIME_MAX - -#if (SIZEOF_TIME_T == SIZEOF_INT) -#define TIME_MAX ((time_t)INT_MAX) -#elif (SIZEOF_TIME_T == SIZEOF_LONG) -#define TIME_MAX ((time_t)LONG_MAX) -#elif (SIZEOF_TIME_T == 8) -#define TIME_MAX ((time_t)INT64_MAX) -#else -#error "Can't define TIME_MAX" -#endif /* (SIZEOF_TIME_T == SIZEOF_INT) || ... */ - -#endif /* !defined(TIME_MAX) */ - -#ifndef TIME_MIN - -#if (SIZEOF_TIME_T == SIZEOF_INT) -#define TIME_MIN ((time_t)INT_MIN) -#elif (SIZEOF_TIME_T == SIZEOF_LONG) -#define TIME_MIN ((time_t)LONG_MIN) -#elif (SIZEOF_TIME_T == 8) -#define TIME_MIN ((time_t)INT64_MIN) -#else -#error "Can't define TIME_MIN" -#endif /* (SIZEOF_TIME_T == SIZEOF_INT) || ... */ - -#endif /* !defined(TIME_MIN) */ - -#ifndef SIZE_MAX -#if (SIZEOF_SIZE_T == 4) -#define SIZE_MAX UINT32_MAX -#elif (SIZEOF_SIZE_T == 8) -#define SIZE_MAX UINT64_MAX -#else -#error "Can't define SIZE_MAX" -#endif /* (SIZEOF_SIZE_T == 4) || ... */ -#endif /* !defined(SIZE_MAX) */ - -#ifdef _WIN32 -# ifdef _WIN64 -# define TOR_PRIuSZ PRIu64 -# else -# define TOR_PRIuSZ PRIu32 -# endif -#else -# define TOR_PRIuSZ "zu" -#endif - -#ifndef SSIZE_MAX -#if (SIZEOF_SIZE_T == 4) -#define SSIZE_MAX INT32_MAX -#elif (SIZEOF_SIZE_T == 8) -#define SSIZE_MAX INT64_MAX -#else -#error "Can't define SSIZE_MAX" -#endif /* (SIZEOF_SIZE_T == 4) || ... */ -#endif /* !defined(SSIZE_MAX) */ - -/** Any ssize_t larger than this amount is likely to be an underflow. */ -#define SSIZE_T_CEILING ((ssize_t)(SSIZE_MAX-16)) -/** Any size_t larger than this amount is likely to be an underflow. */ -#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16)) - -#endif /* !defined(TOR_TORINT_H) */ - diff --git a/src/common/util.c b/src/common/util.c deleted file mode 100644 index dece5877f1..0000000000 --- a/src/common/util.c +++ /dev/null @@ -1,5378 +0,0 @@ -/* Copyright (c) 2003, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util.c - * \brief Common functions for strings, IO, network, data structures, - * process control. - **/ - -#include "orconfig.h" -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#define UTIL_PRIVATE -#include "util.h" -#include "torlog.h" -#include "crypto_digest.h" -#include "torint.h" -#include "container.h" -#include "address.h" -#include "sandbox.h" -#include "backtrace.h" -#include "util_process.h" -#include "util_format.h" - -#ifdef _WIN32 -#include <io.h> -#include <direct.h> -#include <process.h> -#include <tchar.h> -#include <winbase.h> -#else /* !(defined(_WIN32)) */ -#include <dirent.h> -#include <pwd.h> -#include <grp.h> -#endif /* defined(_WIN32) */ - -/* math.h needs this on Linux */ -#ifndef _USE_ISOC99_ -#define _USE_ISOC99_ 1 -#endif -#include <math.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <signal.h> - -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#ifdef HAVE_MALLOC_MALLOC_H -#include <malloc/malloc.h> -#endif -#ifdef HAVE_MALLOC_H -#if !defined(OpenBSD) && !defined(__FreeBSD__) -/* OpenBSD has a malloc.h, but for our purposes, it only exists in order to - * scold us for being so stupid as to autodetect its presence. To be fair, - * they've done this since 1996, when autoconf was only 5 years old. */ -#include <malloc.h> -#endif /* !defined(OpenBSD) && !defined(__FreeBSD__) */ -#endif /* defined(HAVE_MALLOC_H) */ -#ifdef HAVE_MALLOC_NP_H -#include <malloc_np.h> -#endif -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) -#include <sys/prctl.h> -#endif - -#ifdef __clang_analyzer__ -#undef MALLOC_ZERO_WORKS -#endif - -/* ===== - * Memory management - * ===== */ -#ifdef USE_DMALLOC - #undef strndup - #include <dmalloc.h> - /* Macro to pass the extra dmalloc args to another function. */ - #define DMALLOC_FN_ARGS , file, line - - #if defined(HAVE_DMALLOC_STRDUP) - /* the dmalloc_strdup should be fine as defined */ - #elif defined(HAVE_DMALLOC_STRNDUP) - #define dmalloc_strdup(file, line, string, xalloc_b) \ - dmalloc_strndup(file, line, (string), -1, xalloc_b) - #else - #error "No dmalloc_strdup or equivalent" -#endif /* defined(HAVE_DMALLOC_STRDUP) || ... */ - -#else /* !(defined(USE_DMALLOC)) */ - - #define DMALLOC_FN_ARGS -#endif /* defined(USE_DMALLOC) */ - -/** Allocate a chunk of <b>size</b> bytes of memory, and return a pointer to - * result. On error, log and terminate the process. (Same as malloc(size), - * but never returns NULL.) - * - * <b>file</b> and <b>line</b> are used if dmalloc is enabled, and - * ignored otherwise. - */ -void * -tor_malloc_(size_t size DMALLOC_PARAMS) -{ - void *result; - - tor_assert(size < SIZE_T_CEILING); - -#ifndef MALLOC_ZERO_WORKS - /* Some libc mallocs don't work when size==0. Override them. */ - if (size==0) { - size=1; - } -#endif /* !defined(MALLOC_ZERO_WORKS) */ - -#ifdef USE_DMALLOC - result = dmalloc_malloc(file, line, size, DMALLOC_FUNC_MALLOC, 0, 0); -#else - result = raw_malloc(size); -#endif - - if (PREDICT_UNLIKELY(result == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on malloc(). Dying."); - /* If these functions die within a worker process, they won't call - * spawn_exit, but that's ok, since the parent will run out of memory soon - * anyway. */ - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return result; -} - -/** Allocate a chunk of <b>size</b> bytes of memory, fill the memory with - * zero bytes, and return a pointer to the result. Log and terminate - * the process on error. (Same as calloc(size,1), but never returns NULL.) - */ -void * -tor_malloc_zero_(size_t size DMALLOC_PARAMS) -{ - /* You may ask yourself, "wouldn't it be smart to use calloc instead of - * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick - * we don't!" Indeed it does, but its optimizations are only a big win when - * we're allocating something very big (it knows if it just got the memory - * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero - * for big stuff, so we don't bother with calloc. */ - void *result = tor_malloc_(size DMALLOC_FN_ARGS); - memset(result, 0, size); - return result; -} - -/* The square root of SIZE_MAX + 1. If a is less than this, and b is less - * than this, then a*b is less than SIZE_MAX. (For example, if size_t is - * 32 bits, then SIZE_MAX is 0xffffffff and this value is 0x10000. If a and - * b are less than this, then their product is at most (65535*65535) == - * 0xfffe0001. */ -#define SQRT_SIZE_MAX_P1 (((size_t)1) << (sizeof(size_t)*4)) - -/** Return non-zero if and only if the product of the arguments is exact, - * and cannot overflow. */ -int -size_mul_check(const size_t x, const size_t y) -{ - /* This first check is equivalent to - (x < SQRT_SIZE_MAX_P1 && y < SQRT_SIZE_MAX_P1) - - Rationale: if either one of x or y is >= SQRT_SIZE_MAX_P1, then it - will have some bit set in its most significant half. - */ - return ((x|y) < SQRT_SIZE_MAX_P1 || - y == 0 || - x <= SIZE_MAX / y); -} - -/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill - * the memory with zero bytes, and return a pointer to the result. - * Log and terminate the process on error. (Same as - * calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.) - * The second argument (<b>size</b>) should preferably be non-zero - * and a compile-time constant. - */ -void * -tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) -{ - tor_assert(size_mul_check(nmemb, size)); - return tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS); -} - -/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b> - * bytes long; return the new memory block. On error, log and - * terminate. (Like realloc(ptr,size), but never returns NULL.) - */ -void * -tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS) -{ - void *result; - - tor_assert(size < SIZE_T_CEILING); - -#ifndef MALLOC_ZERO_WORKS - /* Some libc mallocs don't work when size==0. Override them. */ - if (size==0) { - size=1; - } -#endif /* !defined(MALLOC_ZERO_WORKS) */ - -#ifdef USE_DMALLOC - result = dmalloc_realloc(file, line, ptr, size, DMALLOC_FUNC_REALLOC, 0); -#else - result = raw_realloc(ptr, size); -#endif - - if (PREDICT_UNLIKELY(result == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on realloc(). Dying."); - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return result; -} - -/** - * Try to realloc <b>ptr</b> so that it takes up sz1 * sz2 bytes. Check for - * overflow. Unlike other allocation functions, return NULL on overflow. - */ -void * -tor_reallocarray_(void *ptr, size_t sz1, size_t sz2 DMALLOC_PARAMS) -{ - /* XXXX we can make this return 0, but we would need to check all the - * reallocarray users. */ - tor_assert(size_mul_check(sz1, sz2)); - - return tor_realloc(ptr, (sz1 * sz2) DMALLOC_FN_ARGS); -} - -/** Return a newly allocated copy of the NUL-terminated string s. On - * error, log and terminate. (Like strdup(s), but never returns - * NULL.) - */ -char * -tor_strdup_(const char *s DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(s); - -#ifdef USE_DMALLOC - duplicate = dmalloc_strdup(file, line, s, 0); -#else - duplicate = raw_strdup(s); -#endif - if (PREDICT_UNLIKELY(duplicate == NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_MM,"Out of memory on strdup(). Dying."); - exit(1); // exit ok: alloc failed. - /* LCOV_EXCL_STOP */ - } - return duplicate; -} - -/** Allocate and return a new string containing the first <b>n</b> - * characters of <b>s</b>. If <b>s</b> is longer than <b>n</b> - * characters, only the first <b>n</b> are copied. The result is - * always NUL-terminated. (Like strndup(s,n), but never returns - * NULL.) - */ -char * -tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(s); - tor_assert(n < SIZE_T_CEILING); - duplicate = tor_malloc_((n+1) DMALLOC_FN_ARGS); - /* Performance note: Ordinarily we prefer strlcpy to strncpy. But - * this function gets called a whole lot, and platform strncpy is - * much faster than strlcpy when strlen(s) is much longer than n. - */ - strncpy(duplicate, s, n); - duplicate[n]='\0'; - return duplicate; -} - -/** Allocate a chunk of <b>len</b> bytes, with the same contents as the - * <b>len</b> bytes starting at <b>mem</b>. */ -void * -tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(len < SIZE_T_CEILING); - tor_assert(mem); - duplicate = tor_malloc_(len DMALLOC_FN_ARGS); - memcpy(duplicate, mem, len); - return duplicate; -} - -/** As tor_memdup(), but add an extra 0 byte at the end of the resulting - * memory. */ -void * -tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) -{ - char *duplicate; - tor_assert(len < SIZE_T_CEILING+1); - tor_assert(mem); - duplicate = tor_malloc_(len+1 DMALLOC_FN_ARGS); - memcpy(duplicate, mem, len); - duplicate[len] = '\0'; - return duplicate; -} - -/** Helper for places that need to take a function pointer to the right - * spelling of "free()". */ -void -tor_free_(void *mem) -{ - tor_free(mem); -} - -DISABLE_GCC_WARNING(aggregate-return) -/** Call the platform malloc info function, and dump the results to the log at - * level <b>severity</b>. If no such function exists, do nothing. */ -void -tor_log_mallinfo(int severity) -{ -#ifdef HAVE_MALLINFO - struct mallinfo mi; - memset(&mi, 0, sizeof(mi)); - mi = mallinfo(); - tor_log(severity, LD_MM, - "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, " - "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, " - "keepcost=%d", - mi.arena, mi.ordblks, mi.smblks, mi.hblks, - mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks, - mi.keepcost); -#else /* !(defined(HAVE_MALLINFO)) */ - (void)severity; -#endif /* defined(HAVE_MALLINFO) */ -#ifdef USE_DMALLOC - dmalloc_log_changed(0, /* Since the program started. */ - 1, /* Log info about non-freed pointers. */ - 0, /* Do not log info about freed pointers. */ - 0 /* Do not log individual pointers. */ - ); -#endif /* defined(USE_DMALLOC) */ -} -ENABLE_GCC_WARNING(aggregate-return) - -/* ===== - * Math - * ===== */ - -/** - * Returns the natural logarithm of d base e. We defined this wrapper here so - * to avoid conflicts with old versions of tor_log(), which were named log(). - */ -double -tor_mathlog(double d) -{ - return log(d); -} - -/** Return the long integer closest to <b>d</b>. We define this wrapper - * here so that not all users of math.h need to use the right incantations - * to get the c99 functions. */ -long -tor_lround(double d) -{ -#if defined(HAVE_LROUND) - return lround(d); -#elif defined(HAVE_RINT) - return (long)rint(d); -#else - return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); -#endif /* defined(HAVE_LROUND) || ... */ -} - -/** Return the 64-bit integer closest to d. We define this wrapper here so - * that not all users of math.h need to use the right incantations to get the - * c99 functions. */ -int64_t -tor_llround(double d) -{ -#if defined(HAVE_LLROUND) - return (int64_t)llround(d); -#elif defined(HAVE_RINT) - return (int64_t)rint(d); -#else - return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5)); -#endif /* defined(HAVE_LLROUND) || ... */ -} - -/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */ -int -tor_log2(uint64_t u64) -{ - int r = 0; - if (u64 >= (U64_LITERAL(1)<<32)) { - u64 >>= 32; - r = 32; - } - if (u64 >= (U64_LITERAL(1)<<16)) { - u64 >>= 16; - r += 16; - } - if (u64 >= (U64_LITERAL(1)<<8)) { - u64 >>= 8; - r += 8; - } - if (u64 >= (U64_LITERAL(1)<<4)) { - u64 >>= 4; - r += 4; - } - if (u64 >= (U64_LITERAL(1)<<2)) { - u64 >>= 2; - r += 2; - } - if (u64 >= (U64_LITERAL(1)<<1)) { - // u64 >>= 1; // not using this any more. - r += 1; - } - return r; -} - -/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If - * there are two powers of 2 equally close, round down. */ -uint64_t -round_to_power_of_2(uint64_t u64) -{ - int lg2; - uint64_t low; - uint64_t high; - if (u64 == 0) - return 1; - - lg2 = tor_log2(u64); - low = U64_LITERAL(1) << lg2; - - if (lg2 == 63) - return low; - - high = U64_LITERAL(1) << (lg2+1); - if (high - u64 < u64 - low) - return high; - else - return low; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as an unsigned, return - * UINT_MAX. Asserts if divisor is zero. */ -unsigned -round_to_next_multiple_of(unsigned number, unsigned divisor) -{ - tor_assert(divisor > 0); - if (UINT_MAX - divisor + 1 < number) - return UINT_MAX; - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as a uint32_t, return - * UINT32_MAX. Asserts if divisor is zero. */ -uint32_t -round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor) -{ - tor_assert(divisor > 0); - if (UINT32_MAX - divisor + 1 < number) - return UINT32_MAX; - - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Return the lowest x such that x is at least <b>number</b>, and x modulo - * <b>divisor</b> == 0. If no such x can be expressed as a uint64_t, return - * UINT64_MAX. Asserts if divisor is zero. */ -uint64_t -round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) -{ - tor_assert(divisor > 0); - if (UINT64_MAX - divisor + 1 < number) - return UINT64_MAX; - number += divisor - 1; - number -= number % divisor; - return number; -} - -/** Transform a random value <b>p</b> from the uniform distribution in - * [0.0, 1.0[ into a Laplace distributed value with location parameter - * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result - * to be an integer in [INT64_MIN, INT64_MAX]. */ -int64_t -sample_laplace_distribution(double mu, double b, double p) -{ - double result; - tor_assert(p >= 0.0 && p < 1.0); - - /* This is the "inverse cumulative distribution function" from: - * http://en.wikipedia.org/wiki/Laplace_distribution */ - if (p <= 0.0) { - /* Avoid taking log(0.0) == -INFINITY, as some processors or compiler - * options can cause the program to trap. */ - return INT64_MIN; - } - - result = mu - b * (p > 0.5 ? 1.0 : -1.0) - * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); - - return clamp_double_to_int64(result); -} - -/** Add random noise between INT64_MIN and INT64_MAX coming from a Laplace - * distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b> to - * <b>signal</b> based on the provided <b>random</b> value in [0.0, 1.0[. - * The epsilon value must be between ]0.0, 1.0]. delta_f must be greater - * than 0. */ -int64_t -add_laplace_noise(int64_t signal_, double random_, double delta_f, - double epsilon) -{ - int64_t noise; - - /* epsilon MUST be between ]0.0, 1.0] */ - tor_assert(epsilon > 0.0 && epsilon <= 1.0); - /* delta_f MUST be greater than 0. */ - tor_assert(delta_f > 0.0); - - /* Just add noise, no further signal */ - noise = sample_laplace_distribution(0.0, - delta_f / epsilon, - random_); - - /* Clip (signal + noise) to [INT64_MIN, INT64_MAX] */ - if (noise > 0 && INT64_MAX - noise < signal_) - return INT64_MAX; - else if (noise < 0 && INT64_MIN - noise > signal_) - return INT64_MIN; - else - return signal_ + noise; -} - -/* Helper: safely add two uint32_t's, capping at UINT32_MAX rather - * than overflow */ -uint32_t -tor_add_u32_nowrap(uint32_t a, uint32_t b) -{ - /* a+b > UINT32_MAX check, without overflow */ - if (PREDICT_UNLIKELY(a > UINT32_MAX - b)) { - return UINT32_MAX; - } else { - return a+b; - } -} - -/* Helper: return greatest common divisor of a,b */ -static uint64_t -gcd64(uint64_t a, uint64_t b) -{ - while (b) { - uint64_t t = b; - b = a % b; - a = t; - } - return a; -} - -/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it. - * Requires that the denominator is greater than 0. */ -void -simplify_fraction64(uint64_t *numer, uint64_t *denom) -{ - tor_assert(denom); - uint64_t gcd = gcd64(*numer, *denom); - *numer /= gcd; - *denom /= gcd; -} - -/** Return the number of bits set in <b>v</b>. */ -int -n_bits_set_u8(uint8_t v) -{ - static const int nybble_table[] = { - 0, /* 0000 */ - 1, /* 0001 */ - 1, /* 0010 */ - 2, /* 0011 */ - 1, /* 0100 */ - 2, /* 0101 */ - 2, /* 0110 */ - 3, /* 0111 */ - 1, /* 1000 */ - 2, /* 1001 */ - 2, /* 1010 */ - 3, /* 1011 */ - 2, /* 1100 */ - 3, /* 1101 */ - 3, /* 1110 */ - 4, /* 1111 */ - }; - - return nybble_table[v & 15] + nybble_table[v>>4]; -} - -/* ===== - * String manipulation - * ===== */ - -/** Remove from the string <b>s</b> every character which appears in - * <b>strip</b>. */ -void -tor_strstrip(char *s, const char *strip) -{ - char *readp = s; - while (*readp) { - if (strchr(strip, *readp)) { - ++readp; - } else { - *s++ = *readp++; - } - } - *s = '\0'; -} - -/** Return a pointer to a NUL-terminated hexadecimal string encoding - * the first <b>fromlen</b> bytes of <b>from</b>. (fromlen must be \<= 32.) The - * result does not need to be deallocated, but repeated calls to - * hex_str will trash old results. - */ -const char * -hex_str(const char *from, size_t fromlen) -{ - static char buf[65]; - if (fromlen>(sizeof(buf)-1)/2) - fromlen = (sizeof(buf)-1)/2; - base16_encode(buf,sizeof(buf),from,fromlen); - return buf; -} - -/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to - * lowercase. */ -void -tor_strlower(char *s) -{ - while (*s) { - *s = TOR_TOLOWER(*s); - ++s; - } -} - -/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to - * lowercase. */ -void -tor_strupper(char *s) -{ - while (*s) { - *s = TOR_TOUPPER(*s); - ++s; - } -} - -/** Return 1 if every character in <b>s</b> is printable, else return 0. - */ -int -tor_strisprint(const char *s) -{ - while (*s) { - if (!TOR_ISPRINT(*s)) - return 0; - s++; - } - return 1; -} - -/** Return 1 if no character in <b>s</b> is uppercase, else return 0. - */ -int -tor_strisnonupper(const char *s) -{ - while (*s) { - if (TOR_ISUPPER(*s)) - return 0; - s++; - } - return 1; -} - -/** Return true iff every character in <b>s</b> is whitespace space; else - * return false. */ -int -tor_strisspace(const char *s) -{ - while (*s) { - if (!TOR_ISSPACE(*s)) - return 0; - s++; - } - return 1; -} - -/** As strcmp, except that either string may be NULL. The NULL string is - * considered to be before any non-NULL string. */ -int -strcmp_opt(const char *s1, const char *s2) -{ - if (!s1) { - if (!s2) - return 0; - else - return -1; - } else if (!s2) { - return 1; - } else { - return strcmp(s1, s2); - } -} - -/** Compares the first strlen(s2) characters of s1 with s2. Returns as for - * strcmp. - */ -int -strcmpstart(const char *s1, const char *s2) -{ - size_t n = strlen(s2); - return strncmp(s1, s2, n); -} - -/** Compare the s1_len-byte string <b>s1</b> with <b>s2</b>, - * without depending on a terminating nul in s1. Sorting order is first by - * length, then lexically; return values are as for strcmp. - */ -int -strcmp_len(const char *s1, const char *s2, size_t s1_len) -{ - size_t s2_len = strlen(s2); - if (s1_len < s2_len) - return -1; - if (s1_len > s2_len) - return 1; - return fast_memcmp(s1, s2, s2_len); -} - -/** Compares the first strlen(s2) characters of s1 with s2. Returns as for - * strcasecmp. - */ -int -strcasecmpstart(const char *s1, const char *s2) -{ - size_t n = strlen(s2); - return strncasecmp(s1, s2, n); -} - -/** Compares the last strlen(s2) characters of s1 with s2. Returns as for - * strcmp. - */ -int -strcmpend(const char *s1, const char *s2) -{ - size_t n1 = strlen(s1), n2 = strlen(s2); - if (n2>n1) - return strcmp(s1,s2); - else - return strncmp(s1+(n1-n2), s2, n2); -} - -/** Compares the last strlen(s2) characters of s1 with s2. Returns as for - * strcasecmp. - */ -int -strcasecmpend(const char *s1, const char *s2) -{ - size_t n1 = strlen(s1), n2 = strlen(s2); - if (n2>n1) /* then they can't be the same; figure out which is bigger */ - return strcasecmp(s1,s2); - else - return strncasecmp(s1+(n1-n2), s2, n2); -} - -/** Compare the value of the string <b>prefix</b> with the start of the - * <b>memlen</b>-byte memory chunk at <b>mem</b>. Return as for strcmp. - * - * [As fast_memcmp(mem, prefix, strlen(prefix)) but returns -1 if memlen is - * less than strlen(prefix).] - */ -int -fast_memcmpstart(const void *mem, size_t memlen, - const char *prefix) -{ - size_t plen = strlen(prefix); - if (memlen < plen) - return -1; - return fast_memcmp(mem, prefix, plen); -} - -/** Return a pointer to the first char of s that is not whitespace and - * not a comment, or to the terminating NUL if no such character exists. - */ -const char * -eat_whitespace(const char *s) -{ - tor_assert(s); - - while (1) { - switch (*s) { - case '\0': - default: - return s; - case ' ': - case '\t': - case '\n': - case '\r': - ++s; - break; - case '#': - ++s; - while (*s && *s != '\n') - ++s; - } - } -} - -/** Return a pointer to the first char of s that is not whitespace and - * not a comment, or to the terminating NUL if no such character exists. - */ -const char * -eat_whitespace_eos(const char *s, const char *eos) -{ - tor_assert(s); - tor_assert(eos && s <= eos); - - while (s < eos) { - switch (*s) { - case '\0': - default: - return s; - case ' ': - case '\t': - case '\n': - case '\r': - ++s; - break; - case '#': - ++s; - while (s < eos && *s && *s != '\n') - ++s; - } - } - return s; -} - -/** Return a pointer to the first char of s that is not a space or a tab - * or a \\r, or to the terminating NUL if no such character exists. */ -const char * -eat_whitespace_no_nl(const char *s) -{ - while (*s == ' ' || *s == '\t' || *s == '\r') - ++s; - return s; -} - -/** As eat_whitespace_no_nl, but stop at <b>eos</b> whether we have - * found a non-whitespace character or not. */ -const char * -eat_whitespace_eos_no_nl(const char *s, const char *eos) -{ - while (s < eos && (*s == ' ' || *s == '\t' || *s == '\r')) - ++s; - return s; -} - -/** Return a pointer to the first char of s that is whitespace or <b>#</b>, - * or to the terminating NUL if no such character exists. - */ -const char * -find_whitespace(const char *s) -{ - /* tor_assert(s); */ - while (1) { - switch (*s) - { - case '\0': - case '#': - case ' ': - case '\r': - case '\n': - case '\t': - return s; - default: - ++s; - } - } -} - -/** As find_whitespace, but stop at <b>eos</b> whether we have found a - * whitespace or not. */ -const char * -find_whitespace_eos(const char *s, const char *eos) -{ - /* tor_assert(s); */ - while (s < eos) { - switch (*s) - { - case '\0': - case '#': - case ' ': - case '\r': - case '\n': - case '\t': - return s; - default: - ++s; - } - } - return s; -} - -/** Return the first occurrence of <b>needle</b> in <b>haystack</b> that - * occurs at the start of a line (that is, at the beginning of <b>haystack</b> - * or immediately after a newline). Return NULL if no such string is found. - */ -const char * -find_str_at_start_of_line(const char *haystack, const char *needle) -{ - size_t needle_len = strlen(needle); - - do { - if (!strncmp(haystack, needle, needle_len)) - return haystack; - - haystack = strchr(haystack, '\n'); - if (!haystack) - return NULL; - else - ++haystack; - } while (*haystack); - - return NULL; -} - -/** Returns true if <b>string</b> could be a C identifier. - A C identifier must begin with a letter or an underscore and the - rest of its characters can be letters, numbers or underscores. No - length limit is imposed. */ -int -string_is_C_identifier(const char *string) -{ - size_t iter; - size_t length = strlen(string); - if (!length) - return 0; - - for (iter = 0; iter < length ; iter++) { - if (iter == 0) { - if (!(TOR_ISALPHA(string[iter]) || - string[iter] == '_')) - return 0; - } else { - if (!(TOR_ISALPHA(string[iter]) || - TOR_ISDIGIT(string[iter]) || - string[iter] == '_')) - return 0; - } - } - - return 1; -} - -/** Return true iff the 'len' bytes at 'mem' are all zero. */ -int -tor_mem_is_zero(const char *mem, size_t len) -{ - static const char ZERO[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - }; - while (len >= sizeof(ZERO)) { - /* It's safe to use fast_memcmp here, since the very worst thing an - * attacker could learn is how many initial bytes of a secret were zero */ - if (fast_memcmp(mem, ZERO, sizeof(ZERO))) - return 0; - len -= sizeof(ZERO); - mem += sizeof(ZERO); - } - /* Deal with leftover bytes. */ - if (len) - return fast_memeq(mem, ZERO, len); - - return 1; -} - -/** Return true iff the DIGEST_LEN bytes in digest are all zero. */ -int -tor_digest_is_zero(const char *digest) -{ - static const uint8_t ZERO_DIGEST[] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 - }; - return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); -} - -/** Return true if <b>string</b> is a valid 'key=[value]' string. - * "value" is optional, to indicate the empty string. Log at logging - * <b>severity</b> if something ugly happens. */ -int -string_is_key_value(int severity, const char *string) -{ - /* position of equal sign in string */ - const char *equal_sign_pos = NULL; - - tor_assert(string); - - if (strlen(string) < 2) { /* "x=" is shortest args string */ - tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.", - escaped(string)); - return 0; - } - - equal_sign_pos = strchr(string, '='); - if (!equal_sign_pos) { - tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string)); - return 0; - } - - /* validate that the '=' is not in the beginning of the string. */ - if (equal_sign_pos == string) { - tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.", - escaped(string)); - return 0; - } - - return 1; -} - -/** Return true if <b>string</b> represents a valid IPv4 adddress in - * 'a.b.c.d' form. - */ -int -string_is_valid_ipv4_address(const char *string) -{ - struct in_addr addr; - - return (tor_inet_pton(AF_INET,string,&addr) == 1); -} - -/** Return true if <b>string</b> represents a valid IPv6 address in - * a form that inet_pton() can parse. - */ -int -string_is_valid_ipv6_address(const char *string) -{ - struct in6_addr addr; - - return (tor_inet_pton(AF_INET6,string,&addr) == 1); -} - -/** Return true iff <b>string</b> is a valid destination address, - * i.e. either a DNS hostname or IPv4/IPv6 address string. - */ -int -string_is_valid_dest(const char *string) -{ - char *tmp = NULL; - int retval; - size_t len; - - if (string == NULL) - return 0; - - len = strlen(string); - - if (len == 0) - return 0; - - if (string[0] == '[' && string[len - 1] == ']') - string = tmp = tor_strndup(string + 1, len - 2); - - retval = string_is_valid_ipv4_address(string) || - string_is_valid_ipv6_address(string) || - string_is_valid_nonrfc_hostname(string); - - tor_free(tmp); - - return retval; -} - -/** Return true iff <b>string</b> matches a pattern of DNS names - * that we allow Tor clients to connect to. - * - * Note: This allows certain technically invalid characters ('_') to cope - * with misconfigured zones that have been encountered in the wild. - */ -int -string_is_valid_nonrfc_hostname(const char *string) -{ - int result = 1; - int has_trailing_dot; - char *last_label; - smartlist_t *components; - - if (!string || strlen(string) == 0) - return 0; - - if (string_is_valid_ipv4_address(string)) - return 0; - - components = smartlist_new(); - - smartlist_split_string(components,string,".",0,0); - - if (BUG(smartlist_len(components) == 0)) - return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks. - - /* Allow a single terminating '.' used rarely to indicate domains - * are FQDNs rather than relative. */ - last_label = (char *)smartlist_get(components, - smartlist_len(components) - 1); - has_trailing_dot = (last_label[0] == '\0'); - if (has_trailing_dot) { - smartlist_pop_last(components); - tor_free(last_label); - last_label = NULL; - } - - SMARTLIST_FOREACH_BEGIN(components, char *, c) { - if ((c[0] == '-') || (*c == '_')) { - result = 0; - break; - } - - do { - result = (TOR_ISALNUM(*c) || (*c == '-') || (*c == '_')); - c++; - } while (result && *c); - - if (result == 0) { - break; - } - } SMARTLIST_FOREACH_END(c); - - SMARTLIST_FOREACH_BEGIN(components, char *, c) { - tor_free(c); - } SMARTLIST_FOREACH_END(c); - - smartlist_free(components); - - return result; -} - -/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ -int -tor_digest256_is_zero(const char *digest) -{ - return tor_mem_is_zero(digest, DIGEST256_LEN); -} - -/* Helper: common code to check whether the result of a strtol or strtoul or - * strtoll is correct. */ -#define CHECK_STRTOX_RESULT() \ - /* Did an overflow occur? */ \ - if (errno == ERANGE) \ - goto err; \ - /* Was at least one character converted? */ \ - if (endptr == s) \ - goto err; \ - /* Were there unexpected unconverted characters? */ \ - if (!next && *endptr) \ - goto err; \ - /* Illogical (max, min) inputs? */ \ - if (BUG(max < min)) \ - goto err; \ - /* Is r within limits? */ \ - if (r < min || r > max) \ - goto err; \ - if (ok) *ok = 1; \ - if (next) *next = endptr; \ - return r; \ - err: \ - if (ok) *ok = 0; \ - if (next) *next = endptr; \ - return 0 - -/** Extract a long from the start of <b>s</b>, in the given numeric - * <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal, - * octal, or hex number in the syntax of a C integer literal. If - * there is unconverted data and <b>next</b> is provided, set - * *<b>next</b> to the first unconverted character. An error has - * occurred if no characters are converted; or if there are - * unconverted characters and <b>next</b> is NULL; or if the parsed - * value is not between <b>min</b> and <b>max</b>. When no error - * occurs, return the parsed value and set *<b>ok</b> (if provided) to - * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided) - * to 0. - */ -long -tor_parse_long(const char *s, int base, long min, long max, - int *ok, char **next) -{ - char *endptr; - long r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; - r = strtol(s, &endptr, base); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long(), but return an unsigned long. */ -unsigned long -tor_parse_ulong(const char *s, int base, unsigned long min, - unsigned long max, int *ok, char **next) -{ - char *endptr; - unsigned long r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; - r = strtoul(s, &endptr, base); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long(), but return a double. */ -double -tor_parse_double(const char *s, double min, double max, int *ok, char **next) -{ - char *endptr; - double r; - - errno = 0; - r = strtod(s, &endptr); - CHECK_STRTOX_RESULT(); -} - -/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to - * work for now. */ -uint64_t -tor_parse_uint64(const char *s, int base, uint64_t min, - uint64_t max, int *ok, char **next) -{ - char *endptr; - uint64_t r; - - if (BUG(base < 0)) { - if (ok) - *ok = 0; - return 0; - } - - errno = 0; -#ifdef HAVE_STRTOULL - r = (uint64_t)strtoull(s, &endptr, base); -#elif defined(_WIN32) - r = (uint64_t)_strtoui64(s, &endptr, base); -#elif SIZEOF_LONG == 8 - r = (uint64_t)strtoul(s, &endptr, base); -#else -#error "I don't know how to parse 64-bit numbers." -#endif /* defined(HAVE_STRTOULL) || ... */ - - CHECK_STRTOX_RESULT(); -} - -/** Allocate and return a new string representing the contents of <b>s</b>, - * surrounded by quotes and using standard C escapes. - * - * Generally, we use this for logging values that come in over the network to - * keep them from tricking users, and for sending certain values to the - * controller. - * - * We trust values from the resolver, OS, configuration file, and command line - * to not be maliciously ill-formed. We validate incoming routerdescs and - * SOCKS requests and addresses from BEGIN cells as they're parsed; - * afterwards, we trust them as non-malicious. - */ -char * -esc_for_log(const char *s) -{ - const char *cp; - char *result, *outp; - size_t len = 3; - if (!s) { - return tor_strdup("(null)"); - } - - for (cp = s; *cp; ++cp) { - switch (*cp) { - case '\\': - case '\"': - case '\'': - case '\r': - case '\n': - case '\t': - len += 2; - break; - default: - if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) - ++len; - else - len += 4; - break; - } - } - - tor_assert(len <= SSIZE_MAX); - - result = outp = tor_malloc(len); - *outp++ = '\"'; - for (cp = s; *cp; ++cp) { - /* This assertion should always succeed, since we will write at least - * one char here, and two chars for closing quote and nul later */ - tor_assert((outp-result) < (ssize_t)len-2); - switch (*cp) { - case '\\': - case '\"': - case '\'': - *outp++ = '\\'; - *outp++ = *cp; - break; - case '\n': - *outp++ = '\\'; - *outp++ = 'n'; - break; - case '\t': - *outp++ = '\\'; - *outp++ = 't'; - break; - case '\r': - *outp++ = '\\'; - *outp++ = 'r'; - break; - default: - if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) { - *outp++ = *cp; - } else { - tor_assert((outp-result) < (ssize_t)len-4); - tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp); - outp += 4; - } - break; - } - } - - tor_assert((outp-result) <= (ssize_t)len-2); - *outp++ = '\"'; - *outp++ = 0; - - return result; -} - -/** Similar to esc_for_log. Allocate and return a new string representing - * the first n characters in <b>chars</b>, surround by quotes and using - * standard C escapes. If a NUL character is encountered in <b>chars</b>, - * the resulting string will be terminated there. - */ -char * -esc_for_log_len(const char *chars, size_t n) -{ - char *string = tor_strndup(chars, n); - char *string_escaped = esc_for_log(string); - tor_free(string); - return string_escaped; -} - -/** Allocate and return a new string representing the contents of <b>s</b>, - * surrounded by quotes and using standard C escapes. - * - * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main - * thread. Also, each call invalidates the last-returned value, so don't - * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b)); - */ -const char * -escaped(const char *s) -{ - static char *escaped_val_ = NULL; - tor_free(escaped_val_); - - if (s) - escaped_val_ = esc_for_log(s); - else - escaped_val_ = NULL; - - return escaped_val_; -} - -/** Return a newly allocated string equal to <b>string</b>, except that every - * character in <b>chars_to_escape</b> is preceded by a backslash. */ -char * -tor_escape_str_for_pt_args(const char *string, const char *chars_to_escape) -{ - char *new_string = NULL; - char *new_cp = NULL; - size_t length, new_length; - - tor_assert(string); - - length = strlen(string); - - if (!length) /* If we were given the empty string, return the same. */ - return tor_strdup(""); - /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) => - (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */ - if (length > (SIZE_MAX - 1)/2) /* check for overflow */ - return NULL; - - /* this should be enough even if all characters must be escaped */ - new_length = (length * 2) + 1; - - new_string = new_cp = tor_malloc(new_length); - - while (*string) { - if (strchr(chars_to_escape, *string)) - *new_cp++ = '\\'; - - *new_cp++ = *string++; - } - - *new_cp = '\0'; /* NUL-terminate the new string */ - - return new_string; -} - -/* ===== - * Time - * ===== */ - -#define TOR_USEC_PER_SEC 1000000 - -/** Return the difference between start->tv_sec and end->tv_sec. - * Returns INT64_MAX on overflow and underflow. - */ -static int64_t -tv_secdiff_impl(const struct timeval *start, const struct timeval *end) -{ - const int64_t s = (int64_t)start->tv_sec; - const int64_t e = (int64_t)end->tv_sec; - - /* This may not be the most efficient way of implemeting this check, - * but it's easy to see that it's correct and doesn't overflow */ - - if (s > 0 && e < INT64_MIN + s) { - /* s is positive: equivalent to e - s < INT64_MIN, but without any - * overflow */ - return INT64_MAX; - } else if (s < 0 && e > INT64_MAX + s) { - /* s is negative: equivalent to e - s > INT64_MAX, but without any - * overflow */ - return INT64_MAX; - } - - return e - s; -} - -/** Return the number of microseconds elapsed between *start and *end. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_udiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t udiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way */ - if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || - secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { - log_warn(LD_GENERAL, "comparing times on microsecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* we'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)udiff; -} - -/** Return the number of milliseconds elapsed between *start and *end. - * If the tv_usec difference is 500, rounds away from zero. - * Returns LONG_MAX on overflow and underflow. - */ -long -tv_mdiff(const struct timeval *start, const struct timeval *end) -{ - /* Sanity check tv_usec */ - if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "start tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(start->tv_usec)); - return LONG_MAX; - } - - if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { - log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " - "end tv_usec: " I64_FORMAT " microseconds", - I64_PRINTF_ARG(end->tv_usec)); - return LONG_MAX; - } - - /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit - */ - int64_t mdiff; - const int64_t secdiff = tv_secdiff_impl(start, end); - - /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the - * mdiff calculation may add another temporary second for rounding. - * Whether this actually causes overflow depends on the compiler's constant - * folding and order of operations. */ - if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || - secdiff < (int64_t)(LONG_MIN/1000 + 1)) { - log_warn(LD_GENERAL, "comparing times on millisecond detail too far " - "apart: " I64_FORMAT " seconds", I64_PRINTF_ARG(secdiff)); - return LONG_MAX; - } - - /* Subtract and round */ - mdiff = secdiff*1000 + - /* We add a million usec here to ensure that the result is positive, - * so that the round-towards-zero behavior of the division will give - * the right result for rounding to the nearest msec. Later we subtract - * 1000 in order to get the correct result. - * We'll never get an overflow here, because we check that both usecs are - * between 0 and TV_USEC_PER_SEC. */ - ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 - - 1000; - - /* Some compilers are smart enough to work out this is a no-op on L64 */ -#if SIZEOF_LONG < 8 - if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { - return LONG_MAX; - } -#endif - - return (long)mdiff; -} - -/** - * Converts timeval to milliseconds. - */ -int64_t -tv_to_msec(const struct timeval *tv) -{ - int64_t conv = ((int64_t)tv->tv_sec)*1000L; - /* Round ghetto-style */ - conv += ((int64_t)tv->tv_usec+500)/1000L; - return conv; -} - -/** Yield true iff <b>y</b> is a leap-year. */ -#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400))) -/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */ -static int -n_leapdays(int year1, int year2) -{ - --year1; - --year2; - return (year2/4 - year1/4) - (year2/100 - year1/100) - + (year2/400 - year1/400); -} -/** Number of days per month in non-leap year; used by tor_timegm and - * parse_rfc1123_time. */ -static const int days_per_month[] = - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -/** Compute a time_t given a struct tm. The result is given in UTC, and - * does not account for leap seconds. Return 0 on success, -1 on failure. - */ -int -tor_timegm(const struct tm *tm, time_t *time_out) -{ - /* This is a pretty ironclad timegm implementation, snarfed from Python2.2. - * It's way more brute-force than fiddling with tzset(). - * - * We use int64_t rather than time_t to avoid overflow on multiplication on - * platforms with 32-bit time_t. Since year is clipped to INT32_MAX, and - * since 365 * 24 * 60 * 60 is approximately 31 million, it's not possible - * for INT32_MAX years to overflow int64_t when converted to seconds. */ - int64_t year, days, hours, minutes, seconds; - int i, invalid_year, dpm; - - /* Initialize time_out to 0 for now, to avoid bad usage in case this function - fails and the caller ignores the return value. */ - tor_assert(time_out); - *time_out = 0; - - /* avoid int overflow on addition */ - if (tm->tm_year < INT32_MAX-1900) { - year = tm->tm_year + 1900; - } else { - /* clamp year */ - year = INT32_MAX; - } - invalid_year = (year < 1970 || tm->tm_year >= INT32_MAX-1900); - - if (tm->tm_mon >= 0 && tm->tm_mon <= 11) { - dpm = days_per_month[tm->tm_mon]; - if (tm->tm_mon == 1 && !invalid_year && IS_LEAPYEAR(tm->tm_year)) { - dpm = 29; - } - } else { - /* invalid month - default to 0 days per month */ - dpm = 0; - } - - if (invalid_year || - tm->tm_mon < 0 || tm->tm_mon > 11 || - tm->tm_mday < 1 || tm->tm_mday > dpm || - tm->tm_hour < 0 || tm->tm_hour > 23 || - tm->tm_min < 0 || tm->tm_min > 59 || - tm->tm_sec < 0 || tm->tm_sec > 60) { - log_warn(LD_BUG, "Out-of-range argument to tor_timegm"); - return -1; - } - days = 365 * (year-1970) + n_leapdays(1970,(int)year); - for (i = 0; i < tm->tm_mon; ++i) - days += days_per_month[i]; - if (tm->tm_mon > 1 && IS_LEAPYEAR(year)) - ++days; - days += tm->tm_mday - 1; - hours = days*24 + tm->tm_hour; - - minutes = hours*60 + tm->tm_min; - seconds = minutes*60 + tm->tm_sec; - /* Check that "seconds" will fit in a time_t. On platforms where time_t is - * 32-bit, this check will fail for dates in and after 2038. - * - * We already know that "seconds" can't be negative because "year" >= 1970 */ -#if SIZEOF_TIME_T < 8 - if (seconds < TIME_MIN || seconds > TIME_MAX) { - log_warn(LD_BUG, "Result does not fit in tor_timegm"); - return -1; - } -#endif /* SIZEOF_TIME_T < 8 */ - *time_out = (time_t)seconds; - return 0; -} - -/* strftime is locale-specific, so we need to replace those parts */ - -/** A c-locale array of 3-letter names of weekdays, starting with Sun. */ -static const char *WEEKDAY_NAMES[] = - { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -/** A c-locale array of 3-letter names of months, starting with Jan. */ -static const char *MONTH_NAMES[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - -/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>. - * The buffer must be at least RFC1123_TIME_LEN+1 bytes long. - * - * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT" - * rather than "UTC".) - */ -void -format_rfc1123_time(char *buf, time_t t) -{ - struct tm tm; - - tor_gmtime_r(&t, &tm); - - strftime(buf, RFC1123_TIME_LEN+1, "___, %d ___ %Y %H:%M:%S GMT", &tm); - tor_assert(tm.tm_wday >= 0); - tor_assert(tm.tm_wday <= 6); - memcpy(buf, WEEKDAY_NAMES[tm.tm_wday], 3); - tor_assert(tm.tm_mon >= 0); - tor_assert(tm.tm_mon <= 11); - memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3); -} - -/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from - * <b>buf</b>, and store the result in *<b>t</b>. - * - * Note that we only accept the subset generated by format_rfc1123_time above, - * not the full range of formats suggested by RFC 1123. - * - * Return 0 on success, -1 on failure. -*/ -int -parse_rfc1123_time(const char *buf, time_t *t) -{ - struct tm tm; - char month[4]; - char weekday[4]; - int i, m, invalid_year; - unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; - unsigned dpm; - - if (strlen(buf) != RFC1123_TIME_LEN) - return -1; - memset(&tm, 0, sizeof(tm)); - if (tor_sscanf(buf, "%3s, %2u %3s %u %2u:%2u:%2u GMT", weekday, - &tm_mday, month, &tm_year, &tm_hour, - &tm_min, &tm_sec) < 7) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); - tor_free(esc); - return -1; - } - - m = -1; - for (i = 0; i < 12; ++i) { - if (!strcmp(month, MONTH_NAMES[i])) { - m = i; - break; - } - } - if (m<0) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s: No such month", esc); - tor_free(esc); - return -1; - } - tm.tm_mon = m; - - invalid_year = (tm_year >= INT32_MAX || tm_year < 1970); - tor_assert(m >= 0 && m <= 11); - dpm = days_per_month[m]; - if (m == 1 && !invalid_year && IS_LEAPYEAR(tm_year)) { - dpm = 29; - } - - if (invalid_year || tm_mday < 1 || tm_mday > dpm || - tm_hour > 23 || tm_min > 59 || tm_sec > 60) { - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); - tor_free(esc); - return -1; - } - tm.tm_mday = (int)tm_mday; - tm.tm_year = (int)tm_year; - tm.tm_hour = (int)tm_hour; - tm.tm_min = (int)tm_min; - tm.tm_sec = (int)tm_sec; - - if (tm.tm_year < 1970) { - /* LCOV_EXCL_START - * XXXX I think this is dead code; we already checked for - * invalid_year above. */ - tor_assert_nonfatal_unreached(); - char *esc = esc_for_log(buf); - log_warn(LD_GENERAL, - "Got invalid RFC1123 time %s. (Before 1970)", esc); - tor_free(esc); - return -1; - /* LCOV_EXCL_STOP */ - } - tm.tm_year -= 1900; - - return tor_timegm(&tm, t); -} - -/** Set <b>buf</b> to the ISO8601 encoding of the local value of <b>t</b>. - * The buffer must be at least ISO_TIME_LEN+1 bytes long. - * - * (ISO8601 format is 2006-10-29 10:57:20) - */ -void -format_local_iso_time(char *buf, time_t t) -{ - struct tm tm; - strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_localtime_r(&t, &tm)); -} - -/** Set <b>buf</b> to the ISO8601 encoding of the GMT value of <b>t</b>. - * The buffer must be at least ISO_TIME_LEN+1 bytes long. - */ -void -format_iso_time(char *buf, time_t t) -{ - struct tm tm; - strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_gmtime_r(&t, &tm)); -} - -/** As format_local_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid - * embedding an internal space. */ -void -format_local_iso_time_nospace(char *buf, time_t t) -{ - format_local_iso_time(buf, t); - buf[10] = 'T'; -} - -/** As format_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid - * embedding an internal space. */ -void -format_iso_time_nospace(char *buf, time_t t) -{ - format_iso_time(buf, t); - buf[10] = 'T'; -} - -/** As format_iso_time_nospace, but include microseconds in decimal - * fixed-point format. Requires that buf be at least ISO_TIME_USEC_LEN+1 - * bytes long. */ -void -format_iso_time_nospace_usec(char *buf, const struct timeval *tv) -{ - tor_assert(tv); - format_iso_time_nospace(buf, (time_t)tv->tv_sec); - tor_snprintf(buf+ISO_TIME_LEN, 8, ".%06d", (int)tv->tv_usec); -} - -/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, - * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on - * failure. Ignore extraneous stuff in <b>cp</b> after the end of the time - * string, unless <b>strict</b> is set. If <b>nospace</b> is set, - * expect the YYYY-MM-DDTHH:MM:SS format. */ -int -parse_iso_time_(const char *cp, time_t *t, int strict, int nospace) -{ - struct tm st_tm; - unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0; - int n_fields; - char extra_char, separator_char; - n_fields = tor_sscanf(cp, "%u-%2u-%2u%c%2u:%2u:%2u%c", - &year, &month, &day, - &separator_char, - &hour, &minute, &second, &extra_char); - if (strict ? (n_fields != 7) : (n_fields < 7)) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); - tor_free(esc); - return -1; - } - if (separator_char != (nospace ? 'T' : ' ')) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); - tor_free(esc); - return -1; - } - if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || - hour > 23 || minute > 59 || second > 60 || year >= INT32_MAX) { - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "ISO time %s was nonsensical", esc); - tor_free(esc); - return -1; - } - st_tm.tm_year = (int)year-1900; - st_tm.tm_mon = month-1; - st_tm.tm_mday = day; - st_tm.tm_hour = hour; - st_tm.tm_min = minute; - st_tm.tm_sec = second; - st_tm.tm_wday = 0; /* Should be ignored. */ - - if (st_tm.tm_year < 70) { - /* LCOV_EXCL_START - * XXXX I think this is dead code; we already checked for - * year < 1970 above. */ - tor_assert_nonfatal_unreached(); - char *esc = esc_for_log(cp); - log_warn(LD_GENERAL, "Got invalid ISO time %s. (Before 1970)", esc); - tor_free(esc); - return -1; - /* LCOV_EXCL_STOP */ - } - return tor_timegm(&st_tm, t); -} - -/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, - * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on - * failure. Reject the string if any characters are present after the time. - */ -int -parse_iso_time(const char *cp, time_t *t) -{ - return parse_iso_time_(cp, t, 1, 0); -} - -/** - * As parse_iso_time, but parses a time encoded by format_iso_time_nospace(). - */ -int -parse_iso_time_nospace(const char *cp, time_t *t) -{ - return parse_iso_time_(cp, t, 1, 1); -} - -/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh), - * parse it into <b>tm</b>. Return 0 on success, negative on failure. */ -int -parse_http_time(const char *date, struct tm *tm) -{ - const char *cp; - char month[4]; - char wkday[4]; - int i; - unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; - - tor_assert(tm); - memset(tm, 0, sizeof(*tm)); - - /* First, try RFC1123 or RFC850 format: skip the weekday. */ - if ((cp = strchr(date, ','))) { - ++cp; - if (*cp != ' ') - return -1; - ++cp; - if (tor_sscanf(cp, "%2u %3s %4u %2u:%2u:%2u GMT", - &tm_mday, month, &tm_year, - &tm_hour, &tm_min, &tm_sec) == 6) { - /* rfc1123-date */ - tm_year -= 1900; - } else if (tor_sscanf(cp, "%2u-%3s-%2u %2u:%2u:%2u GMT", - &tm_mday, month, &tm_year, - &tm_hour, &tm_min, &tm_sec) == 6) { - /* rfc850-date */ - } else { - return -1; - } - } else { - /* No comma; possibly asctime() format. */ - if (tor_sscanf(date, "%3s %3s %2u %2u:%2u:%2u %4u", - wkday, month, &tm_mday, - &tm_hour, &tm_min, &tm_sec, &tm_year) == 7) { - tm_year -= 1900; - } else { - return -1; - } - } - tm->tm_mday = (int)tm_mday; - tm->tm_year = (int)tm_year; - tm->tm_hour = (int)tm_hour; - tm->tm_min = (int)tm_min; - tm->tm_sec = (int)tm_sec; - tm->tm_wday = 0; /* Leave this unset. */ - - month[3] = '\0'; - /* Okay, now decode the month. */ - /* set tm->tm_mon to dummy value so the check below fails. */ - tm->tm_mon = -1; - for (i = 0; i < 12; ++i) { - if (!strcasecmp(MONTH_NAMES[i], month)) { - tm->tm_mon = i; - } - } - - if (tm->tm_year < 0 || - tm->tm_mon < 0 || tm->tm_mon > 11 || - tm->tm_mday < 1 || tm->tm_mday > 31 || - tm->tm_hour < 0 || tm->tm_hour > 23 || - tm->tm_min < 0 || tm->tm_min > 59 || - tm->tm_sec < 0 || tm->tm_sec > 60) - return -1; /* Out of range, or bad month. */ - - return 0; -} - -/** Given an <b>interval</b> in seconds, try to write it to the - * <b>out_len</b>-byte buffer in <b>out</b> in a human-readable form. - * Returns a non-negative integer on success, -1 on failure. - */ -int -format_time_interval(char *out, size_t out_len, long interval) -{ - /* We only report seconds if there's no hours. */ - long sec = 0, min = 0, hour = 0, day = 0; - - /* -LONG_MIN is LONG_MAX + 1, which causes signed overflow */ - if (interval < -LONG_MAX) - interval = LONG_MAX; - else if (interval < 0) - interval = -interval; - - if (interval >= 86400) { - day = interval / 86400; - interval %= 86400; - } - if (interval >= 3600) { - hour = interval / 3600; - interval %= 3600; - } - if (interval >= 60) { - min = interval / 60; - interval %= 60; - } - sec = interval; - - if (day) { - return tor_snprintf(out, out_len, "%ld days, %ld hours, %ld minutes", - day, hour, min); - } else if (hour) { - return tor_snprintf(out, out_len, "%ld hours, %ld minutes", hour, min); - } else if (min) { - return tor_snprintf(out, out_len, "%ld minutes, %ld seconds", min, sec); - } else { - return tor_snprintf(out, out_len, "%ld seconds", sec); - } -} - -/* ===== - * Cached time - * ===== */ - -#ifndef TIME_IS_FAST -/** Cached estimate of the current time. Updated around once per second; - * may be a few seconds off if we are really busy. This is a hack to avoid - * calling time(NULL) (which not everybody has optimized) on critical paths. - */ -static time_t cached_approx_time = 0; - -/** Return a cached estimate of the current time from when - * update_approx_time() was last called. This is a hack to avoid calling - * time(NULL) on critical paths: please do not even think of calling it - * anywhere else. */ -time_t -approx_time(void) -{ - return cached_approx_time; -} - -/** Update the cached estimate of the current time. This function SHOULD be - * called once per second, and MUST be called before the first call to - * get_approx_time. */ -void -update_approx_time(time_t now) -{ - cached_approx_time = now; -} -#endif /* !defined(TIME_IS_FAST) */ - -/* ===== - * Rate limiting - * ===== */ - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number - * of calls to rate_limit_is_ready (including this one!) since the last time - * rate_limit_is_ready returned nonzero. Otherwise return 0. - * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning - * about this event and stop counting. */ -static int -rate_limit_is_ready(ratelim_t *lim, time_t now) -{ - if (lim->rate + lim->last_allowed <= now) { - int res = lim->n_calls_since_last_time + 1; - lim->last_allowed = now; - lim->n_calls_since_last_time = 0; - return res; - } else { - if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { - ++lim->n_calls_since_last_time; - } - - return 0; - } -} - -/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly - * allocated string indicating how many messages were suppressed, suitable to - * append to a log message. Otherwise return NULL. */ -char * -rate_limit_log(ratelim_t *lim, time_t now) -{ - int n; - if ((n = rate_limit_is_ready(lim, now))) { - if (n == 1) { - return tor_strdup(""); - } else { - char *cp=NULL; - const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; - /* XXXX this is not exactly correct: the messages could have occurred - * any time between the old value of lim->allowed and now. */ - tor_asprintf(&cp, - " [%s%d similar message(s) suppressed in last %d seconds]", - opt_over, n-1, lim->rate); - return cp; - } - } else { - return NULL; - } -} - -/* ===== - * File helpers - * ===== */ - -/** Write <b>count</b> bytes from <b>buf</b> to <b>fd</b>. <b>isSocket</b> - * must be 1 if fd was returned by socket() or accept(), and 0 if fd - * was returned by open(). Return the number of bytes written, or -1 - * on error. Only use if fd is a blocking fd. */ -ssize_t -write_all(tor_socket_t fd, const char *buf, size_t count, int isSocket) -{ - size_t written = 0; - ssize_t result; - tor_assert(count < SSIZE_MAX); - - while (written != count) { - if (isSocket) - result = tor_socket_send(fd, buf+written, count-written, 0); - else - result = write((int)fd, buf+written, count-written); - if (result<0) - return -1; - written += result; - } - return (ssize_t)count; -} - -/** Read from <b>fd</b> to <b>buf</b>, until we get <b>count</b> bytes - * or reach the end of the file. <b>isSocket</b> must be 1 if fd - * was returned by socket() or accept(), and 0 if fd was returned by - * open(). Return the number of bytes read, or -1 on error. Only use - * if fd is a blocking fd. */ -ssize_t -read_all(tor_socket_t fd, char *buf, size_t count, int isSocket) -{ - size_t numread = 0; - ssize_t result; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) { - errno = EINVAL; - return -1; - } - - while (numread < count) { - if (isSocket) - result = tor_socket_recv(fd, buf+numread, count-numread, 0); - else - result = read((int)fd, buf+numread, count-numread); - if (result<0) - return -1; - else if (result == 0) - break; - numread += result; - } - return (ssize_t)numread; -} - -/* - * Filesystem operations. - */ - -/** Clean up <b>name</b> so that we can use it in a call to "stat". On Unix, - * we do nothing. On Windows, we remove a trailing slash, unless the path is - * the root of a disk. */ -static void -clean_name_for_stat(char *name) -{ -#ifdef _WIN32 - size_t len = strlen(name); - if (!len) - return; - if (name[len-1]=='\\' || name[len-1]=='/') { - if (len == 1 || (len==3 && name[1]==':')) - return; - name[len-1]='\0'; - } -#else /* !(defined(_WIN32)) */ - (void)name; -#endif /* defined(_WIN32) */ -} - -/** Wrapper for unlink() to make it mockable for the test suite; returns 0 - * if unlinking the file succeeded, -1 and sets errno if unlinking fails. - */ - -MOCK_IMPL(int, -tor_unlink,(const char *pathname)) -{ - return unlink(pathname); -} - -/** Return: - * FN_ERROR if filename can't be read, is NULL, or is zero-length, - * FN_NOENT if it doesn't exist, - * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems, - * FN_EMPTY for zero-byte regular files, - * FN_DIR if it's a directory, and - * FN_ERROR for any other file type. - * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR - * is returned due to an unhandled file type.) */ -file_status_t -file_status(const char *fname) -{ - struct stat st; - char *f; - int r; - if (!fname || strlen(fname) == 0) { - return FN_ERROR; - } - f = tor_strdup(fname); - clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", f); - r = stat(sandbox_intern_string(f), &st); - tor_free(f); - if (r) { - if (errno == ENOENT) { - return FN_NOENT; - } - return FN_ERROR; - } - if (st.st_mode & S_IFDIR) { - return FN_DIR; - } else if (st.st_mode & S_IFREG) { - if (st.st_size > 0) { - return FN_FILE; - } else if (st.st_size == 0) { - return FN_EMPTY; - } else { - return FN_ERROR; - } -#ifndef _WIN32 - } else if (st.st_mode & S_IFIFO) { - return FN_FILE; -#endif - } else { - return FN_ERROR; - } -} - -/** Check whether <b>dirname</b> exists and is private. If yes return 0. - * If <b>dirname</b> does not exist: - * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success. - * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0. - * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0. - * - otherwise, return -1. - * If CPD_GROUP_OK is set, then it's okay if the directory - * is group-readable, but in all cases we create the directory mode 0700. - * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and - * if the directory is created it will use mode 0750 with group read - * permission. Group read privileges also assume execute permission - * as norm for directories. If CPD_CHECK_MODE_ONLY is set, then we don't - * alter the directory permissions if they are too permissive: - * we just return -1. - * When effective_user is not NULL, check permissions against the given user - * and its primary group. - */ -MOCK_IMPL(int, -check_private_dir,(const char *dirname, cpd_check_t check, - const char *effective_user)) -{ - int r; - struct stat st; - - tor_assert(dirname); - -#ifndef _WIN32 - int fd; - const struct passwd *pw = NULL; - uid_t running_uid; - gid_t running_gid; - - /* - * Goal is to harden the implementation by removing any - * potential for race between stat() and chmod(). - * chmod() accepts filename as argument. If an attacker can move - * the file between stat() and chmod(), a potential race exists. - * - * Several suggestions taken from: - * https://developer.apple.com/library/mac/documentation/ - * Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html - */ - - /* Open directory. - * O_NOFOLLOW to ensure that it does not follow symbolic links */ - fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); - - /* Was there an error? Maybe the directory does not exist? */ - if (fd == -1) { - - if (errno != ENOENT) { - /* Other directory error */ - log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, - strerror(errno)); - return -1; - } - - /* Received ENOENT: Directory does not exist */ - - /* Should we create the directory? */ - if (check & CPD_CREATE) { - log_info(LD_GENERAL, "Creating directory %s", dirname); - if (check & CPD_GROUP_READ) { - r = mkdir(dirname, 0750); - } else { - r = mkdir(dirname, 0700); - } - - /* check for mkdir() error */ - if (r) { - log_warn(LD_FS, "Error creating directory %s: %s", dirname, - strerror(errno)); - return -1; - } - - /* we just created the directory. try to open it again. - * permissions on the directory will be checked again below.*/ - fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); - - if (fd == -1) { - log_warn(LD_FS, "Could not reopen recently created directory %s: %s", - dirname, - strerror(errno)); - return -1; - } else { - close(fd); - } - - } else if (!(check & CPD_CHECK)) { - log_warn(LD_FS, "Directory %s does not exist.", dirname); - return -1; - } - - /* XXXX In the case where check==CPD_CHECK, we should look at the - * parent directory a little harder. */ - return 0; - } - - tor_assert(fd >= 0); - - //f = tor_strdup(dirname); - //clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", dirname); - //r = stat(sandbox_intern_string(f), &st); - r = fstat(fd, &st); - if (r == -1) { - log_warn(LD_FS, "fstat() on directory %s failed.", dirname); - close(fd); - return -1; - } - //tor_free(f); - - /* check that dirname is a directory */ - if (!(st.st_mode & S_IFDIR)) { - log_warn(LD_FS, "%s is not a directory", dirname); - close(fd); - return -1; - } - - if (effective_user) { - /* Look up the user and group information. - * If we have a problem, bail out. */ - pw = tor_getpwnam(effective_user); - if (pw == NULL) { - log_warn(LD_CONFIG, "Error setting configured user: %s not found", - effective_user); - close(fd); - return -1; - } - running_uid = pw->pw_uid; - running_gid = pw->pw_gid; - } else { - running_uid = getuid(); - running_gid = getgid(); - } - if (st.st_uid != running_uid) { - char *process_ownername = NULL, *file_ownername = NULL; - - { - const struct passwd *pw_running = tor_getpwuid(running_uid); - process_ownername = pw_running ? tor_strdup(pw_running->pw_name) : - tor_strdup("<unknown>"); - } - - { - const struct passwd *pw_stat = tor_getpwuid(st.st_uid); - file_ownername = pw_stat ? tor_strdup(pw_stat->pw_name) : - tor_strdup("<unknown>"); - } - - log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by " - "%s (%d). Perhaps you are running Tor as the wrong user?", - dirname, process_ownername, (int)running_uid, - file_ownername, (int)st.st_uid); - - tor_free(process_ownername); - tor_free(file_ownername); - close(fd); - return -1; - } - if ( (check & (CPD_GROUP_OK|CPD_GROUP_READ)) - && (st.st_gid != running_gid) && (st.st_gid != 0)) { - struct group *gr; - char *process_groupname = NULL; - gr = getgrgid(running_gid); - process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>"); - gr = getgrgid(st.st_gid); - - log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group " - "%s (%d). Are you running Tor as the wrong user?", - dirname, process_groupname, (int)running_gid, - gr ? gr->gr_name : "<unknown>", (int)st.st_gid); - - tor_free(process_groupname); - close(fd); - return -1; - } - unsigned unwanted_bits = 0; - if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) { - unwanted_bits = 0027; - } else { - unwanted_bits = 0077; - } - unsigned check_bits_filter = ~0; - if (check & CPD_RELAX_DIRMODE_CHECK) { - check_bits_filter = 0022; - } - if ((st.st_mode & unwanted_bits & check_bits_filter) != 0) { - unsigned new_mode; - if (check & CPD_CHECK_MODE_ONLY) { - log_warn(LD_FS, "Permissions on directory %s are too permissive.", - dirname); - close(fd); - return -1; - } - log_warn(LD_FS, "Fixing permissions on directory %s", dirname); - new_mode = st.st_mode; - new_mode |= 0700; /* Owner should have rwx */ - if (check & CPD_GROUP_READ) { - new_mode |= 0050; /* Group should have rx */ - } - new_mode &= ~unwanted_bits; /* Clear the bits that we didn't want set...*/ - if (fchmod(fd, new_mode)) { - log_warn(LD_FS, "Could not chmod directory %s: %s", dirname, - strerror(errno)); - close(fd); - return -1; - } else { - close(fd); - return 0; - } - } - close(fd); -#else /* !(!defined(_WIN32)) */ - /* Win32 case: we can't open() a directory. */ - (void)effective_user; - - char *f = tor_strdup(dirname); - clean_name_for_stat(f); - log_debug(LD_FS, "stat()ing %s", f); - r = stat(sandbox_intern_string(f), &st); - tor_free(f); - if (r) { - if (errno != ENOENT) { - log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, - strerror(errno)); - return -1; - } - if (check & CPD_CREATE) { - log_info(LD_GENERAL, "Creating directory %s", dirname); - r = mkdir(dirname); - if (r) { - log_warn(LD_FS, "Error creating directory %s: %s", dirname, - strerror(errno)); - return -1; - } - } else if (!(check & CPD_CHECK)) { - log_warn(LD_FS, "Directory %s does not exist.", dirname); - return -1; - } - return 0; - } - if (!(st.st_mode & S_IFDIR)) { - log_warn(LD_FS, "%s is not a directory", dirname); - return -1; - } - -#endif /* !defined(_WIN32) */ - return 0; -} - -/** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite - * the previous <b>fname</b> if possible. Return 0 on success, -1 on failure. - * - * This function replaces the old file atomically, if possible. This - * function, and all other functions in util.c that create files, create them - * with mode 0600. - */ -MOCK_IMPL(int, -write_str_to_file,(const char *fname, const char *str, int bin)) -{ -#ifdef _WIN32 - if (!bin && strchr(str, '\r')) { - log_warn(LD_BUG, - "We're writing a text string that already contains a CR to %s", - escaped(fname)); - } -#endif /* defined(_WIN32) */ - return write_bytes_to_file(fname, str, strlen(str), bin); -} - -/** Represents a file that we're writing to, with support for atomic commit: - * we can write into a temporary file, and either remove the file on - * failure, or replace the original file on success. */ -struct open_file_t { - char *tempname; /**< Name of the temporary file. */ - char *filename; /**< Name of the original file. */ - unsigned rename_on_close:1; /**< Are we using the temporary file or not? */ - unsigned binary:1; /**< Did we open in binary mode? */ - int fd; /**< fd for the open file. */ - FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */ -}; - -/** Try to start writing to the file in <b>fname</b>, passing the flags - * <b>open_flags</b> to the open() syscall, creating the file (if needed) with - * access value <b>mode</b>. If the O_APPEND flag is set, we append to the - * original file. Otherwise, we open a new temporary file in the same - * directory, and either replace the original or remove the temporary file - * when we're done. - * - * Return the fd for the newly opened file, and store working data in - * *<b>data_out</b>. The caller should not close the fd manually: - * instead, call finish_writing_to_file() or abort_writing_to_file(). - * Returns -1 on failure. - * - * NOTE: When not appending, the flags O_CREAT and O_TRUNC are treated - * as true and the flag O_EXCL is treated as false. - * - * NOTE: Ordinarily, O_APPEND means "seek to the end of the file before each - * write()". We don't do that. - */ -int -start_writing_to_file(const char *fname, int open_flags, int mode, - open_file_t **data_out) -{ - open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t)); - const char *open_name; - int append = 0; - - tor_assert(fname); - tor_assert(data_out); -#if (O_BINARY != 0 && O_TEXT != 0) - tor_assert((open_flags & (O_BINARY|O_TEXT)) != 0); -#endif - new_file->fd = -1; - new_file->filename = tor_strdup(fname); - if (open_flags & O_APPEND) { - open_name = fname; - new_file->rename_on_close = 0; - append = 1; - open_flags &= ~O_APPEND; - } else { - tor_asprintf(&new_file->tempname, "%s.tmp", fname); - open_name = new_file->tempname; - /* We always replace an existing temporary file if there is one. */ - open_flags |= O_CREAT|O_TRUNC; - open_flags &= ~O_EXCL; - new_file->rename_on_close = 1; - } -#if O_BINARY != 0 - if (open_flags & O_BINARY) - new_file->binary = 1; -#endif - - new_file->fd = tor_open_cloexec(open_name, open_flags, mode); - if (new_file->fd < 0) { - log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s", - open_name, fname, strerror(errno)); - goto err; - } - if (append) { - if (tor_fd_seekend(new_file->fd) < 0) { - log_warn(LD_FS, "Couldn't seek to end of file \"%s\": %s", open_name, - strerror(errno)); - goto err; - } - } - - *data_out = new_file; - - return new_file->fd; - - err: - if (new_file->fd >= 0) - close(new_file->fd); - *data_out = NULL; - tor_free(new_file->filename); - tor_free(new_file->tempname); - tor_free(new_file); - return -1; -} - -/** Given <b>file_data</b> from start_writing_to_file(), return a stdio FILE* - * that can be used to write to the same file. The caller should not mix - * stdio calls with non-stdio calls. */ -FILE * -fdopen_file(open_file_t *file_data) -{ - tor_assert(file_data); - if (file_data->stdio_file) - return file_data->stdio_file; - tor_assert(file_data->fd >= 0); - if (!(file_data->stdio_file = fdopen(file_data->fd, - file_data->binary?"ab":"a"))) { - log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename, - file_data->fd, strerror(errno)); - } - return file_data->stdio_file; -} - -/** Combines start_writing_to_file with fdopen_file(): arguments are as - * for start_writing_to_file, but */ -FILE * -start_writing_to_stdio_file(const char *fname, int open_flags, int mode, - open_file_t **data_out) -{ - FILE *res; - if (start_writing_to_file(fname, open_flags, mode, data_out)<0) - return NULL; - if (!(res = fdopen_file(*data_out))) { - abort_writing_to_file(*data_out); - *data_out = NULL; - } - return res; -} - -/** Helper function: close and free the underlying file and memory in - * <b>file_data</b>. If we were writing into a temporary file, then delete - * that file (if abort_write is true) or replaces the target file with - * the temporary file (if abort_write is false). */ -static int -finish_writing_to_file_impl(open_file_t *file_data, int abort_write) -{ - int r = 0; - - tor_assert(file_data && file_data->filename); - if (file_data->stdio_file) { - if (fclose(file_data->stdio_file)) { - log_warn(LD_FS, "Error closing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - } else if (file_data->fd >= 0 && close(file_data->fd) < 0) { - log_warn(LD_FS, "Error flushing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - - if (file_data->rename_on_close) { - tor_assert(file_data->tempname && file_data->filename); - if (!abort_write) { - tor_assert(strcmp(file_data->filename, file_data->tempname)); - if (replace_file(file_data->tempname, file_data->filename)) { - log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename, - strerror(errno)); - abort_write = r = -1; - } - } - if (abort_write) { - int res = unlink(file_data->tempname); - if (res != 0) { - /* We couldn't unlink and we'll leave a mess behind */ - log_warn(LD_FS, "Failed to unlink %s: %s", - file_data->tempname, strerror(errno)); - r = -1; - } - } - } - - tor_free(file_data->filename); - tor_free(file_data->tempname); - tor_free(file_data); - - return r; -} - -/** Finish writing to <b>file_data</b>: close the file handle, free memory as - * needed, and if using a temporary file, replace the original file with - * the temporary file. */ -int -finish_writing_to_file(open_file_t *file_data) -{ - return finish_writing_to_file_impl(file_data, 0); -} - -/** Finish writing to <b>file_data</b>: close the file handle, free memory as - * needed, and if using a temporary file, delete it. */ -int -abort_writing_to_file(open_file_t *file_data) -{ - return finish_writing_to_file_impl(file_data, 1); -} - -/** Helper: given a set of flags as passed to open(2), open the file - * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to - * the file. Do so as atomically as possible e.g. by opening temp files and - * renaming. */ -static int -write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks, - int open_flags) -{ - open_file_t *file = NULL; - int fd; - ssize_t result; - fd = start_writing_to_file(fname, open_flags, 0600, &file); - if (fd<0) - return -1; - SMARTLIST_FOREACH(chunks, sized_chunk_t *, chunk, - { - result = write_all(fd, chunk->bytes, chunk->len, 0); - if (result < 0) { - log_warn(LD_FS, "Error writing to \"%s\": %s", fname, - strerror(errno)); - goto err; - } - tor_assert((size_t)result == chunk->len); - }); - - return finish_writing_to_file(file); - err: - abort_writing_to_file(file); - return -1; -} - -/** Given a smartlist of sized_chunk_t, write them to a file - * <b>fname</b>, overwriting or creating the file as necessary. - * If <b>no_tempfile</b> is 0 then the file will be written - * atomically. */ -int -write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin, - int no_tempfile) -{ - int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT); - - if (no_tempfile) { - /* O_APPEND stops write_chunks_to_file from using tempfiles */ - flags |= O_APPEND; - } - return write_chunks_to_file_impl(fname, chunks, flags); -} - -/** Write <b>len</b> bytes, starting at <b>str</b>, to <b>fname</b> - using the open() flags passed in <b>flags</b>. */ -static int -write_bytes_to_file_impl(const char *fname, const char *str, size_t len, - int flags) -{ - int r; - sized_chunk_t c = { str, len }; - smartlist_t *chunks = smartlist_new(); - smartlist_add(chunks, &c); - r = write_chunks_to_file_impl(fname, chunks, flags); - smartlist_free(chunks); - return r; -} - -/** As write_str_to_file, but does not assume a NUL-terminated - * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */ -MOCK_IMPL(int, -write_bytes_to_file,(const char *fname, const char *str, size_t len, - int bin)) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT)); -} - -/** As write_bytes_to_file, but if the file already exists, append the bytes - * to the end of the file instead of overwriting it. */ -int -append_bytes_to_file(const char *fname, const char *str, size_t len, - int bin) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT)); -} - -/** Like write_str_to_file(), but also return -1 if there was a file - already residing in <b>fname</b>. */ -int -write_bytes_to_new_file(const char *fname, const char *str, size_t len, - int bin) -{ - return write_bytes_to_file_impl(fname, str, len, - OPEN_FLAGS_DONT_REPLACE| - (bin?O_BINARY:O_TEXT)); -} - -/** - * Read the contents of the open file <b>fd</b> presuming it is a FIFO - * (or similar) file descriptor for which the size of the file isn't - * known ahead of time. Return NULL on failure, and a NUL-terminated - * string on success. On success, set <b>sz_out</b> to the number of - * bytes read. - */ -char * -read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) -{ - ssize_t r; - size_t pos = 0; - char *string = NULL; - size_t string_max = 0; - - if (max_bytes_to_read+1 >= SIZE_T_CEILING) { - errno = EINVAL; - return NULL; - } - - do { - /* XXXX This "add 1K" approach is a little goofy; if we care about - * performance here, we should be doubling. But in practice we shouldn't - * be using this function on big files anyway. */ - string_max = pos + 1024; - if (string_max > max_bytes_to_read) - string_max = max_bytes_to_read + 1; - string = tor_realloc(string, string_max); - r = read(fd, string + pos, string_max - pos - 1); - if (r < 0) { - int save_errno = errno; - tor_free(string); - errno = save_errno; - return NULL; - } - - pos += r; - } while (r > 0 && pos < max_bytes_to_read); - - tor_assert(pos < string_max); - *sz_out = pos; - string[pos] = '\0'; - return string; -} - -/** Read the contents of <b>filename</b> into a newly allocated - * string; return the string on success or NULL on failure. - * - * If <b>stat_out</b> is provided, store the result of stat()ing the - * file into <b>stat_out</b>. - * - * If <b>flags</b> & RFTS_BIN, open the file in binary mode. - * If <b>flags</b> & RFTS_IGNORE_MISSING, don't warn if the file - * doesn't exist. - */ -/* - * This function <em>may</em> return an erroneous result if the file - * is modified while it is running, but must not crash or overflow. - * Right now, the error case occurs when the file length grows between - * the call to stat and the call to read_all: the resulting string will - * be truncated. - */ -MOCK_IMPL(char *, -read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) -{ - int fd; /* router file */ - struct stat statbuf; - char *string; - ssize_t r; - int bin = flags & RFTS_BIN; - - tor_assert(filename); - - fd = tor_open_cloexec(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0); - if (fd<0) { - int severity = LOG_WARN; - int save_errno = errno; - if (errno == ENOENT && (flags & RFTS_IGNORE_MISSING)) - severity = LOG_INFO; - log_fn(severity, LD_FS,"Could not open \"%s\": %s",filename, - strerror(errno)); - errno = save_errno; - return NULL; - } - - if (fstat(fd, &statbuf)<0) { - int save_errno = errno; - close(fd); - log_warn(LD_FS,"Could not fstat \"%s\".",filename); - errno = save_errno; - return NULL; - } - -#ifndef _WIN32 -/** When we detect that we're reading from a FIFO, don't read more than - * this many bytes. It's insane overkill for most uses. */ -#define FIFO_READ_MAX (1024*1024) - if (S_ISFIFO(statbuf.st_mode)) { - size_t sz = 0; - string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz); - int save_errno = errno; - if (string && stat_out) { - statbuf.st_size = sz; - memcpy(stat_out, &statbuf, sizeof(struct stat)); - } - close(fd); - if (!string) - errno = save_errno; - return string; - } -#endif /* !defined(_WIN32) */ - - if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) { - close(fd); - errno = EINVAL; - return NULL; - } - - string = tor_malloc((size_t)(statbuf.st_size+1)); - - r = read_all(fd,string,(size_t)statbuf.st_size,0); - if (r<0) { - int save_errno = errno; - log_warn(LD_FS,"Error reading from file \"%s\": %s", filename, - strerror(errno)); - tor_free(string); - close(fd); - errno = save_errno; - return NULL; - } - string[r] = '\0'; /* NUL-terminate the result. */ - -#if defined(_WIN32) || defined(__CYGWIN__) - if (!bin && strchr(string, '\r')) { - log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped " - "when reading %s. Coping.", - filename); - tor_strstrip(string, "\r"); - r = strlen(string); - } - if (!bin) { - statbuf.st_size = (size_t) r; - } else -#endif /* defined(_WIN32) || defined(__CYGWIN__) */ - if (r != statbuf.st_size) { - /* Unless we're using text mode on win32, we'd better have an exact - * match for size. */ - int save_errno = errno; - log_warn(LD_FS,"Could read only %d of %ld bytes of file \"%s\".", - (int)r, (long)statbuf.st_size,filename); - tor_free(string); - close(fd); - errno = save_errno; - return NULL; - } - close(fd); - if (stat_out) { - memcpy(stat_out, &statbuf, sizeof(struct stat)); - } - - return string; -} - -#define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7') - -/** Given a c-style double-quoted escaped string in <b>s</b>, extract and - * decode its contents into a newly allocated string. On success, assign this - * string to *<b>result</b>, assign its length to <b>size_out</b> (if - * provided), and return a pointer to the position in <b>s</b> immediately - * after the string. On failure, return NULL. - */ -const char * -unescape_string(const char *s, char **result, size_t *size_out) -{ - const char *cp; - char *out; - if (s[0] != '\"') - return NULL; - cp = s+1; - while (1) { - switch (*cp) { - case '\0': - case '\n': - return NULL; - case '\"': - goto end_of_loop; - case '\\': - if (cp[1] == 'x' || cp[1] == 'X') { - if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3]))) - return NULL; - cp += 4; - } else if (TOR_ISODIGIT(cp[1])) { - cp += 2; - if (TOR_ISODIGIT(*cp)) ++cp; - if (TOR_ISODIGIT(*cp)) ++cp; - } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"' - || cp[1] == '\\' || cp[1] == '\'') { - cp += 2; - } else { - return NULL; - } - break; - default: - ++cp; - break; - } - } - end_of_loop: - out = *result = tor_malloc(cp-s + 1); - cp = s+1; - while (1) { - switch (*cp) - { - case '\"': - *out = '\0'; - if (size_out) *size_out = out - *result; - return cp+1; - - /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */ - case '\0': - tor_fragile_assert(); - tor_free(*result); - return NULL; - /* LCOV_EXCL_STOP */ - case '\\': - switch (cp[1]) - { - case 'n': *out++ = '\n'; cp += 2; break; - case 'r': *out++ = '\r'; cp += 2; break; - case 't': *out++ = '\t'; cp += 2; break; - case 'x': case 'X': - { - int x1, x2; - - x1 = hex_decode_digit(cp[2]); - x2 = hex_decode_digit(cp[3]); - if (x1 == -1 || x2 == -1) { - /* LCOV_EXCL_START */ - /* we caught this above in the initial loop. */ - tor_assert_nonfatal_unreached(); - tor_free(*result); - return NULL; - /* LCOV_EXCL_STOP */ - } - - *out++ = ((x1<<4) + x2); - cp += 4; - } - break; - case '0': case '1': case '2': case '3': case '4': case '5': - case '6': case '7': - { - int n = cp[1]-'0'; - cp += 2; - if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } - if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } - if (n > 255) { tor_free(*result); return NULL; } - *out++ = (char)n; - } - break; - case '\'': - case '\"': - case '\\': - case '\?': - *out++ = cp[1]; - cp += 2; - break; - - /* LCOV_EXCL_START */ - default: - /* we caught this above in the initial loop. */ - tor_assert_nonfatal_unreached(); - tor_free(*result); return NULL; - /* LCOV_EXCL_STOP */ - } - break; - default: - *out++ = *cp++; - } - } -} - -/** Removes enclosing quotes from <b>path</b> and unescapes quotes between the - * enclosing quotes. Backslashes are not unescaped. Return the unquoted - * <b>path</b> on success or 0 if <b>path</b> is not quoted correctly. */ -char * -get_unquoted_path(const char *path) -{ - size_t len = strlen(path); - - if (len == 0) { - return tor_strdup(""); - } - - int has_start_quote = (path[0] == '\"'); - int has_end_quote = (len > 0 && path[len-1] == '\"'); - if (has_start_quote != has_end_quote || (len == 1 && has_start_quote)) { - return NULL; - } - - char *unquoted_path = tor_malloc(len - has_start_quote - has_end_quote + 1); - char *s = unquoted_path; - size_t i; - for (i = has_start_quote; i < len - has_end_quote; i++) { - if (path[i] == '\"' && (i > 0 && path[i-1] == '\\')) { - *(s-1) = path[i]; - } else if (path[i] != '\"') { - *s++ = path[i]; - } else { /* unescaped quote */ - tor_free(unquoted_path); - return NULL; - } - } - *s = '\0'; - return unquoted_path; -} - -/** Expand any homedir prefix on <b>filename</b>; return a newly allocated - * string. */ -char * -expand_filename(const char *filename) -{ - tor_assert(filename); -#ifdef _WIN32 - /* Might consider using GetFullPathName() as described here: - * http://etutorials.org/Programming/secure+programming/ - * Chapter+3.+Input+Validation/3.7+Validating+Filenames+and+Paths/ - */ - return tor_strdup(filename); -#else /* !(defined(_WIN32)) */ - if (*filename == '~') { - char *home, *result=NULL; - const char *rest; - - if (filename[1] == '/' || filename[1] == '\0') { - home = getenv("HOME"); - if (!home) { - log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while " - "expanding \"%s\"; defaulting to \"\".", filename); - home = tor_strdup(""); - } else { - home = tor_strdup(home); - } - rest = strlen(filename)>=2?(filename+2):""; - } else { -#ifdef HAVE_PWD_H - char *username, *slash; - slash = strchr(filename, '/'); - if (slash) - username = tor_strndup(filename+1,slash-filename-1); - else - username = tor_strdup(filename+1); - if (!(home = get_user_homedir(username))) { - log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username); - tor_free(username); - return NULL; - } - tor_free(username); - rest = slash ? (slash+1) : ""; -#else /* !(defined(HAVE_PWD_H)) */ - log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h"); - return tor_strdup(filename); -#endif /* defined(HAVE_PWD_H) */ - } - tor_assert(home); - /* Remove trailing slash. */ - if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) { - home[strlen(home)-1] = '\0'; - } - tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest); - tor_free(home); - return result; - } else { - return tor_strdup(filename); - } -#endif /* defined(_WIN32) */ -} - -#define MAX_SCANF_WIDTH 9999 - -/** Helper: given an ASCII-encoded decimal digit, return its numeric value. - * NOTE: requires that its input be in-bounds. */ -static int -digit_to_num(char d) -{ - int num = ((int)d) - (int)'0'; - tor_assert(num <= 9 && num >= 0); - return num; -} - -/** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b> - * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On - * success, store the result in <b>out</b>, advance bufp to the next - * character, and return 0. On failure, return -1. */ -static int -scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base) -{ - unsigned long result = 0; - int scanned_so_far = 0; - const int hex = base==16; - tor_assert(base == 10 || base == 16); - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp)) - && scanned_so_far < width) { - unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); - // Check for overflow beforehand, without actually causing any overflow - // This preserves functionality on compilers that don't wrap overflow - // (i.e. that trap or optimise away overflow) - // result * base + digit > ULONG_MAX - // result * base > ULONG_MAX - digit - if (result > (ULONG_MAX - digit)/base) - return -1; /* Processing this digit would overflow */ - result = result * base + digit; - ++scanned_so_far; - } - - if (!scanned_so_far) /* No actual digits scanned */ - return -1; - - *out = result; - return 0; -} - -/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b> - * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On - * success, store the result in <b>out</b>, advance bufp to the next - * character, and return 0. On failure, return -1. */ -static int -scan_signed(const char **bufp, long *out, int width) -{ - int neg = 0; - unsigned long result = 0; - - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - if (**bufp == '-') { - neg = 1; - ++*bufp; - --width; - } - - if (scan_unsigned(bufp, &result, width, 10) < 0) - return -1; - - if (neg && result > 0) { - if (result > ((unsigned long)LONG_MAX) + 1) - return -1; /* Underflow */ - else if (result == ((unsigned long)LONG_MAX) + 1) - *out = LONG_MIN; - else { - /* We once had a far more clever no-overflow conversion here, but - * some versions of GCC apparently ran it into the ground. Now - * we just check for LONG_MIN explicitly. - */ - *out = -(long)result; - } - } else { - if (result > LONG_MAX) - return -1; /* Overflow */ - *out = (long)result; - } - - return 0; -} - -/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to - * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less - * than 0.) On success, store the result in <b>out</b>, advance bufp to the - * next character, and return 0. On failure, return -1. */ -static int -scan_double(const char **bufp, double *out, int width) -{ - int neg = 0; - double result = 0; - int scanned_so_far = 0; - - if (!bufp || !*bufp || !out) - return -1; - if (width<0) - width=MAX_SCANF_WIDTH; - - if (**bufp == '-') { - neg = 1; - ++*bufp; - } - - while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { - const int digit = digit_to_num(*(*bufp)++); - result = result * 10 + digit; - ++scanned_so_far; - } - if (**bufp == '.') { - double fracval = 0, denominator = 1; - ++*bufp; - ++scanned_so_far; - while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { - const int digit = digit_to_num(*(*bufp)++); - fracval = fracval * 10 + digit; - denominator *= 10; - ++scanned_so_far; - } - result += fracval / denominator; - } - - if (!scanned_so_far) /* No actual digits scanned */ - return -1; - - *out = neg ? -result : result; - return 0; -} - -/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to - * <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b> - * to the next non-space character or the EOS. */ -static int -scan_string(const char **bufp, char *out, int width) -{ - int scanned_so_far = 0; - if (!bufp || !out || width < 0) - return -1; - while (**bufp && ! TOR_ISSPACE(**bufp) && scanned_so_far < width) { - *out++ = *(*bufp)++; - ++scanned_so_far; - } - *out = '\0'; - return 0; -} - -/** Locale-independent, minimal, no-surprises scanf variant, accepting only a - * restricted pattern format. For more info on what it supports, see - * tor_sscanf() documentation. */ -int -tor_vsscanf(const char *buf, const char *pattern, va_list ap) -{ - int n_matched = 0; - - while (*pattern) { - if (*pattern != '%') { - if (*buf == *pattern) { - ++buf; - ++pattern; - continue; - } else { - return n_matched; - } - } else { - int width = -1; - int longmod = 0; - ++pattern; - if (TOR_ISDIGIT(*pattern)) { - width = digit_to_num(*pattern++); - while (TOR_ISDIGIT(*pattern)) { - width *= 10; - width += digit_to_num(*pattern++); - if (width > MAX_SCANF_WIDTH) - return -1; - } - if (!width) /* No zero-width things. */ - return -1; - } - if (*pattern == 'l') { - longmod = 1; - ++pattern; - } - if (*pattern == 'u' || *pattern == 'x') { - unsigned long u; - const int base = (*pattern == 'u') ? 10 : 16; - if (!*buf) - return n_matched; - if (scan_unsigned(&buf, &u, width, base)<0) - return n_matched; - if (longmod) { - unsigned long *out = va_arg(ap, unsigned long *); - *out = u; - } else { - unsigned *out = va_arg(ap, unsigned *); - if (u > UINT_MAX) - return n_matched; - *out = (unsigned) u; - } - ++pattern; - ++n_matched; - } else if (*pattern == 'f') { - double *d = va_arg(ap, double *); - if (!longmod) - return -1; /* float not supported */ - if (!*buf) - return n_matched; - if (scan_double(&buf, d, width)<0) - return n_matched; - ++pattern; - ++n_matched; - } else if (*pattern == 'd') { - long lng=0; - if (scan_signed(&buf, &lng, width)<0) - return n_matched; - if (longmod) { - long *out = va_arg(ap, long *); - *out = lng; - } else { - int *out = va_arg(ap, int *); -#if LONG_MAX > INT_MAX - if (lng < INT_MIN || lng > INT_MAX) - return n_matched; -#endif - *out = (int)lng; - } - ++pattern; - ++n_matched; - } else if (*pattern == 's') { - char *s = va_arg(ap, char *); - if (longmod) - return -1; - if (width < 0) - return -1; - if (scan_string(&buf, s, width)<0) - return n_matched; - ++pattern; - ++n_matched; - } else if (*pattern == 'c') { - char *ch = va_arg(ap, char *); - if (longmod) - return -1; - if (width != -1) - return -1; - if (!*buf) - return n_matched; - *ch = *buf++; - ++pattern; - ++n_matched; - } else if (*pattern == '%') { - if (*buf != '%') - return n_matched; - if (longmod) - return -1; - ++buf; - ++pattern; - } else { - return -1; /* Unrecognized pattern component. */ - } - } - } - - return n_matched; -} - -/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b> - * and store the results in the corresponding argument fields. Differs from - * sscanf in that: - * <ul><li>It only handles %u, %lu, %x, %lx, %[NUM]s, %d, %ld, %lf, and %c. - * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1) - * <li>It does not handle arbitrarily long widths. - * <li>Numbers do not consume any space characters. - * <li>It is locale-independent. - * <li>%u and %x do not consume any space. - * <li>It returns -1 on malformed patterns.</ul> - * - * (As with other locale-independent functions, we need this to parse data that - * is in ASCII without worrying that the C library's locale-handling will make - * miscellaneous characters look like numbers, spaces, and so on.) - */ -int -tor_sscanf(const char *buf, const char *pattern, ...) -{ - int r; - va_list ap; - va_start(ap, pattern); - r = tor_vsscanf(buf, pattern, ap); - va_end(ap); - return r; -} - -/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>) - * to <b>sl</b>. */ -void -smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) -{ - va_list ap; - va_start(ap, pattern); - smartlist_add_vasprintf(sl, pattern, ap); - va_end(ap); -} - -/** va_list-based backend of smartlist_add_asprintf. */ -void -smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, - va_list args) -{ - char *str = NULL; - - tor_vasprintf(&str, pattern, args); - tor_assert(str != NULL); - - smartlist_add(sl, str); -} - -/** Append a copy of string to sl */ -void -smartlist_add_strdup(struct smartlist_t *sl, const char *string) -{ - char *copy; - - copy = tor_strdup(string); - - smartlist_add(sl, copy); -} - -/** Return a new list containing the filenames in the directory <b>dirname</b>. - * Return NULL on error or if <b>dirname</b> is not a directory. - */ -MOCK_IMPL(smartlist_t *, -tor_listdir, (const char *dirname)) -{ - smartlist_t *result; -#ifdef _WIN32 - char *pattern=NULL; - TCHAR tpattern[MAX_PATH] = {0}; - char name[MAX_PATH*2+1] = {0}; - HANDLE handle; - WIN32_FIND_DATA findData; - tor_asprintf(&pattern, "%s\\*", dirname); -#ifdef UNICODE - mbstowcs(tpattern,pattern,MAX_PATH); -#else - strlcpy(tpattern, pattern, MAX_PATH); -#endif - if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) { - tor_free(pattern); - return NULL; - } - result = smartlist_new(); - while (1) { -#ifdef UNICODE - wcstombs(name,findData.cFileName,MAX_PATH); - name[sizeof(name)-1] = '\0'; -#else - strlcpy(name,findData.cFileName,sizeof(name)); -#endif /* defined(UNICODE) */ - if (strcmp(name, ".") && - strcmp(name, "..")) { - smartlist_add_strdup(result, name); - } - if (!FindNextFile(handle, &findData)) { - DWORD err; - if ((err = GetLastError()) != ERROR_NO_MORE_FILES) { - char *errstr = format_win32_error(err); - log_warn(LD_FS, "Error reading directory '%s': %s", dirname, errstr); - tor_free(errstr); - } - break; - } - } - FindClose(handle); - tor_free(pattern); -#else /* !(defined(_WIN32)) */ - const char *prot_dname = sandbox_intern_string(dirname); - DIR *d; - struct dirent *de; - if (!(d = opendir(prot_dname))) - return NULL; - - result = smartlist_new(); - while ((de = readdir(d))) { - if (!strcmp(de->d_name, ".") || - !strcmp(de->d_name, "..")) - continue; - smartlist_add_strdup(result, de->d_name); - } - closedir(d); -#endif /* defined(_WIN32) */ - return result; -} - -/** Return true iff <b>filename</b> is a relative path. */ -int -path_is_relative(const char *filename) -{ - if (filename && filename[0] == '/') - return 0; -#ifdef _WIN32 - else if (filename && filename[0] == '\\') - return 0; - else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) && - filename[1] == ':' && filename[2] == '\\') - return 0; -#endif /* defined(_WIN32) */ - else - return 1; -} - -/* ===== - * Process helpers - * ===== */ - -#ifndef _WIN32 -/* Based on code contributed by christian grothoff */ -/** True iff we've called start_daemon(). */ -static int start_daemon_called = 0; -/** True iff we've called finish_daemon(). */ -static int finish_daemon_called = 0; -/** Socketpair used to communicate between parent and child process while - * daemonizing. */ -static int daemon_filedes[2]; -/** Start putting the process into daemon mode: fork and drop all resources - * except standard fds. The parent process never returns, but stays around - * until finish_daemon is called. (Note: it's safe to call this more - * than once: calls after the first are ignored.) - */ -void -start_daemon(void) -{ - pid_t pid; - - if (start_daemon_called) - return; - start_daemon_called = 1; - - if (pipe(daemon_filedes)) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno)); - exit(1); // exit ok: during daemonize, pipe failed. - /* LCOV_EXCL_STOP */ - } - pid = fork(); - if (pid < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"fork failed. Exiting."); - exit(1); // exit ok: during daemonize, fork failed - /* LCOV_EXCL_STOP */ - } - if (pid) { /* Parent */ - int ok; - char c; - - close(daemon_filedes[1]); /* we only read */ - ok = -1; - while (0 < read(daemon_filedes[0], &c, sizeof(char))) { - if (c == '.') - ok = 1; - } - fflush(stdout); - if (ok == 1) - exit(0); // exit ok: during daemonize, daemonizing. - else - exit(1); /* child reported error. exit ok: daemonize failed. */ - } else { /* Child */ - close(daemon_filedes[0]); /* we only write */ - - (void) setsid(); /* Detach from controlling terminal */ - /* - * Fork one more time, so the parent (the session group leader) can exit. - * This means that we, as a non-session group leader, can never regain a - * controlling terminal. This part is recommended by Stevens's - * _Advanced Programming in the Unix Environment_. - */ - if (fork() != 0) { - exit(0); // exit ok: during daemonize, fork failed (2) - } - set_main_thread(); /* We are now the main thread. */ - - return; - } -} - -/** Finish putting the process into daemon mode: drop standard fds, and tell - * the parent process to exit. (Note: it's safe to call this more than once: - * calls after the first are ignored. Calls start_daemon first if it hasn't - * been called already.) - */ -void -finish_daemon(const char *desired_cwd) -{ - int nullfd; - char c = '.'; - if (finish_daemon_called) - return; - if (!start_daemon_called) - start_daemon(); - finish_daemon_called = 1; - - if (!desired_cwd) - desired_cwd = "/"; - /* Don't hold the wrong FS mounted */ - if (chdir(desired_cwd) < 0) { - log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd); - exit(1); // exit ok: during daemonize, chdir failed. - } - - nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0); - if (nullfd < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"/dev/null can't be opened. Exiting."); - exit(1); // exit ok: during daemonize, couldn't open /dev/null - /* LCOV_EXCL_STOP */ - } - /* close fds linking to invoking terminal, but - * close usual incoming fds, but redirect them somewhere - * useful so the fds don't get reallocated elsewhere. - */ - if (dup2(nullfd,0) < 0 || - dup2(nullfd,1) < 0 || - dup2(nullfd,2) < 0) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"dup2 failed. Exiting."); - exit(1); // exit ok: during daemonize, dup2 failed. - /* LCOV_EXCL_STOP */ - } - if (nullfd > 2) - close(nullfd); - /* signal success */ - if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) { - log_err(LD_GENERAL,"write failed. Exiting."); - } - close(daemon_filedes[1]); -} -#else /* !(!defined(_WIN32)) */ -/* defined(_WIN32) */ -void -start_daemon(void) -{ -} -void -finish_daemon(const char *cp) -{ - (void)cp; -} -#endif /* !defined(_WIN32) */ - -/** Write the current process ID, followed by NL, into <b>filename</b>. - * Return 0 on success, -1 on failure. - */ -int -write_pidfile(const char *filename) -{ - FILE *pidfile; - - if ((pidfile = fopen(filename, "w")) == NULL) { - log_warn(LD_FS, "Unable to open \"%s\" for writing: %s", filename, - strerror(errno)); - return -1; - } else { -#ifdef _WIN32 - int pid = (int)_getpid(); -#else - int pid = (int)getpid(); -#endif - int rv = 0; - if (fprintf(pidfile, "%d\n", pid) < 0) - rv = -1; - if (fclose(pidfile) < 0) - rv = -1; - return rv; - } -} - -#ifdef _WIN32 -HANDLE -load_windows_system_library(const TCHAR *library_name) -{ - TCHAR path[MAX_PATH]; - unsigned n; - n = GetSystemDirectory(path, MAX_PATH); - if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH) - return 0; - _tcscat(path, TEXT("\\")); - _tcscat(path, library_name); - return LoadLibrary(path); -} -#endif /* defined(_WIN32) */ - -/** Format a single argument for being put on a Windows command line. - * Returns a newly allocated string */ -static char * -format_win_cmdline_argument(const char *arg) -{ - char *formatted_arg; - char need_quotes; - const char *c; - int i; - int bs_counter = 0; - /* Backslash we can point to when one is inserted into the string */ - const char backslash = '\\'; - - /* Smartlist of *char */ - smartlist_t *arg_chars; - arg_chars = smartlist_new(); - - /* Quote string if it contains whitespace or is empty */ - need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]); - - /* Build up smartlist of *chars */ - for (c=arg; *c != '\0'; c++) { - if ('"' == *c) { - /* Double up backslashes preceding a quote */ - for (i=0; i<(bs_counter*2); i++) - smartlist_add(arg_chars, (void*)&backslash); - bs_counter = 0; - /* Escape the quote */ - smartlist_add(arg_chars, (void*)&backslash); - smartlist_add(arg_chars, (void*)c); - } else if ('\\' == *c) { - /* Count backslashes until we know whether to double up */ - bs_counter++; - } else { - /* Don't double up slashes preceding a non-quote */ - for (i=0; i<bs_counter; i++) - smartlist_add(arg_chars, (void*)&backslash); - bs_counter = 0; - smartlist_add(arg_chars, (void*)c); - } - } - /* Don't double up trailing backslashes */ - for (i=0; i<bs_counter; i++) - smartlist_add(arg_chars, (void*)&backslash); - - /* Allocate space for argument, quotes (if needed), and terminator */ - const size_t formatted_arg_len = smartlist_len(arg_chars) + - (need_quotes ? 2 : 0) + 1; - formatted_arg = tor_malloc_zero(formatted_arg_len); - - /* Add leading quote */ - i=0; - if (need_quotes) - formatted_arg[i++] = '"'; - - /* Add characters */ - SMARTLIST_FOREACH(arg_chars, char*, ch, - { - formatted_arg[i++] = *ch; - }); - - /* Add trailing quote */ - if (need_quotes) - formatted_arg[i++] = '"'; - formatted_arg[i] = '\0'; - - smartlist_free(arg_chars); - return formatted_arg; -} - -/** Format a command line for use on Windows, which takes the command as a - * string rather than string array. Follows the rules from "Parsing C++ - * Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the - * Python subprocess module. Returns a newly allocated string */ -char * -tor_join_win_cmdline(const char *argv[]) -{ - smartlist_t *argv_list; - char *joined_argv; - int i; - - /* Format each argument and put the result in a smartlist */ - argv_list = smartlist_new(); - for (i=0; argv[i] != NULL; i++) { - smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i])); - } - - /* Join the arguments with whitespace */ - joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL); - - /* Free the newly allocated arguments, and the smartlist */ - SMARTLIST_FOREACH(argv_list, char *, arg, - { - tor_free(arg); - }); - smartlist_free(argv_list); - - return joined_argv; -} - -/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument - * in range 2..16 inclusive. */ -static int -format_number_sigsafe(unsigned long x, char *buf, int buf_len, - unsigned int radix) -{ - unsigned long tmp; - int len; - char *cp; - - /* NOT tor_assert. This needs to be safe to run from within a signal handler, - * and from within the 'tor_assert() has failed' code. */ - if (radix < 2 || radix > 16) - return 0; - - /* Count how many digits we need. */ - tmp = x; - len = 1; - while (tmp >= radix) { - tmp /= radix; - ++len; - } - - /* Not long enough */ - if (!buf || len >= buf_len) - return 0; - - cp = buf + len; - *cp = '\0'; - do { - unsigned digit = (unsigned) (x % radix); - tor_assert(cp > buf); - --cp; - *cp = "0123456789ABCDEF"[digit]; - x /= radix; - } while (x); - - /* NOT tor_assert; see above. */ - if (cp != buf) { - abort(); // LCOV_EXCL_LINE - } - - return len; -} - -/** - * Helper function to output hex numbers from within a signal handler. - * - * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer - * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits - * written, not counting the terminal NUL. - * - * If there is insufficient space, write nothing and return 0. - * - * This accepts an unsigned int because format_helper_exit_status() needs to - * call it with a signed int and an unsigned char, and since the C standard - * does not guarantee that an int is wider than a char (an int must be at - * least 16 bits but it is permitted for a char to be that wide as well), we - * can't assume a signed int is sufficient to accommodate an unsigned char. - * Thus, format_helper_exit_status() will still need to emit any require '-' - * on its own. - * - * For most purposes, you'd want to use tor_snprintf("%x") instead of this - * function; it's designed to be used in code paths where you can't call - * arbitrary C functions. - */ -int -format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len) -{ - return format_number_sigsafe(x, buf, buf_len, 16); -} - -/** As format_hex_number_sigsafe, but format the number in base 10. */ -int -format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len) -{ - return format_number_sigsafe(x, buf, buf_len, 10); -} - -#ifndef _WIN32 -/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in - * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler - * safe. - * - * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE+1 bytes available. - * - * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded - * with spaces. CHILD_STATE indicates where - * in the process of starting the child process did the failure occur (see - * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of - * errno when the failure occurred. - * - * On success return the number of characters added to hex_errno, not counting - * the terminating NUL; return -1 on error. - */ -STATIC int -format_helper_exit_status(unsigned char child_state, int saved_errno, - char *hex_errno) -{ - unsigned int unsigned_errno; - int written, left; - char *cur; - size_t i; - int res = -1; - - /* Fill hex_errno with spaces, and a trailing newline (memset may - not be signal handler safe, so we can't use it) */ - for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++) - hex_errno[i] = ' '; - hex_errno[HEX_ERRNO_SIZE - 1] = '\n'; - - /* Convert errno to be unsigned for hex conversion */ - if (saved_errno < 0) { - // Avoid overflow on the cast to unsigned int when result is INT_MIN - // by adding 1 to the signed int negative value, - // then, after it has been negated and cast to unsigned, - // adding the original 1 back (the double-addition is intentional). - // Otherwise, the cast to signed could cause a temporary int - // to equal INT_MAX + 1, which is undefined. - unsigned_errno = ((unsigned int) -(saved_errno + 1)) + 1; - } else { - unsigned_errno = (unsigned int) saved_errno; - } - - /* - * Count how many chars of space we have left, and keep a pointer into the - * current point in the buffer. - */ - left = HEX_ERRNO_SIZE+1; - cur = hex_errno; - - /* Emit child_state */ - written = format_hex_number_sigsafe(child_state, cur, left); - - if (written <= 0) - goto err; - - /* Adjust left and cur */ - left -= written; - cur += written; - if (left <= 0) - goto err; - - /* Now the '/' */ - *cur = '/'; - - /* Adjust left and cur */ - ++cur; - --left; - if (left <= 0) - goto err; - - /* Need minus? */ - if (saved_errno < 0) { - *cur = '-'; - ++cur; - --left; - if (left <= 0) - goto err; - } - - /* Emit unsigned_errno */ - written = format_hex_number_sigsafe(unsigned_errno, cur, left); - - if (written <= 0) - goto err; - - /* Adjust left and cur */ - left -= written; - cur += written; - - /* Check that we have enough space left for a newline and a NUL */ - if (left <= 1) - goto err; - - /* Emit the newline and NUL */ - *cur++ = '\n'; - *cur++ = '\0'; - - res = (int)(cur - hex_errno - 1); - - goto done; - - err: - /* - * In error exit, just write a '\0' in the first char so whatever called - * this at least won't fall off the end. - */ - *hex_errno = '\0'; - - done: - return res; -} -#endif /* !defined(_WIN32) */ - -/* Maximum number of file descriptors, if we cannot get it via sysconf() */ -#define DEFAULT_MAX_FD 256 - -/** Terminate the process of <b>process_handle</b>, if that process has not - * already exited. - * - * Return 0 if we succeeded in terminating the process (or if the process - * already exited), and -1 if we tried to kill the process but failed. - * - * Based on code originally borrowed from Python's os.kill. */ -int -tor_terminate_process(process_handle_t *process_handle) -{ -#ifdef _WIN32 - if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) { - HANDLE handle = process_handle->pid.hProcess; - - if (!TerminateProcess(handle, 0)) - return -1; - else - return 0; - } -#else /* !(defined(_WIN32)) */ - if (process_handle->waitpid_cb) { - /* We haven't got a waitpid yet, so we can just kill off the process. */ - return kill(process_handle->pid, SIGTERM); - } -#endif /* defined(_WIN32) */ - - return 0; /* We didn't need to kill the process, so report success */ -} - -/** Return the Process ID of <b>process_handle</b>. */ -int -tor_process_get_pid(process_handle_t *process_handle) -{ -#ifdef _WIN32 - return (int) process_handle->pid.dwProcessId; -#else - return (int) process_handle->pid; -#endif -} - -#ifdef _WIN32 -HANDLE -tor_process_get_stdout_pipe(process_handle_t *process_handle) -{ - return process_handle->stdout_pipe; -} -#else /* !(defined(_WIN32)) */ -/* DOCDOC tor_process_get_stdout_pipe */ -int -tor_process_get_stdout_pipe(process_handle_t *process_handle) -{ - return process_handle->stdout_pipe; -} -#endif /* defined(_WIN32) */ - -/* DOCDOC process_handle_new */ -static process_handle_t * -process_handle_new(void) -{ - process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t)); - -#ifdef _WIN32 - out->stdin_pipe = INVALID_HANDLE_VALUE; - out->stdout_pipe = INVALID_HANDLE_VALUE; - out->stderr_pipe = INVALID_HANDLE_VALUE; -#else - out->stdin_pipe = -1; - out->stdout_pipe = -1; - out->stderr_pipe = -1; -#endif /* defined(_WIN32) */ - - return out; -} - -#ifndef _WIN32 -/** Invoked when a process that we've launched via tor_spawn_background() has - * been found to have terminated. - */ -static void -process_handle_waitpid_cb(int status, void *arg) -{ - process_handle_t *process_handle = arg; - - process_handle->waitpid_exit_status = status; - clear_waitpid_callback(process_handle->waitpid_cb); - if (process_handle->status == PROCESS_STATUS_RUNNING) - process_handle->status = PROCESS_STATUS_NOTRUNNING; - process_handle->waitpid_cb = 0; -} -#endif /* !defined(_WIN32) */ - -/** - * @name child-process states - * - * Each of these values represents a possible state that a child process can - * be in. They're used to determine what to say when telling the parent how - * far along we were before failure. - * - * @{ - */ -#define CHILD_STATE_INIT 0 -#define CHILD_STATE_PIPE 1 -#define CHILD_STATE_MAXFD 2 -#define CHILD_STATE_FORK 3 -#define CHILD_STATE_DUPOUT 4 -#define CHILD_STATE_DUPERR 5 -#define CHILD_STATE_DUPIN 6 -#define CHILD_STATE_CLOSEFD 7 -#define CHILD_STATE_EXEC 8 -#define CHILD_STATE_FAILEXEC 9 -/** @} */ -/** - * Boolean. If true, then Tor may call execve or CreateProcess via - * tor_spawn_background. - **/ -static int may_spawn_background_process = 1; -/** - * Turn off may_spawn_background_process, so that all future calls to - * tor_spawn_background are guaranteed to fail. - **/ -void -tor_disable_spawning_background_processes(void) -{ - may_spawn_background_process = 0; -} -/** Start a program in the background. If <b>filename</b> contains a '/', then - * it will be treated as an absolute or relative path. Otherwise, on - * non-Windows systems, the system path will be searched for <b>filename</b>. - * On Windows, only the current directory will be searched. Here, to search the - * system path (as well as the application directory, current working - * directory, and system directories), set filename to NULL. - * - * The strings in <b>argv</b> will be passed as the command line arguments of - * the child program (following convention, argv[0] should normally be the - * filename of the executable, and this must be the case if <b>filename</b> is - * NULL). The last element of argv must be NULL. A handle to the child process - * will be returned in process_handle (which must be non-NULL). Read - * process_handle.status to find out if the process was successfully launched. - * For convenience, process_handle.status is returned by this function. - * - * Some parts of this code are based on the POSIX subprocess module from - * Python, and example code from - * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx. - */ -int -tor_spawn_background(const char *const filename, const char **argv, - process_environment_t *env, - process_handle_t **process_handle_out) -{ - if (BUG(may_spawn_background_process == 0)) { - /* We should never reach this point if we're forbidden to spawn - * processes. Instead we should have caught the attempt earlier. */ - return PROCESS_STATUS_ERROR; - } - -#ifdef _WIN32 - HANDLE stdout_pipe_read = NULL; - HANDLE stdout_pipe_write = NULL; - HANDLE stderr_pipe_read = NULL; - HANDLE stderr_pipe_write = NULL; - HANDLE stdin_pipe_read = NULL; - HANDLE stdin_pipe_write = NULL; - process_handle_t *process_handle; - int status; - - STARTUPINFOA siStartInfo; - BOOL retval = FALSE; - - SECURITY_ATTRIBUTES saAttr; - char *joined_argv; - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - /* TODO: should we set explicit security attributes? (#2046, comment 5) */ - saAttr.lpSecurityDescriptor = NULL; - - /* Assume failure to start process */ - status = PROCESS_STATUS_ERROR; - - /* Set up pipe for stdout */ - if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stdout communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stdout communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Set up pipe for stderr */ - if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stderr communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stderr communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Set up pipe for stdin */ - if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) { - log_warn(LD_GENERAL, - "Failed to create pipe for stdin communication with child process: %s", - format_win32_error(GetLastError())); - return status; - } - if (!SetHandleInformation(stdin_pipe_write, HANDLE_FLAG_INHERIT, 0)) { - log_warn(LD_GENERAL, - "Failed to configure pipe for stdin communication with child " - "process: %s", format_win32_error(GetLastError())); - return status; - } - - /* Create the child process */ - - /* Windows expects argv to be a whitespace delimited string, so join argv up - */ - joined_argv = tor_join_win_cmdline(argv); - - process_handle = process_handle_new(); - process_handle->status = status; - - ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION)); - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); - siStartInfo.cb = sizeof(STARTUPINFO); - siStartInfo.hStdError = stderr_pipe_write; - siStartInfo.hStdOutput = stdout_pipe_write; - siStartInfo.hStdInput = stdin_pipe_read; - siStartInfo.dwFlags |= STARTF_USESTDHANDLES; - - /* Create the child process */ - - retval = CreateProcessA(filename, // module name - joined_argv, // command line - /* TODO: should we set explicit security attributes? (#2046, comment 5) */ - NULL, // process security attributes - NULL, // primary thread security attributes - TRUE, // handles are inherited - /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess() - * work?) */ - CREATE_NO_WINDOW, // creation flags - (env==NULL) ? NULL : env->windows_environment_block, - NULL, // use parent's current directory - &siStartInfo, // STARTUPINFO pointer - &(process_handle->pid)); // receives PROCESS_INFORMATION - - tor_free(joined_argv); - - if (!retval) { - log_warn(LD_GENERAL, - "Failed to create child process %s: %s", filename?filename:argv[0], - format_win32_error(GetLastError())); - tor_free(process_handle); - } else { - /* TODO: Close hProcess and hThread in process_handle->pid? */ - process_handle->stdout_pipe = stdout_pipe_read; - process_handle->stderr_pipe = stderr_pipe_read; - process_handle->stdin_pipe = stdin_pipe_write; - status = process_handle->status = PROCESS_STATUS_RUNNING; - } - - /* TODO: Close pipes on exit */ - *process_handle_out = process_handle; - return status; -#else /* !(defined(_WIN32)) */ - pid_t pid; - int stdout_pipe[2]; - int stderr_pipe[2]; - int stdin_pipe[2]; - int fd, retval; - process_handle_t *process_handle; - int status; - - const char *error_message = SPAWN_ERROR_MESSAGE; - size_t error_message_length; - - /* Represents where in the process of spawning the program is; - this is used for printing out the error message */ - unsigned char child_state = CHILD_STATE_INIT; - - char hex_errno[HEX_ERRNO_SIZE + 2]; /* + 1 should be sufficient actually */ - - static int max_fd = -1; - - status = PROCESS_STATUS_ERROR; - - /* We do the strlen here because strlen() is not signal handler safe, - and we are not allowed to use unsafe functions between fork and exec */ - error_message_length = strlen(error_message); - - // child_state = CHILD_STATE_PIPE; - - /* Set up pipe for redirecting stdout, stderr, and stdin of child */ - retval = pipe(stdout_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stdout communication with child process: %s", - strerror(errno)); - return status; - } - - retval = pipe(stderr_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stderr communication with child process: %s", - strerror(errno)); - - close(stdout_pipe[0]); - close(stdout_pipe[1]); - - return status; - } - - retval = pipe(stdin_pipe); - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to set up pipe for stdin communication with child process: %s", - strerror(errno)); - - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - - return status; - } - - // child_state = CHILD_STATE_MAXFD; - -#ifdef _SC_OPEN_MAX - if (-1 == max_fd) { - max_fd = (int) sysconf(_SC_OPEN_MAX); - if (max_fd == -1) { - max_fd = DEFAULT_MAX_FD; - log_warn(LD_GENERAL, - "Cannot find maximum file descriptor, assuming %d", max_fd); - } - } -#else /* !(defined(_SC_OPEN_MAX)) */ - max_fd = DEFAULT_MAX_FD; -#endif /* defined(_SC_OPEN_MAX) */ - - // child_state = CHILD_STATE_FORK; - - pid = fork(); - if (0 == pid) { - /* In child */ - -#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) - /* Attempt to have the kernel issue a SIGTERM if the parent - * goes away. Certain attributes of the binary being execve()ed - * will clear this during the execve() call, but it's better - * than nothing. - */ - prctl(PR_SET_PDEATHSIG, SIGTERM); -#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */ - - child_state = CHILD_STATE_DUPOUT; - - /* Link child stdout to the write end of the pipe */ - retval = dup2(stdout_pipe[1], STDOUT_FILENO); - if (-1 == retval) - goto error; - - child_state = CHILD_STATE_DUPERR; - - /* Link child stderr to the write end of the pipe */ - retval = dup2(stderr_pipe[1], STDERR_FILENO); - if (-1 == retval) - goto error; - - child_state = CHILD_STATE_DUPIN; - - /* Link child stdin to the read end of the pipe */ - retval = dup2(stdin_pipe[0], STDIN_FILENO); - if (-1 == retval) - goto error; - - // child_state = CHILD_STATE_CLOSEFD; - - close(stderr_pipe[0]); - close(stderr_pipe[1]); - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stdin_pipe[0]); - close(stdin_pipe[1]); - - /* Close all other fds, including the read end of the pipe */ - /* XXX: We should now be doing enough FD_CLOEXEC setting to make - * this needless. */ - for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) { - close(fd); - } - - // child_state = CHILD_STATE_EXEC; - - /* Call the requested program. We need the cast because - execvp doesn't define argv as const, even though it - does not modify the arguments */ - if (env) - execve(filename, (char *const *) argv, env->unixoid_environment_block); - else { - static char *new_env[] = { NULL }; - execve(filename, (char *const *) argv, new_env); - } - - /* If we got here, the exec or open(/dev/null) failed */ - - child_state = CHILD_STATE_FAILEXEC; - - error: - { - /* XXX: are we leaking fds from the pipe? */ - int n, err=0; - ssize_t nbytes; - - n = format_helper_exit_status(child_state, errno, hex_errno); - - if (n >= 0) { - /* Write the error message. GCC requires that we check the return - value, but there is nothing we can do if it fails */ - /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */ - nbytes = write(STDOUT_FILENO, error_message, error_message_length); - err = (nbytes < 0); - nbytes = write(STDOUT_FILENO, hex_errno, n); - err += (nbytes < 0); - } - - _exit(err?254:255); // exit ok: in child. - } - - /* Never reached, but avoids compiler warning */ - return status; // LCOV_EXCL_LINE - } - - /* In parent */ - - if (-1 == pid) { - log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno)); - close(stdin_pipe[0]); - close(stdin_pipe[1]); - close(stdout_pipe[0]); - close(stdout_pipe[1]); - close(stderr_pipe[0]); - close(stderr_pipe[1]); - return status; - } - - process_handle = process_handle_new(); - process_handle->status = status; - process_handle->pid = pid; - - /* TODO: If the child process forked but failed to exec, waitpid it */ - - /* Return read end of the pipes to caller, and close write end */ - process_handle->stdout_pipe = stdout_pipe[0]; - retval = close(stdout_pipe[1]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close write end of stdout pipe in parent process: %s", - strerror(errno)); - } - - process_handle->waitpid_cb = set_waitpid_callback(pid, - process_handle_waitpid_cb, - process_handle); - - process_handle->stderr_pipe = stderr_pipe[0]; - retval = close(stderr_pipe[1]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close write end of stderr pipe in parent process: %s", - strerror(errno)); - } - - /* Return write end of the stdin pipe to caller, and close the read end */ - process_handle->stdin_pipe = stdin_pipe[1]; - retval = close(stdin_pipe[0]); - - if (-1 == retval) { - log_warn(LD_GENERAL, - "Failed to close read end of stdin pipe in parent process: %s", - strerror(errno)); - } - - status = process_handle->status = PROCESS_STATUS_RUNNING; - /* Set stdin/stdout/stderr pipes to be non-blocking */ - if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 || - fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 || - fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) { - log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes " - "nonblocking in parent process: %s", strerror(errno)); - } - - *process_handle_out = process_handle; - return status; -#endif /* defined(_WIN32) */ -} - -/** Destroy all resources allocated by the process handle in - * <b>process_handle</b>. - * If <b>also_terminate_process</b> is true, also terminate the - * process of the process handle. */ -MOCK_IMPL(void, -tor_process_handle_destroy,(process_handle_t *process_handle, - int also_terminate_process)) -{ - if (!process_handle) - return; - - if (also_terminate_process) { - if (tor_terminate_process(process_handle) < 0) { - const char *errstr = -#ifdef _WIN32 - format_win32_error(GetLastError()); -#else - strerror(errno); -#endif - log_notice(LD_GENERAL, "Failed to terminate process with " - "PID '%d' ('%s').", tor_process_get_pid(process_handle), - errstr); - } else { - log_info(LD_GENERAL, "Terminated process with PID '%d'.", - tor_process_get_pid(process_handle)); - } - } - - process_handle->status = PROCESS_STATUS_NOTRUNNING; - -#ifdef _WIN32 - if (process_handle->stdout_pipe) - CloseHandle(process_handle->stdout_pipe); - - if (process_handle->stderr_pipe) - CloseHandle(process_handle->stderr_pipe); - - if (process_handle->stdin_pipe) - CloseHandle(process_handle->stdin_pipe); -#else /* !(defined(_WIN32)) */ - close(process_handle->stdout_pipe); - close(process_handle->stderr_pipe); - close(process_handle->stdin_pipe); - - clear_waitpid_callback(process_handle->waitpid_cb); -#endif /* defined(_WIN32) */ - - memset(process_handle, 0x0f, sizeof(process_handle_t)); - tor_free(process_handle); -} - -/** Get the exit code of a process specified by <b>process_handle</b> and store - * it in <b>exit_code</b>, if set to a non-NULL value. If <b>block</b> is set - * to true, the call will block until the process has exited. Otherwise if - * the process is still running, the function will return - * PROCESS_EXIT_RUNNING, and exit_code will be left unchanged. Returns - * PROCESS_EXIT_EXITED if the process did exit. If there is a failure, - * PROCESS_EXIT_ERROR will be returned and the contents of exit_code (if - * non-NULL) will be undefined. N.B. Under *nix operating systems, this will - * probably not work in Tor, because waitpid() is called in main.c to reap any - * terminated child processes.*/ -int -tor_get_exit_code(process_handle_t *process_handle, - int block, int *exit_code) -{ -#ifdef _WIN32 - DWORD retval; - BOOL success; - - if (block) { - /* Wait for the process to exit */ - retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE); - if (retval != WAIT_OBJECT_0) { - log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", - (int)retval, format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } else { - retval = WaitForSingleObject(process_handle->pid.hProcess, 0); - if (WAIT_TIMEOUT == retval) { - /* Process has not exited */ - return PROCESS_EXIT_RUNNING; - } else if (retval != WAIT_OBJECT_0) { - log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", - (int)retval, format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } - - if (exit_code != NULL) { - success = GetExitCodeProcess(process_handle->pid.hProcess, - (PDWORD)exit_code); - if (!success) { - log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s", - format_win32_error(GetLastError())); - return PROCESS_EXIT_ERROR; - } - } -#else /* !(defined(_WIN32)) */ - int stat_loc; - int retval; - - if (process_handle->waitpid_cb) { - /* We haven't processed a SIGCHLD yet. */ - retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG); - if (retval == process_handle->pid) { - clear_waitpid_callback(process_handle->waitpid_cb); - process_handle->waitpid_cb = NULL; - process_handle->waitpid_exit_status = stat_loc; - } - } else { - /* We already got a SIGCHLD for this process, and handled it. */ - retval = process_handle->pid; - stat_loc = process_handle->waitpid_exit_status; - } - - if (!block && 0 == retval) { - /* Process has not exited */ - return PROCESS_EXIT_RUNNING; - } else if (retval != process_handle->pid) { - log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", - (int)process_handle->pid, strerror(errno)); - return PROCESS_EXIT_ERROR; - } - - if (!WIFEXITED(stat_loc)) { - log_warn(LD_GENERAL, "Process %d did not exit normally", - (int)process_handle->pid); - return PROCESS_EXIT_ERROR; - } - - if (exit_code != NULL) - *exit_code = WEXITSTATUS(stat_loc); -#endif /* defined(_WIN32) */ - - return PROCESS_EXIT_EXITED; -} - -/** Helper: return the number of characters in <b>s</b> preceding the first - * occurrence of <b>ch</b>. If <b>ch</b> does not occur in <b>s</b>, return - * the length of <b>s</b>. Should be equivalent to strspn(s, "ch"). */ -static inline size_t -str_num_before(const char *s, char ch) -{ - const char *cp = strchr(s, ch); - if (cp) - return cp - s; - else - return strlen(s); -} - -/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b> - * to have the same name as strings in a process's environment. */ -int -environment_variable_names_equal(const char *s1, const char *s2) -{ - size_t s1_name_len = str_num_before(s1, '='); - size_t s2_name_len = str_num_before(s2, '='); - - return (s1_name_len == s2_name_len && - tor_memeq(s1, s2, s1_name_len)); -} - -/** Free <b>env</b> (assuming it was produced by - * process_environment_make). */ -void -process_environment_free_(process_environment_t *env) -{ - if (env == NULL) return; - - /* As both an optimization hack to reduce consing on Unixoid systems - * and a nice way to ensure that some otherwise-Windows-specific - * code will always get tested before changes to it get merged, the - * strings which env->unixoid_environment_block points to are packed - * into env->windows_environment_block. */ - tor_free(env->unixoid_environment_block); - tor_free(env->windows_environment_block); - - tor_free(env); -} - -/** Make a process_environment_t containing the environment variables - * specified in <b>env_vars</b> (as C strings of the form - * "NAME=VALUE"). */ -process_environment_t * -process_environment_make(struct smartlist_t *env_vars) -{ - process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t)); - int n_env_vars = smartlist_len(env_vars); - int i; - size_t total_env_length; - smartlist_t *env_vars_sorted; - - tor_assert(n_env_vars + 1 != 0); - env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *)); - /* env->unixoid_environment_block is already NULL-terminated, - * because we assume that NULL == 0 (and check that during compilation). */ - - total_env_length = 1; /* terminating NUL of terminating empty string */ - for (i = 0; i < n_env_vars; ++i) { - const char *s = smartlist_get(env_vars, i); - size_t slen = strlen(s); - - tor_assert(slen + 1 != 0); - tor_assert(slen + 1 < SIZE_MAX - total_env_length); - total_env_length += slen + 1; - } - - env->windows_environment_block = tor_malloc_zero(total_env_length); - /* env->windows_environment_block is already - * (NUL-terminated-empty-string)-terminated. */ - - /* Some versions of Windows supposedly require that environment - * blocks be sorted. Or maybe some Windows programs (or their - * runtime libraries) fail to look up strings in non-sorted - * environment blocks. - * - * Also, sorting strings makes it easy to find duplicate environment - * variables and environment-variable strings without an '=' on all - * OSes, and they can cause badness. Let's complain about those. */ - env_vars_sorted = smartlist_new(); - smartlist_add_all(env_vars_sorted, env_vars); - smartlist_sort_strings(env_vars_sorted); - - /* Now copy the strings into the environment blocks. */ - { - char *cp = env->windows_environment_block; - const char *prev_env_var = NULL; - - for (i = 0; i < n_env_vars; ++i) { - const char *s = smartlist_get(env_vars_sorted, i); - size_t slen = strlen(s); - size_t s_name_len = str_num_before(s, '='); - - if (s_name_len == slen) { - log_warn(LD_GENERAL, - "Preparing an environment containing a variable " - "without a value: %s", - s); - } - if (prev_env_var != NULL && - environment_variable_names_equal(s, prev_env_var)) { - log_warn(LD_GENERAL, - "Preparing an environment containing two variables " - "with the same name: %s and %s", - prev_env_var, s); - } - - prev_env_var = s; - - /* Actually copy the string into the environment. */ - memcpy(cp, s, slen+1); - env->unixoid_environment_block[i] = cp; - cp += slen+1; - } - - tor_assert(cp == env->windows_environment_block + total_env_length - 1); - } - - smartlist_free(env_vars_sorted); - - return env; -} - -/** Return a newly allocated smartlist containing every variable in - * this process's environment, as a NUL-terminated string of the form - * "NAME=VALUE". Note that on some/many/most/all OSes, the parent - * process can put strings not of that form in our environment; - * callers should try to not get crashed by that. - * - * The returned strings are heap-allocated, and must be freed by the - * caller. */ -struct smartlist_t * -get_current_process_environment_variables(void) -{ - smartlist_t *sl = smartlist_new(); - - char **environ_tmp; /* Not const char ** ? Really? */ - for (environ_tmp = get_environment(); *environ_tmp; ++environ_tmp) { - smartlist_add_strdup(sl, *environ_tmp); - } - - return sl; -} - -/** For each string s in <b>env_vars</b> such that - * environment_variable_names_equal(s, <b>new_var</b>), remove it; if - * <b>free_p</b> is non-zero, call <b>free_old</b>(s). If - * <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */ -void -set_environment_variable_in_smartlist(struct smartlist_t *env_vars, - const char *new_var, - void (*free_old)(void*), - int free_p) -{ - SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) { - if (environment_variable_names_equal(s, new_var)) { - SMARTLIST_DEL_CURRENT(env_vars, s); - if (free_p) { - free_old((void *)s); - } - } - } SMARTLIST_FOREACH_END(s); - - if (strchr(new_var, '=') != NULL) { - smartlist_add(env_vars, (void *)new_var); - } -} - -#ifdef _WIN32 -/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If - * <b>hProcess</b> is NULL, the function will return immediately if there is - * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle - * to the process owning the <b>h</b>. In this case, the function will exit - * only once the process has exited, or <b>count</b> bytes are read. Returns - * the number of bytes read, or -1 on error. */ -ssize_t -tor_read_all_handle(HANDLE h, char *buf, size_t count, - const process_handle_t *process) -{ - size_t numread = 0; - BOOL retval; - DWORD byte_count; - BOOL process_exited = FALSE; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) - return -1; - - while (numread < count) { - /* Check if there is anything to read */ - retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL); - if (!retval) { - log_warn(LD_GENERAL, - "Failed to peek from handle: %s", - format_win32_error(GetLastError())); - return -1; - } else if (0 == byte_count) { - /* Nothing available: process exited or it is busy */ - - /* Exit if we don't know whether the process is running */ - if (NULL == process) - break; - - /* The process exited and there's nothing left to read from it */ - if (process_exited) - break; - - /* If process is not running, check for output one more time in case - it wrote something after the peek was performed. Otherwise keep on - waiting for output */ - tor_assert(process != NULL); - byte_count = WaitForSingleObject(process->pid.hProcess, 0); - if (WAIT_TIMEOUT != byte_count) - process_exited = TRUE; - - continue; - } - - /* There is data to read; read it */ - retval = ReadFile(h, buf+numread, count-numread, &byte_count, NULL); - tor_assert(byte_count + numread <= count); - if (!retval) { - log_warn(LD_GENERAL, "Failed to read from handle: %s", - format_win32_error(GetLastError())); - return -1; - } else if (0 == byte_count) { - /* End of file */ - break; - } - numread += byte_count; - } - return (ssize_t)numread; -} -#else /* !(defined(_WIN32)) */ -/** Read from a handle <b>fd</b> into <b>buf</b>, up to <b>count</b> bytes. If - * <b>process</b> is NULL, the function will return immediately if there is - * nothing more to read. Otherwise data will be read until end of file, or - * <b>count</b> bytes are read. Returns the number of bytes read, or -1 on - * error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the - * file has been reached. */ -ssize_t -tor_read_all_handle(int fd, char *buf, size_t count, - const process_handle_t *process, - int *eof) -{ - size_t numread = 0; - ssize_t result; - - if (eof) - *eof = 0; - - if (count > SIZE_T_CEILING || count > SSIZE_MAX) - return -1; - - while (numread < count) { - result = read(fd, buf+numread, count-numread); - - if (result == 0) { - log_debug(LD_GENERAL, "read() reached end of file"); - if (eof) - *eof = 1; - break; - } else if (result < 0 && errno == EAGAIN) { - if (process) - continue; - else - break; - } else if (result < 0) { - log_warn(LD_GENERAL, "read() failed: %s", strerror(errno)); - return -1; - } - - numread += result; - } - - log_debug(LD_GENERAL, "read() read %d bytes from handle", (int)numread); - return (ssize_t)numread; -} -#endif /* defined(_WIN32) */ - -/** Read from stdout of a process until the process exits. */ -ssize_t -tor_read_all_from_process_stdout(const process_handle_t *process_handle, - char *buf, size_t count) -{ -#ifdef _WIN32 - return tor_read_all_handle(process_handle->stdout_pipe, buf, count, - process_handle); -#else - return tor_read_all_handle(process_handle->stdout_pipe, buf, count, - process_handle, NULL); -#endif /* defined(_WIN32) */ -} - -/** Read from stdout of a process until the process exits. */ -ssize_t -tor_read_all_from_process_stderr(const process_handle_t *process_handle, - char *buf, size_t count) -{ -#ifdef _WIN32 - return tor_read_all_handle(process_handle->stderr_pipe, buf, count, - process_handle); -#else - return tor_read_all_handle(process_handle->stderr_pipe, buf, count, - process_handle, NULL); -#endif /* defined(_WIN32) */ -} - -/** Split buf into lines, and add to smartlist. The buffer <b>buf</b> will be - * modified. The resulting smartlist will consist of pointers to buf, so there - * is no need to free the contents of sl. <b>buf</b> must be a NUL-terminated - * string. <b>len</b> should be set to the length of the buffer excluding the - * NUL. Non-printable characters (including NUL) will be replaced with "." */ -int -tor_split_lines(smartlist_t *sl, char *buf, int len) -{ - /* Index in buf of the start of the current line */ - int start = 0; - /* Index in buf of the current character being processed */ - int cur = 0; - /* Are we currently in a line */ - char in_line = 0; - - /* Loop over string */ - while (cur < len) { - /* Loop until end of line or end of string */ - for (; cur < len; cur++) { - if (in_line) { - if ('\r' == buf[cur] || '\n' == buf[cur]) { - /* End of line */ - buf[cur] = '\0'; - /* Point cur to the next line */ - cur++; - /* Line starts at start and ends with a nul */ - break; - } else { - if (!TOR_ISPRINT(buf[cur])) - buf[cur] = '.'; - } - } else { - if ('\r' == buf[cur] || '\n' == buf[cur]) { - /* Skip leading vertical space */ - ; - } else { - in_line = 1; - start = cur; - if (!TOR_ISPRINT(buf[cur])) - buf[cur] = '.'; - } - } - } - /* We are at the end of the line or end of string. If in_line is true there - * is a line which starts at buf+start and ends at a NUL. cur points to - * the character after the NUL. */ - if (in_line) - smartlist_add(sl, (void *)(buf+start)); - in_line = 0; - } - return smartlist_len(sl); -} - -/** Return a string corresponding to <b>stream_status</b>. */ -const char * -stream_status_to_string(enum stream_status stream_status) -{ - switch (stream_status) { - case IO_STREAM_OKAY: - return "okay"; - case IO_STREAM_EAGAIN: - return "temporarily unavailable"; - case IO_STREAM_TERM: - return "terminated"; - case IO_STREAM_CLOSED: - return "closed"; - default: - tor_fragile_assert(); - return "unknown"; - } -} - -#ifdef _WIN32 - -/** Return a smartlist containing lines outputted from - * <b>handle</b>. Return NULL on error, and set - * <b>stream_status_out</b> appropriately. */ -MOCK_IMPL(smartlist_t *, -tor_get_lines_from_handle, (HANDLE *handle, - enum stream_status *stream_status_out)) -{ - int pos; - char stdout_buf[600] = {0}; - smartlist_t *lines = NULL; - - tor_assert(stream_status_out); - - *stream_status_out = IO_STREAM_TERM; - - pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL); - if (pos < 0) { - *stream_status_out = IO_STREAM_TERM; - return NULL; - } - if (pos == 0) { - *stream_status_out = IO_STREAM_EAGAIN; - return NULL; - } - - /* End with a null even if there isn't a \r\n at the end */ - /* TODO: What if this is a partial line? */ - stdout_buf[pos] = '\0'; - - /* Split up the buffer */ - lines = smartlist_new(); - tor_split_lines(lines, stdout_buf, pos); - - /* Currently 'lines' is populated with strings residing on the - stack. Replace them with their exact copies on the heap: */ - SMARTLIST_FOREACH(lines, char *, line, - SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line))); - - *stream_status_out = IO_STREAM_OKAY; - - return lines; -} - -#else /* !(defined(_WIN32)) */ - -/** Return a smartlist containing lines outputted from - * <b>fd</b>. Return NULL on error, and set - * <b>stream_status_out</b> appropriately. */ -MOCK_IMPL(smartlist_t *, -tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out)) -{ - enum stream_status stream_status; - char stdout_buf[400]; - smartlist_t *lines = NULL; - - while (1) { - memset(stdout_buf, 0, sizeof(stdout_buf)); - - stream_status = get_string_from_pipe(fd, - stdout_buf, sizeof(stdout_buf) - 1); - if (stream_status != IO_STREAM_OKAY) - goto done; - - if (!lines) lines = smartlist_new(); - smartlist_split_string(lines, stdout_buf, "\n", 0, 0); - } - - done: - *stream_status_out = stream_status; - return lines; -} - -#endif /* defined(_WIN32) */ - -/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making - * sure it's below <b>count</b> bytes. - * If the string has a trailing newline, we strip it off. - * - * This function is specifically created to handle input from managed - * proxies, according to the pluggable transports spec. Make sure it - * fits your needs before using it. - * - * Returns: - * IO_STREAM_CLOSED: If the stream is closed. - * IO_STREAM_EAGAIN: If there is nothing to read and we should check back - * later. - * IO_STREAM_TERM: If something is wrong with the stream. - * IO_STREAM_OKAY: If everything went okay and we got a string - * in <b>buf_out</b>. */ -enum stream_status -get_string_from_pipe(int fd, char *buf_out, size_t count) -{ - ssize_t ret; - - tor_assert(count <= INT_MAX); - - ret = read(fd, buf_out, count); - - if (ret == 0) - return IO_STREAM_CLOSED; - else if (ret < 0 && errno == EAGAIN) - return IO_STREAM_EAGAIN; - else if (ret < 0) - return IO_STREAM_TERM; - - if (buf_out[ret - 1] == '\n') { - /* Remove the trailing newline */ - buf_out[ret - 1] = '\0'; - } else - buf_out[ret] = '\0'; - - return IO_STREAM_OKAY; -} - -/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */ -void -tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed) -{ - rng->state = (uint32_t)(seed & 0x7fffffff); -} - -/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based - * on the RNG state of <b>rng</b>. This entropy will not be cryptographically - * strong; do not rely on it for anything an adversary should not be able to - * predict. */ -int32_t -tor_weak_random(tor_weak_rng_t *rng) -{ - /* Here's a linear congruential generator. OpenBSD and glibc use these - * parameters; they aren't too bad, and should have maximal period over the - * range 0..INT32_MAX. We don't want to use the platform rand() or random(), - * since some platforms have bad weak RNGs that only return values in the - * range 0..INT16_MAX, which just isn't enough. */ - rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff; - return (int32_t) rng->state; -} - -/** Return a random number in the range [0 , <b>top</b>). {That is, the range - * of integers i such that 0 <= i < top.} Chooses uniformly. Requires that - * top is greater than 0. This randomness is not cryptographically strong; do - * not rely on it for anything an adversary should not be able to predict. */ -int32_t -tor_weak_random_range(tor_weak_rng_t *rng, int32_t top) -{ - /* We don't want to just do tor_weak_random() % top, since random() is often - * implemented with an LCG whose modulus is a power of 2, and those are - * cyclic in their low-order bits. */ - int divisor, result; - tor_assert(top > 0); - divisor = TOR_WEAK_RANDOM_MAX / top; - do { - result = (int32_t)(tor_weak_random(rng) / divisor); - } while (result >= top); - return result; -} - -/** Cast a given double value to a int64_t. Return 0 if number is NaN. - * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t - * range. */ -int64_t -clamp_double_to_int64(double number) -{ - int exponent; - -#if defined(MINGW_ANY) && GCC_VERSION >= 409 -/* - Mingw's math.h uses gcc's __builtin_choose_expr() facility to declare - isnan, isfinite, and signbit. But as implemented in at least some - versions of gcc, __builtin_choose_expr() can generate type warnings - even from branches that are not taken. So, suppress those warnings. -*/ -#define PROBLEMATIC_FLOAT_CONVERSION_WARNING -DISABLE_GCC_WARNING(float-conversion) -#endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */ - -/* - With clang 4.0 we apparently run into "double promotion" warnings here, - since clang thinks we're promoting a double to a long double. - */ -#if defined(__clang__) -#if __has_warning("-Wdouble-promotion") -#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING -DISABLE_GCC_WARNING(double-promotion) -#endif -#endif /* defined(__clang__) */ - - /* NaN is a special case that can't be used with the logic below. */ - if (isnan(number)) { - return 0; - } - - /* Time to validate if result can overflows a int64_t value. Fun with - * float! Find that exponent exp such that - * number == x * 2^exp - * for some x with abs(x) in [0.5, 1.0). Note that this implies that the - * magnitude of number is strictly less than 2^exp. - * - * If number is infinite, the call to frexp is legal but the contents of - * are exponent unspecified. */ - frexp(number, &exponent); - - /* If the magnitude of number is strictly less than 2^63, the truncated - * version of number is guaranteed to be representable. The only - * representable integer for which this is not the case is INT64_MIN, but - * it is covered by the logic below. */ - if (isfinite(number) && exponent <= 63) { - return (int64_t)number; - } - - /* Handle infinities and finite numbers with magnitude >= 2^63. */ - return signbit(number) ? INT64_MIN : INT64_MAX; - -#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING -ENABLE_GCC_WARNING(double-promotion) -#endif -#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING -ENABLE_GCC_WARNING(float-conversion) -#endif -} - -/** Return a uint64_t value from <b>a</b> in network byte order. */ -uint64_t -tor_htonll(uint64_t a) -{ -#ifdef WORDS_BIGENDIAN - /* Big endian. */ - return a; -#else /* WORDS_BIGENDIAN */ - /* Little endian. The worst... */ - return htonl((uint32_t)(a>>32)) | - (((uint64_t)htonl((uint32_t)a))<<32); -#endif /* defined(WORDS_BIGENDIAN) */ -} - -/** Return a uint64_t value from <b>a</b> in host byte order. */ -uint64_t -tor_ntohll(uint64_t a) -{ - return tor_htonll(a); -} - diff --git a/src/common/util.h b/src/common/util.h deleted file mode 100644 index 7172b7da08..0000000000 --- a/src/common/util.h +++ /dev/null @@ -1,572 +0,0 @@ -/* Copyright (c) 2003-2004, Roger Dingledine - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file util.h - * \brief Headers for util.c - **/ - -#ifndef TOR_UTIL_H -#define TOR_UTIL_H - -#include "orconfig.h" -#include "torint.h" -#include "compat.h" -#include "di_ops.h" -#include "testsupport.h" -#include <stdio.h> -#include <stdlib.h> -#ifdef _WIN32 -/* for the correct alias to struct stat */ -#include <sys/stat.h> -#endif -#include "util_bug.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#ifndef O_TEXT -#define O_TEXT 0 -#endif -#ifndef O_NOFOLLOW -#define O_NOFOLLOW 0 -#endif - -/* If we're building with dmalloc, we want all of our memory allocation - * functions to take an extra file/line pair of arguments. If not, not. - * We define DMALLOC_PARAMS to the extra parameters to insert in the - * function prototypes, and DMALLOC_ARGS to the extra arguments to add - * to calls. */ -#ifdef USE_DMALLOC -#define DMALLOC_PARAMS , const char *file, const int line -#define DMALLOC_ARGS , SHORT_FILE__, __LINE__ -#else -#define DMALLOC_PARAMS -#define DMALLOC_ARGS -#endif /* defined(USE_DMALLOC) */ - -/* Memory management */ -void *tor_malloc_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_malloc_zero_(size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC; -void *tor_realloc_(void *ptr, size_t size DMALLOC_PARAMS); -void *tor_reallocarray_(void *ptr, size_t size1, size_t size2 DMALLOC_PARAMS); -char *tor_strdup_(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1)); -char *tor_strndup_(const char *s, size_t n DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void *tor_memdup_(const void *mem, size_t len DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void *tor_memdup_nulterm_(const void *mem, size_t len DMALLOC_PARAMS) - ATTR_MALLOC ATTR_NONNULL((1)); -void tor_free_(void *mem); -uint64_t tor_htonll(uint64_t a); -uint64_t tor_ntohll(uint64_t a); -#ifdef USE_DMALLOC -extern int dmalloc_free(const char *file, const int line, void *pnt, - const int func_id); -#define tor_free(p) STMT_BEGIN \ - if (PREDICT_LIKELY((p)!=NULL)) { \ - dmalloc_free(SHORT_FILE__, __LINE__, (p), 0); \ - (p)=NULL; \ - } \ - STMT_END -#else /* !(defined(USE_DMALLOC)) */ -/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup, - * etc. Unlike the free() function, the tor_free() macro sets the - * pointer value to NULL after freeing it. - * - * This is a macro. If you need a function pointer to release memory from - * tor_malloc(), use tor_free_(). - * - * Note that this macro takes the address of the pointer it is going to - * free and clear. If that pointer is stored with a nonstandard - * alignment (eg because of a "packed" pragma) it is not correct to use - * tor_free(). - */ -#ifdef __GNUC__ -#define tor_free(p) STMT_BEGIN \ - typeof(&(p)) tor_free__tmpvar = &(p); \ - raw_free(*tor_free__tmpvar); \ - *tor_free__tmpvar=NULL; \ - STMT_END -#else -#define tor_free(p) STMT_BEGIN \ - raw_free(p); \ - (p)=NULL; \ - STMT_END -#endif -#endif /* defined(USE_DMALLOC) */ - -#define tor_malloc(size) tor_malloc_(size DMALLOC_ARGS) -#define tor_malloc_zero(size) tor_malloc_zero_(size DMALLOC_ARGS) -#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size DMALLOC_ARGS) -#define tor_realloc(ptr, size) tor_realloc_(ptr, size DMALLOC_ARGS) -#define tor_reallocarray(ptr, sz1, sz2) \ - tor_reallocarray_((ptr), (sz1), (sz2) DMALLOC_ARGS) -#define tor_strdup(s) tor_strdup_(s DMALLOC_ARGS) -#define tor_strndup(s, n) tor_strndup_(s, n DMALLOC_ARGS) -#define tor_memdup(s, n) tor_memdup_(s, n DMALLOC_ARGS) -#define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n DMALLOC_ARGS) - -/* Aliases for the underlying system malloc/realloc/free. Only use - * them to indicate "I really want the underlying system function, I know - * what I'm doing." */ -#define raw_malloc malloc -#define raw_realloc realloc -#define raw_free free -#define raw_strdup strdup - -void tor_log_mallinfo(int severity); - -/* Helper macro: free a variable of type 'typename' using freefn, and - * set the variable to NULL. - */ -#define FREE_AND_NULL(typename, freefn, var) \ - do { \ - /* only evaluate (var) once. */ \ - typename **tmp__free__ptr ## freefn = &(var); \ - freefn(*tmp__free__ptr ## freefn); \ - (*tmp__free__ptr ## freefn) = NULL; \ - } while (0) - -/** Macro: yield a pointer to the field at position <b>off</b> within the - * structure <b>st</b>. Example: - * <pre> - * struct a { int foo; int bar; } x; - * off_t bar_offset = offsetof(struct a, bar); - * int *bar_p = STRUCT_VAR_P(&x, bar_offset); - * *bar_p = 3; - * </pre> - */ -#define STRUCT_VAR_P(st, off) ((void*) ( ((char*)(st)) + (off) ) ) - -/** Macro: yield a pointer to an enclosing structure given a pointer to - * a substructure at offset <b>off</b>. Example: - * <pre> - * struct base { ... }; - * struct subtype { int x; struct base b; } x; - * struct base *bp = &x.base; - * struct *sp = SUBTYPE_P(bp, struct subtype, b); - * </pre> - */ -#define SUBTYPE_P(p, subtype, basemember) \ - ((void*) ( ((char*)(p)) - offsetof(subtype, basemember) )) - -/* Logic */ -/** Macro: true if two values have the same boolean value. */ -#define bool_eq(a,b) (!(a)==!(b)) -/** Macro: true if two values have different boolean values. */ -#define bool_neq(a,b) (!(a)!=!(b)) - -/* Math functions */ -double tor_mathlog(double d) ATTR_CONST; -long tor_lround(double d) ATTR_CONST; -int64_t tor_llround(double d) ATTR_CONST; -int tor_log2(uint64_t u64) ATTR_CONST; -uint64_t round_to_power_of_2(uint64_t u64); -unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); -uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); -uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); -int64_t sample_laplace_distribution(double mu, double b, double p); -int64_t add_laplace_noise(int64_t signal, double random, double delta_f, - double epsilon); -int n_bits_set_u8(uint8_t v); -int64_t clamp_double_to_int64(double number); -void simplify_fraction64(uint64_t *numer, uint64_t *denom); - -uint32_t tor_add_u32_nowrap(uint32_t a, uint32_t b); - -/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> - * and positive <b>b</b>. Works on integer types only. Not defined if a+(b-1) - * can overflow. */ -#define CEIL_DIV(a,b) (((a)+((b)-1))/(b)) - -/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise - * return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if - * <b>b</b> is larger than <b>max</b>. - * - * Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of - * its arguments more than once! */ -#define CLAMP(min,v,max) \ - ( ((v) < (min)) ? (min) : \ - ((v) > (max)) ? (max) : \ - (v) ) - -/* String manipulation */ - -/** Allowable characters in a hexadecimal string. */ -#define HEX_CHARACTERS "0123456789ABCDEFabcdef" -void tor_strlower(char *s) ATTR_NONNULL((1)); -void tor_strupper(char *s) ATTR_NONNULL((1)); -int tor_strisprint(const char *s) ATTR_NONNULL((1)); -int tor_strisnonupper(const char *s) ATTR_NONNULL((1)); -int tor_strisspace(const char *s); -int strcmp_opt(const char *s1, const char *s2); -int strcmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcmp_len(const char *s1, const char *s2, size_t len) ATTR_NONNULL((1,2)); -int strcasecmpstart(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int strcasecmpend(const char *s1, const char *s2) ATTR_NONNULL((1,2)); -int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix); - -void tor_strstrip(char *s, const char *strip) ATTR_NONNULL((1,2)); -long tor_parse_long(const char *s, int base, long min, - long max, int *ok, char **next); -unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, - unsigned long max, int *ok, char **next); -double tor_parse_double(const char *s, double min, double max, int *ok, - char **next); -uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, - uint64_t max, int *ok, char **next); -const char *hex_str(const char *from, size_t fromlen) ATTR_NONNULL((1)); -const char *eat_whitespace(const char *s); -const char *eat_whitespace_eos(const char *s, const char *eos); -const char *eat_whitespace_no_nl(const char *s); -const char *eat_whitespace_eos_no_nl(const char *s, const char *eos); -const char *find_whitespace(const char *s); -const char *find_whitespace_eos(const char *s, const char *eos); -const char *find_str_at_start_of_line(const char *haystack, - const char *needle); -int string_is_C_identifier(const char *string); -int string_is_key_value(int severity, const char *string); -int string_is_valid_dest(const char *string); -int string_is_valid_nonrfc_hostname(const char *string); -int string_is_valid_ipv4_address(const char *string); -int string_is_valid_ipv6_address(const char *string); - -int tor_mem_is_zero(const char *mem, size_t len); -int tor_digest_is_zero(const char *digest); -int tor_digest256_is_zero(const char *digest); -char *esc_for_log(const char *string) ATTR_MALLOC; -char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC; -const char *escaped(const char *string); - -char *tor_escape_str_for_pt_args(const char *string, - const char *chars_to_escape); - -struct smartlist_t; -int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \ - CHECK_SCANF(2, 0); -int tor_sscanf(const char *buf, const char *pattern, ...) - CHECK_SCANF(2, 3); - -void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) - CHECK_PRINTF(2, 3); -void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, - va_list args) - CHECK_PRINTF(2, 0); -void smartlist_add_strdup(struct smartlist_t *sl, const char *string); - -/* Time helpers */ -long tv_udiff(const struct timeval *start, const struct timeval *end); -long tv_mdiff(const struct timeval *start, const struct timeval *end); -int64_t tv_to_msec(const struct timeval *tv); -int tor_timegm(const struct tm *tm, time_t *time_out); -#define RFC1123_TIME_LEN 29 -void format_rfc1123_time(char *buf, time_t t); -int parse_rfc1123_time(const char *buf, time_t *t); -#define ISO_TIME_LEN 19 -#define ISO_TIME_USEC_LEN (ISO_TIME_LEN+7) -void format_local_iso_time(char *buf, time_t t); -void format_iso_time(char *buf, time_t t); -void format_local_iso_time_nospace(char *buf, time_t t); -void format_iso_time_nospace(char *buf, time_t t); -void format_iso_time_nospace_usec(char *buf, const struct timeval *tv); -int parse_iso_time_(const char *cp, time_t *t, int strict, int nospace); -int parse_iso_time(const char *buf, time_t *t); -int parse_iso_time_nospace(const char *cp, time_t *t); -int parse_http_time(const char *buf, struct tm *tm); -int format_time_interval(char *out, size_t out_len, long interval); - -/* Cached time */ -#ifdef TIME_IS_FAST -#define approx_time() time(NULL) -#define update_approx_time(t) STMT_NIL -#else -time_t approx_time(void); -void update_approx_time(time_t now); -#endif /* defined(TIME_IS_FAST) */ - -/* Rate-limiter */ - -/** A ratelim_t remembers how often an event is occurring, and how often - * it's allowed to occur. Typical usage is something like: - * - <pre> - if (possibly_very_frequent_event()) { - const int INTERVAL = 300; - static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); - char *m; - if ((m = rate_limit_log(&warning_limit, approx_time()))) { - log_warn(LD_GENERAL, "The event occurred!%s", m); - tor_free(m); - } - } - </pre> - - As a convenience wrapper for logging, you can replace the above with: - <pre> - if (possibly_very_frequent_event()) { - static ratelim_t warning_limit = RATELIM_INIT(300); - log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL, - "The event occurred!"); - } - </pre> - */ -typedef struct ratelim_t { - int rate; - time_t last_allowed; - int n_calls_since_last_time; -} ratelim_t; - -#define RATELIM_INIT(r) { (r), 0, 0 } -#define RATELIM_TOOMANY (16*1000*1000) - -char *rate_limit_log(ratelim_t *lim, time_t now); - -/* File helpers */ -ssize_t write_all(tor_socket_t fd, const char *buf, size_t count,int isSocket); -ssize_t read_all(tor_socket_t fd, char *buf, size_t count, int isSocket); - -/** Status of an I/O stream. */ -enum stream_status { - IO_STREAM_OKAY, - IO_STREAM_EAGAIN, - IO_STREAM_TERM, - IO_STREAM_CLOSED -}; - -const char *stream_status_to_string(enum stream_status stream_status); - -enum stream_status get_string_from_pipe(int fd, char *buf, size_t count); - -MOCK_DECL(int,tor_unlink,(const char *pathname)); - -/** Return values from file_status(); see that function's documentation - * for details. */ -typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t; -file_status_t file_status(const char *filename); - -/** Possible behaviors for check_private_dir() on encountering a nonexistent - * directory; see that function's documentation for details. */ -typedef unsigned int cpd_check_t; -#define CPD_NONE 0 -#define CPD_CREATE (1u << 0) -#define CPD_CHECK (1u << 1) -#define CPD_GROUP_OK (1u << 2) -#define CPD_GROUP_READ (1u << 3) -#define CPD_CHECK_MODE_ONLY (1u << 4) -#define CPD_RELAX_DIRMODE_CHECK (1u << 5) -MOCK_DECL(int, check_private_dir, - (const char *dirname, cpd_check_t check, - const char *effective_user)); - -#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC) -#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND) -#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY) -typedef struct open_file_t open_file_t; -int start_writing_to_file(const char *fname, int open_flags, int mode, - open_file_t **data_out); -FILE *start_writing_to_stdio_file(const char *fname, int open_flags, int mode, - open_file_t **data_out); -FILE *fdopen_file(open_file_t *file_data); -int finish_writing_to_file(open_file_t *file_data); -int abort_writing_to_file(open_file_t *file_data); -MOCK_DECL(int, -write_str_to_file,(const char *fname, const char *str, int bin)); -MOCK_DECL(int, -write_bytes_to_file,(const char *fname, const char *str, size_t len, - int bin)); -/** An ad-hoc type to hold a string of characters and a count; used by - * write_chunks_to_file. */ -typedef struct sized_chunk_t { - const char *bytes; - size_t len; -} sized_chunk_t; -int write_chunks_to_file(const char *fname, const struct smartlist_t *chunks, - int bin, int no_tempfile); -int append_bytes_to_file(const char *fname, const char *str, size_t len, - int bin); -int write_bytes_to_new_file(const char *fname, const char *str, size_t len, - int bin); - -/** Flag for read_file_to_str: open the file in binary mode. */ -#define RFTS_BIN 1 -/** Flag for read_file_to_str: it's okay if the file doesn't exist. */ -#define RFTS_IGNORE_MISSING 2 - -#ifndef _WIN32 -struct stat; -#endif -MOCK_DECL_ATTR(char *, read_file_to_str, - (const char *filename, int flags, struct stat *stat_out), - ATTR_MALLOC); -char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, - size_t *sz_out) - ATTR_MALLOC; -const char *unescape_string(const char *s, char **result, size_t *size_out); -char *get_unquoted_path(const char *path); -char *expand_filename(const char *filename); -MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname)); -int path_is_relative(const char *filename); - -/* Process helpers */ -void start_daemon(void); -void finish_daemon(const char *desired_cwd); -int write_pidfile(const char *filename); - -void tor_disable_spawning_background_processes(void); - -typedef struct process_handle_t process_handle_t; -typedef struct process_environment_t process_environment_t; -int tor_spawn_background(const char *const filename, const char **argv, - process_environment_t *env, - process_handle_t **process_handle_out); - -#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " - -#ifdef _WIN32 -HANDLE load_windows_system_library(const TCHAR *library_name); -#endif - -int environment_variable_names_equal(const char *s1, const char *s2); - -/* DOCDOC process_environment_t */ -struct process_environment_t { - /** A pointer to a sorted empty-string-terminated sequence of - * NUL-terminated strings of the form "NAME=VALUE". */ - char *windows_environment_block; - /** A pointer to a NULL-terminated array of pointers to - * NUL-terminated strings of the form "NAME=VALUE". */ - char **unixoid_environment_block; -}; - -process_environment_t *process_environment_make(struct smartlist_t *env_vars); -void process_environment_free_(process_environment_t *env); -#define process_environment_free(env) \ - FREE_AND_NULL(process_environment_t, process_environment_free_, (env)) - -struct smartlist_t *get_current_process_environment_variables(void); - -void set_environment_variable_in_smartlist(struct smartlist_t *env_vars, - const char *new_var, - void (*free_old)(void*), - int free_p); - -/* Values of process_handle_t.status. */ -#define PROCESS_STATUS_NOTRUNNING 0 -#define PROCESS_STATUS_RUNNING 1 -#define PROCESS_STATUS_ERROR -1 - -#ifdef UTIL_PRIVATE -struct waitpid_callback_t; -/** Structure to represent the state of a process with which Tor is - * communicating. The contents of this structure are private to util.c */ -struct process_handle_t { - /** One of the PROCESS_STATUS_* values */ - int status; -#ifdef _WIN32 - HANDLE stdin_pipe; - HANDLE stdout_pipe; - HANDLE stderr_pipe; - PROCESS_INFORMATION pid; -#else /* !(defined(_WIN32)) */ - int stdin_pipe; - int stdout_pipe; - int stderr_pipe; - pid_t pid; - /** If the process has not given us a SIGCHLD yet, this has the - * waitpid_callback_t that gets invoked once it has. Otherwise this - * contains NULL. */ - struct waitpid_callback_t *waitpid_cb; - /** The exit status reported by waitpid. */ - int waitpid_exit_status; -#endif /* defined(_WIN32) */ -}; -#endif /* defined(UTIL_PRIVATE) */ - -/* Return values of tor_get_exit_code() */ -#define PROCESS_EXIT_RUNNING 1 -#define PROCESS_EXIT_EXITED 0 -#define PROCESS_EXIT_ERROR -1 -int tor_get_exit_code(process_handle_t *process_handle, - int block, int *exit_code); -int tor_split_lines(struct smartlist_t *sl, char *buf, int len); -#ifdef _WIN32 -ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count, - const process_handle_t *process); -#else -ssize_t tor_read_all_handle(int fd, char *buf, size_t count, - const process_handle_t *process, - int *eof); -#endif /* defined(_WIN32) */ -ssize_t tor_read_all_from_process_stdout( - const process_handle_t *process_handle, char *buf, size_t count); -ssize_t tor_read_all_from_process_stderr( - const process_handle_t *process_handle, char *buf, size_t count); -char *tor_join_win_cmdline(const char *argv[]); - -int tor_process_get_pid(process_handle_t *process_handle); -#ifdef _WIN32 -HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle); -#else -int tor_process_get_stdout_pipe(process_handle_t *process_handle); -#endif - -#ifdef _WIN32 -MOCK_DECL(struct smartlist_t *, -tor_get_lines_from_handle,(HANDLE *handle, - enum stream_status *stream_status)); -#else -MOCK_DECL(struct smartlist_t *, -tor_get_lines_from_handle,(int fd, - enum stream_status *stream_status)); -#endif /* defined(_WIN32) */ - -int -tor_terminate_process(process_handle_t *process_handle); - -MOCK_DECL(void, -tor_process_handle_destroy,(process_handle_t *process_handle, - int also_terminate_process)); - -/* ===== Insecure rng */ -typedef struct tor_weak_rng_t { - uint32_t state; -} tor_weak_rng_t; - -#define TOR_WEAK_RNG_INIT {383745623} -#define TOR_WEAK_RANDOM_MAX (INT_MAX) -void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed); -int32_t tor_weak_random(tor_weak_rng_t *weak_rng); -int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top); -/** Randomly return true according to <b>rng</b> with probability 1 in - * <b>n</b> */ -#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n))) - -int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); -int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len); - -#ifdef UTIL_PRIVATE -/* Prototypes for private functions only used by util.c (and unit tests) */ - -#ifndef _WIN32 -STATIC int format_helper_exit_status(unsigned char child_state, - int saved_errno, char *hex_errno); - -/* Space for hex values of child state, a slash, saved_errno (with - leading minus) and newline (no null) */ -#define HEX_ERRNO_SIZE (sizeof(char) * 2 + 1 + \ - 1 + sizeof(int) * 2 + 1) -#endif /* !defined(_WIN32) */ - -#endif /* defined(UTIL_PRIVATE) */ - -int size_mul_check(const size_t x, const size_t y); - -#define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0])) - -#endif /* !defined(TOR_UTIL_H) */ - diff --git a/src/or/hs_ntor.c b/src/core/crypto/hs_ntor.c index 809fa83bb8..d98d16f7f6 100644 --- a/src/or/hs_ntor.c +++ b/src/core/crypto/hs_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** \file hs_ntor.c @@ -24,9 +24,11 @@ * rendezvous key expansion to setup end-to-end rend circuit keys. */ -#include "or.h" -#include "crypto_util.h" -#include "hs_ntor.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "core/crypto/hs_ntor.h" /* String constants used by the ntor HS protocol */ #define PROTOID "tor-hs-ntor-curve25519-sha3-256-1" @@ -616,4 +618,3 @@ hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, size_t seed_len, return 0; } - diff --git a/src/core/crypto/hs_ntor.h b/src/core/crypto/hs_ntor.h new file mode 100644 index 0000000000..30738c4ae0 --- /dev/null +++ b/src/core/crypto/hs_ntor.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_HS_NTOR_H +#define TOR_HS_NTOR_H + +#include "core/or/or.h" +struct ed25519_public_key_t; +struct curve25519_public_key_t; +struct curve25519_keypair_t; + +/* Output length of KDF for key expansion */ +#define HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN \ + (DIGEST256_LEN*2 + CIPHER256_KEY_LEN*2) + +/* Key material needed to encode/decode INTRODUCE1 cells */ +typedef struct { + /* Key used for encryption of encrypted INTRODUCE1 blob */ + uint8_t enc_key[CIPHER256_KEY_LEN]; + /* MAC key used to protect encrypted INTRODUCE1 blob */ + uint8_t mac_key[DIGEST256_LEN]; +} hs_ntor_intro_cell_keys_t; + +/* Key material needed to encode/decode RENDEZVOUS1 cells */ +typedef struct { + /* This is the MAC of the HANDSHAKE_INFO field */ + uint8_t rend_cell_auth_mac[DIGEST256_LEN]; + /* This is the key seed used to derive further rendezvous crypto keys as + * detailed in section 4.2.1 of rend-spec-ng.txt. */ + uint8_t ntor_key_seed[DIGEST256_LEN]; +} hs_ntor_rend_cell_keys_t; + +int hs_ntor_client_get_introduce1_keys( + const struct ed25519_public_key_t *intro_auth_pubkey, + const struct curve25519_public_key_t *intro_enc_pubkey, + const struct curve25519_keypair_t *client_ephemeral_enc_keypair, + const uint8_t *subcredential, + hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out); + +int hs_ntor_client_get_rendezvous1_keys( + const struct ed25519_public_key_t *intro_auth_pubkey, + const struct curve25519_keypair_t *client_ephemeral_enc_keypair, + const struct curve25519_public_key_t *intro_enc_pubkey, + const struct curve25519_public_key_t *service_ephemeral_rend_pubkey, + hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out); + +int hs_ntor_service_get_introduce1_keys( + const struct ed25519_public_key_t *intro_auth_pubkey, + const struct curve25519_keypair_t *intro_enc_keypair, + const struct curve25519_public_key_t *client_ephemeral_enc_pubkey, + const uint8_t *subcredential, + hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out); + +int hs_ntor_service_get_rendezvous1_keys( + const struct ed25519_public_key_t *intro_auth_pubkey, + const struct curve25519_keypair_t *intro_enc_keypair, + const struct curve25519_keypair_t *service_ephemeral_rend_keypair, + const struct curve25519_public_key_t *client_ephemeral_enc_pubkey, + hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out); + +int hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, + size_t seed_len, + uint8_t *keys_out, size_t keys_out_len); + +int hs_ntor_client_rendezvous2_mac_is_good( + const hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys, + const uint8_t *rcvd_mac); + +#endif /* !defined(TOR_HS_NTOR_H) */ diff --git a/src/or/onion.c b/src/core/crypto/onion.c index 829be12bae..e71bfc1fd9 100644 --- a/src/or/onion.c +++ b/src/core/crypto/onion.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -62,23 +62,28 @@ * onion_fast.c for more information. **/ -#include "or.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "config.h" -#include "cpuworker.h" -#include "crypto_util.h" -#include "networkstatus.h" -#include "onion.h" -#include "onion_fast.h" -#include "onion_ntor.h" -#include "onion_tap.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" +#include "core/or/or.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "app/config/config.h" +#include "core/mainloop/cpuworker.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "feature/nodelist/networkstatus.h" +#include "core/crypto/onion.h" +#include "core/crypto/onion_fast.h" +#include "core/crypto/onion_ntor.h" +#include "core/crypto/onion_tap.h" +#include "core/or/relay.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" + +#include "core/or/cell_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/or_circuit_st.h" // trunnel -#include "ed25519_cert.h" +#include "trunnel/ed25519_cert.h" /** Type for a linked list of circuits that are waiting for a free CPU worker * to process a waiting onion handshake. */ @@ -554,7 +559,7 @@ onion_skin_server_handshake(int type, (char*)keys_out, keys_out_len)<0) return -1; r = TAP_ONIONSKIN_REPLY_LEN; - memcpy(rend_nonce_out, reply_out+DH_KEY_LEN, DIGEST_LEN); + memcpy(rend_nonce_out, reply_out+DH1024_KEY_LEN, DIGEST_LEN); break; case ONION_HANDSHAKE_TYPE_FAST: if (onionskin_len != CREATE_FAST_LEN) @@ -631,7 +636,7 @@ onion_skin_client_handshake(int type, msg_out) < 0) return -1; - memcpy(rend_authenticator_out, reply+DH_KEY_LEN, DIGEST_LEN); + memcpy(rend_authenticator_out, reply+DH1024_KEY_LEN, DIGEST_LEN); return 0; case ONION_HANDSHAKE_TYPE_FAST: @@ -1339,4 +1344,3 @@ extended_cell_format(uint8_t *command_out, uint16_t *len_out, return 0; } - diff --git a/src/or/onion.h b/src/core/crypto/onion.h index 3b738debeb..ff70f299d5 100644 --- a/src/or/onion.h +++ b/src/core/crypto/onion.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,6 +13,10 @@ #define TOR_ONION_H struct create_cell_t; +struct curve25519_keypair_t; +struct curve25519_public_key_t; +#include "lib/crypt_ops/crypto_ed25519.h" + int onion_pending_add(or_circuit_t *circ, struct create_cell_t *onionskin); or_circuit_t *onion_next_task(struct create_cell_t **onionskin_out); int onion_num_pending(uint16_t handshake_type); @@ -23,8 +27,8 @@ typedef struct server_onion_keys_t { uint8_t my_identity[DIGEST_LEN]; crypto_pk_t *onion_key; crypto_pk_t *last_onion_key; - di_digest256_map_t *curve25519_key_map; - curve25519_keypair_t *junk_keypair; + struct di_digest256_map_t *curve25519_key_map; + struct curve25519_keypair_t *junk_keypair; } server_onion_keys_t; #define MAX_ONIONSKIN_CHALLENGE_LEN 255 @@ -88,7 +92,7 @@ typedef struct extend_cell_t { /** Identity fingerprint of the node we're conecting to.*/ uint8_t node_id[DIGEST_LEN]; /** Ed25519 public identity key. Zero if not set. */ - ed25519_public_key_t ed_pubkey; + struct ed25519_public_key_t ed_pubkey; /** The "create cell" embedded in this extend cell. Note that unlike the * create cells we generate ourself, this once can have a handshake type we * don't recognize. */ @@ -122,4 +126,3 @@ int extended_cell_format(uint8_t *command_out, uint16_t *len_out, uint8_t *payload_out, const extended_cell_t *cell_in); #endif /* !defined(TOR_ONION_H) */ - diff --git a/src/or/onion_fast.c b/src/core/crypto/onion_fast.c index 9f9b2199d4..292aeca402 100644 --- a/src/or/onion_fast.c +++ b/src/core/crypto/onion_fast.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,10 +27,11 @@ * many RSA1024 keys. **/ -#include "or.h" -#include "onion_fast.h" -#include "crypto_rand.h" -#include "crypto_util.h" +#include "core/or/or.h" +#include "core/crypto/onion_fast.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" /** Release all state held in <b>victim</b>. */ void @@ -141,4 +142,3 @@ fast_client_handshake(const fast_handshake_state_t *handshake_state, tor_free(out); return r; } - diff --git a/src/or/onion_fast.h b/src/core/crypto/onion_fast.h index c56712e2c2..a7b6ec53f4 100644 --- a/src/or/onion_fast.h +++ b/src/core/crypto/onion_fast.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/onion_ntor.c b/src/core/crypto/onion_ntor.c index 02d43cb722..9e1e273ef6 100644 --- a/src/or/onion_ntor.c +++ b/src/core/crypto/onion_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,12 +21,17 @@ #include "orconfig.h" #define ONION_NTOR_PRIVATE -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_util.h" -#include "onion_ntor.h" -#include "torlog.h" -#include "util.h" + +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "core/crypto/onion_ntor.h" + +#include <string.h> /** Free storage held in an ntor handshake state. */ void @@ -334,4 +339,3 @@ onion_skin_ntor_client_handshake( return bad ? -1 : 0; } - diff --git a/src/or/onion_ntor.h b/src/core/crypto/onion_ntor.h index f7c962b7d0..0ba4abe49e 100644 --- a/src/or/onion_ntor.h +++ b/src/core/crypto/onion_ntor.h @@ -1,12 +1,14 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ONION_NTOR_H #define TOR_ONION_NTOR_H -#include "torint.h" -#include "crypto_curve25519.h" -#include "di_ops.h" +#include "lib/cc/torint.h" + +struct di_digest256_map_t; +struct curve25519_public_key_t; +struct curve25519_keypair_t; /** State to be maintained by a client between sending an ntor onionskin * and receiving a reply. */ @@ -22,17 +24,17 @@ void ntor_handshake_state_free_(ntor_handshake_state_t *state); FREE_AND_NULL(ntor_handshake_state_t, ntor_handshake_state_free_, (state)) int onion_skin_ntor_create(const uint8_t *router_id, - const curve25519_public_key_t *router_key, + const struct curve25519_public_key_t *router_key, ntor_handshake_state_t **handshake_state_out, uint8_t *onion_skin_out); int onion_skin_ntor_server_handshake(const uint8_t *onion_skin, - const di_digest256_map_t *private_keys, - const curve25519_keypair_t *junk_keypair, - const uint8_t *my_node_id, - uint8_t *handshake_reply_out, - uint8_t *key_out, - size_t key_out_len); + const struct di_digest256_map_t *private_keys, + const struct curve25519_keypair_t *junk_keypair, + const uint8_t *my_node_id, + uint8_t *handshake_reply_out, + uint8_t *key_out, + size_t key_out_len); int onion_skin_ntor_client_handshake( const ntor_handshake_state_t *handshake_state, @@ -42,6 +44,7 @@ int onion_skin_ntor_client_handshake( const char **msg_out); #ifdef ONION_NTOR_PRIVATE +#include "lib/crypt_ops/crypto_curve25519.h" /** Storage held by a client while waiting for an ntor reply from a server. */ struct ntor_handshake_state_t { @@ -60,4 +63,3 @@ struct ntor_handshake_state_t { #endif /* defined(ONION_NTOR_PRIVATE) */ #endif /* !defined(TOR_ONION_NTOR_H) */ - diff --git a/src/or/onion_tap.c b/src/core/crypto/onion_tap.c index 44737034f4..7ffe0ea5c5 100644 --- a/src/or/onion_tap.c +++ b/src/core/crypto/onion_tap.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,12 +27,13 @@ * invoked from onion.c. **/ -#include "or.h" -#include "config.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "onion_tap.h" -#include "rephist.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "core/crypto/onion_tap.h" +#include "feature/stats/rephist.h" /*----------------------------------------------------------------------*/ @@ -53,7 +54,7 @@ onion_skin_TAP_create(crypto_pk_t *dest_router_key, crypto_dh_t **handshake_state_out, char *onion_skin_out) /* TAP_ONIONSKIN_CHALLENGE_LEN bytes */ { - char challenge[DH_KEY_LEN]; + char challenge[DH1024_KEY_LEN]; crypto_dh_t *dh = NULL; int dhbytes, pkbytes; @@ -77,7 +78,7 @@ onion_skin_TAP_create(crypto_pk_t *dest_router_key, /* set meeting point, meeting cookie, etc here. Leave zero for now. */ if (crypto_pk_obsolete_public_hybrid_encrypt(dest_router_key, onion_skin_out, TAP_ONIONSKIN_CHALLENGE_LEN, - challenge, DH_KEY_LEN, + challenge, DH1024_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1)<0) goto err; @@ -136,7 +137,7 @@ onion_skin_TAP_server_handshake( log_info(LD_PROTOCOL, "Couldn't decrypt onionskin: client may be using old onion key"); goto err; - } else if (len != DH_KEY_LEN) { + } else if (len != DH1024_KEY_LEN) { log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL, "Unexpected onionskin length after decryption: %ld", (long)len); @@ -152,7 +153,7 @@ onion_skin_TAP_server_handshake( goto err; /* LCOV_EXCL_STOP */ } - if (crypto_dh_get_public(dh, handshake_reply_out, DH_KEY_LEN)) { + if (crypto_dh_get_public(dh, handshake_reply_out, DH1024_KEY_LEN)) { /* LCOV_EXCL_START * This can only fail if the length of the key we just allocated is too * big. That should be impossible. */ @@ -164,7 +165,7 @@ onion_skin_TAP_server_handshake( key_material_len = DIGEST_LEN+key_out_len; key_material = tor_malloc(key_material_len); len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, challenge, - DH_KEY_LEN, key_material, + DH1024_KEY_LEN, key_material, key_material_len); if (len < 0) { log_info(LD_GENERAL, "crypto_dh_compute_secret failed."); @@ -172,7 +173,7 @@ onion_skin_TAP_server_handshake( } /* send back H(K|0) as proof that we learned K. */ - memcpy(handshake_reply_out+DH_KEY_LEN, key_material, DIGEST_LEN); + memcpy(handshake_reply_out+DH1024_KEY_LEN, key_material, DIGEST_LEN); /* use the rest of the key material for our shared keys, digests, etc */ memcpy(key_out, key_material+DIGEST_LEN, key_out_len); @@ -212,12 +213,12 @@ onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, ssize_t len; char *key_material=NULL; size_t key_material_len; - tor_assert(crypto_dh_get_bytes(handshake_state) == DH_KEY_LEN); + tor_assert(crypto_dh_get_bytes(handshake_state) == DH1024_KEY_LEN); key_material_len = DIGEST_LEN + key_out_len; key_material = tor_malloc(key_material_len); len = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, handshake_state, - handshake_reply, DH_KEY_LEN, key_material, + handshake_reply, DH1024_KEY_LEN, key_material, key_material_len); if (len < 0) { if (msg_out) @@ -225,7 +226,7 @@ onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, goto err; } - if (tor_memneq(key_material, handshake_reply+DH_KEY_LEN, DIGEST_LEN)) { + if (tor_memneq(key_material, handshake_reply+DH1024_KEY_LEN, DIGEST_LEN)) { /* H(K) does *not* match. Something fishy. */ if (msg_out) *msg_out = "Digest DOES NOT MATCH on onion handshake. Bug or attack."; @@ -243,4 +244,3 @@ onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, tor_free(key_material); return -1; } - diff --git a/src/or/onion_tap.h b/src/core/crypto/onion_tap.h index 713c1d7391..9a3df684d6 100644 --- a/src/or/onion_tap.h +++ b/src/core/crypto/onion_tap.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,25 +14,27 @@ #define TAP_ONIONSKIN_CHALLENGE_LEN (PKCS1_OAEP_PADDING_OVERHEAD+\ CIPHER_KEY_LEN+\ - DH_KEY_LEN) -#define TAP_ONIONSKIN_REPLY_LEN (DH_KEY_LEN+DIGEST_LEN) + DH1024_KEY_LEN) +#define TAP_ONIONSKIN_REPLY_LEN (DH1024_KEY_LEN+DIGEST_LEN) -int onion_skin_TAP_create(crypto_pk_t *router_key, - crypto_dh_t **handshake_state_out, +struct crypto_dh_t; +struct crypto_pk_t; + +int onion_skin_TAP_create(struct crypto_pk_t *router_key, + struct crypto_dh_t **handshake_state_out, char *onion_skin_out); int onion_skin_TAP_server_handshake(const char *onion_skin, - crypto_pk_t *private_key, - crypto_pk_t *prev_private_key, + struct crypto_pk_t *private_key, + struct crypto_pk_t *prev_private_key, char *handshake_reply_out, char *key_out, size_t key_out_len); -int onion_skin_TAP_client_handshake(crypto_dh_t *handshake_state, +int onion_skin_TAP_client_handshake(struct crypto_dh_t *handshake_state, const char *handshake_reply, char *key_out, size_t key_out_len, const char **msg_out); #endif /* !defined(TOR_ONION_TAP_H) */ - diff --git a/src/or/relay_crypto.c b/src/core/crypto/relay_crypto.c index 530c8e5828..b2388d2c45 100644 --- a/src/or/relay_crypto.c +++ b/src/core/crypto/relay_crypto.c @@ -4,12 +4,18 @@ * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN -#include "relay.h" -#include "relay_crypto.h" +#include "core/or/or.h" +#include "core/or/circuitlist.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_util.h" +#include "core/crypto/hs_ntor.h" // for HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN +#include "core/or/relay.h" +#include "core/crypto/relay_crypto.h" + +#include "core/or/cell_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" /** Update digest from the payload of cell. Assign integrity part to * cell. @@ -324,4 +330,3 @@ relay_crypto_assert_ok(const relay_crypto_t *crypto) tor_assert(crypto->f_digest); tor_assert(crypto->b_digest); } - diff --git a/src/or/relay_crypto.h b/src/core/crypto/relay_crypto.h index 66ae02cee9..67da93344f 100644 --- a/src/or/relay_crypto.h +++ b/src/core/crypto/relay_crypto.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/include.am b/src/core/include.am new file mode 100644 index 0000000000..1f37044e9a --- /dev/null +++ b/src/core/include.am @@ -0,0 +1,330 @@ + +noinst_LIBRARIES += \ + src/core/libtor-app.a +if UNITTESTS_ENABLED +noinst_LIBRARIES += \ + src/core/libtor-app-testing.a +endif + +LIBTOR_APP_A_SOURCES = \ + src/app/config/config.c \ + src/app/config/confparse.c \ + src/app/config/statefile.c \ + src/core/crypto/hs_ntor.c \ + src/core/crypto/onion.c \ + src/core/crypto/onion_fast.c \ + src/core/crypto/onion_ntor.c \ + src/core/crypto/onion_tap.c \ + src/core/crypto/relay_crypto.c \ + src/core/mainloop/connection.c \ + src/core/mainloop/cpuworker.c \ + src/core/mainloop/main.c \ + src/core/mainloop/periodic.c \ + src/core/or/address_set.c \ + src/core/or/channel.c \ + src/core/or/channelpadding.c \ + src/core/or/channeltls.c \ + src/core/or/circuitbuild.c \ + src/core/or/circuitlist.c \ + src/core/or/circuitmux.c \ + src/core/or/circuitmux_ewma.c \ + src/core/or/circuitstats.c \ + src/core/or/circuituse.c \ + src/core/or/command.c \ + src/core/or/connection_edge.c \ + src/core/or/connection_or.c \ + src/core/or/dos.c \ + src/core/or/git_revision.c \ + src/core/or/policies.c \ + src/core/or/protover.c \ + src/core/or/reasons.c \ + src/core/or/relay.c \ + src/core/or/scheduler.c \ + src/core/or/scheduler_kist.c \ + src/core/or/scheduler_vanilla.c \ + src/core/or/status.c \ + src/core/proto/proto_cell.c \ + src/core/proto/proto_control0.c \ + src/core/proto/proto_ext_or.c \ + src/core/proto/proto_http.c \ + src/core/proto/proto_socks.c \ + src/core/proto/protover_rust.c \ + src/feature/api/tor_api.c \ + src/feature/client/addressmap.c \ + src/feature/client/bridges.c \ + src/feature/client/circpathbias.c \ + src/feature/client/dnsserv.c \ + src/feature/client/entrynodes.c \ + src/feature/client/transports.c \ + src/feature/control/control.c \ + src/feature/dirauth/keypin.c \ + src/feature/dircache/conscache.c \ + src/feature/dircache/consdiffmgr.c \ + src/feature/dircache/directory.c \ + src/feature/dircache/dirserv.c \ + src/feature/dircommon/consdiff.c \ + src/feature/dircommon/fp_pair.c \ + src/feature/dircommon/voting_schedule.c \ + src/feature/hibernate/hibernate.c \ + src/feature/hs/hs_cache.c \ + src/feature/hs/hs_cell.c \ + src/feature/hs/hs_circuit.c \ + src/feature/hs/hs_circuitmap.c \ + src/feature/hs/hs_client.c \ + src/feature/hs/hs_common.c \ + src/feature/hs/hs_config.c \ + src/feature/hs/hs_control.c \ + src/feature/hs/hs_descriptor.c \ + src/feature/hs/hs_ident.c \ + src/feature/hs/hs_intropoint.c \ + src/feature/hs/hs_service.c \ + src/feature/hs/hs_stats.c \ + src/feature/hs_common/replaycache.c \ + src/feature/hs_common/shared_random_client.c \ + src/feature/nodelist/microdesc.c \ + src/feature/nodelist/networkstatus.c \ + src/feature/nodelist/nodelist.c \ + src/feature/nodelist/parsecommon.c \ + src/feature/nodelist/routerlist.c \ + src/feature/nodelist/routerparse.c \ + src/feature/nodelist/routerset.c \ + src/feature/nodelist/torcert.c \ + src/feature/relay/dns.c \ + src/feature/relay/ext_orport.c \ + src/feature/relay/router.c \ + src/feature/relay/routerkeys.c \ + src/feature/rend/rendcache.c \ + src/feature/rend/rendclient.c \ + src/feature/rend/rendcommon.c \ + src/feature/rend/rendmid.c \ + src/feature/rend/rendservice.c \ + src/feature/stats/geoip.c \ + src/feature/stats/rephist.c + +if BUILD_NT_SERVICES +LIBTOR_APP_A_SOURCES += src/app/main/ntmain.c +endif + +# +# Modules are conditionnally compiled in tor starting here. We add the C files +# only if the modules has been enabled at configure time. We always add the +# source files of every module to libtor-testing.a so we can build the unit +# tests for everything. See the UNITTESTS_ENABLED branch below. +# +LIBTOR_APP_TESTING_A_SOURCES = $(LIBTOR_APP_A_SOURCES) + +# The Directory Authority module. +MODULE_DIRAUTH_SOURCES = \ + src/feature/dirauth/dircollate.c \ + src/feature/dirauth/dirvote.c \ + src/feature/dirauth/shared_random.c \ + src/feature/dirauth/shared_random_state.c + +if BUILD_MODULE_DIRAUTH +LIBTOR_APP_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) +endif + +src_core_libtor_app_a_SOURCES = $(LIBTOR_APP_A_SOURCES) +if UNITTESTS_ENABLED + +# Add the sources of the modules that are needed for tests to work here. +LIBTOR_APP_TESTING_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) + +src_core_libtor_app_testing_a_SOURCES = $(LIBTOR_APP_TESTING_A_SOURCES) +else +src_core_libtor_app_testing_a_SOURCES = +endif + +src/core/or/git_revision.$(OBJEXT) \ + src/core/or/src_core_libtor_app_testing_a-git_revision.$(OBJEXT): \ + micro-revision.i + +AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \ + -DLOCALSTATEDIR="\"$(localstatedir)\"" \ + -DBINDIR="\"$(bindir)\"" + +src_core_libtor_app_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_core_libtor_app_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/app/config/config.h \ + src/app/config/confparse.h \ + src/app/config/or_options_st.h \ + src/app/config/or_state_st.h \ + src/app/config/statefile.h \ + src/app/main/ntmain.h \ + src/core/crypto/hs_ntor.h \ + src/core/crypto/onion.h \ + src/core/crypto/onion_fast.h \ + src/core/crypto/onion_ntor.h \ + src/core/crypto/onion_tap.h \ + src/core/crypto/relay_crypto.h \ + src/core/mainloop/connection.h \ + src/core/mainloop/cpuworker.h \ + src/core/mainloop/main.h \ + src/core/mainloop/periodic.h \ + src/core/or/addr_policy_st.h \ + src/core/or/address_set.h \ + src/core/or/cell_queue_st.h \ + src/core/or/cell_st.h \ + src/core/or/channel.h \ + src/core/or/channelpadding.h \ + src/core/or/channeltls.h \ + src/core/or/circuit_st.h \ + src/core/or/circuitbuild.h \ + src/core/or/circuitlist.h \ + src/core/or/circuitmux.h \ + src/core/or/circuitmux_ewma.h \ + src/core/or/circuitstats.h \ + src/core/or/circuituse.h \ + src/core/or/command.h \ + src/core/or/connection_edge.h \ + src/core/or/connection_or.h \ + src/core/or/connection_st.h \ + src/core/or/cpath_build_state_st.h \ + src/core/or/crypt_path_reference_st.h \ + src/core/or/crypt_path_st.h \ + src/core/or/destroy_cell_queue_st.h \ + src/core/or/dos.h \ + src/core/or/edge_connection_st.h \ + src/core/or/entry_connection_st.h \ + src/core/or/entry_port_cfg_st.h \ + src/core/or/extend_info_st.h \ + src/core/or/git_revision.h \ + src/core/or/listener_connection_st.h \ + src/core/or/or.h \ + src/core/or/or_circuit_st.h \ + src/core/or/or_connection_st.h \ + src/core/or/or_handshake_certs_st.h \ + src/core/or/or_handshake_state_st.h \ + src/core/or/origin_circuit_st.h \ + src/core/or/policies.h \ + src/core/or/port_cfg_st.h \ + src/core/or/protover.h \ + src/core/or/reasons.h \ + src/core/or/relay.h \ + src/core/or/relay_crypto_st.h \ + src/core/or/scheduler.h \ + src/core/or/server_port_cfg_st.h \ + src/core/or/socks_request_st.h \ + src/core/or/status.h \ + src/core/or/tor_version_st.h \ + src/core/or/var_cell_st.h \ + src/core/proto/proto_cell.h \ + src/core/proto/proto_control0.h \ + src/core/proto/proto_ext_or.h \ + src/core/proto/proto_http.h \ + src/core/proto/proto_socks.h \ + src/feature/api/tor_api_internal.h \ + src/feature/client/addressmap.h \ + src/feature/client/bridges.h \ + src/feature/client/circpathbias.h \ + src/feature/client/dnsserv.h \ + src/feature/client/entrynodes.h \ + src/feature/client/transports.h \ + src/feature/control/control.h \ + src/feature/control/control_connection_st.h \ + src/feature/dirauth/dircollate.h \ + src/feature/dirauth/dirvote.h \ + src/feature/dirauth/keypin.h \ + src/feature/dirauth/mode.h \ + src/feature/dirauth/ns_detached_signatures_st.h \ + src/feature/dirauth/shared_random.h \ + src/feature/dirauth/shared_random_state.h \ + src/feature/dirauth/vote_microdesc_hash_st.h \ + src/feature/dircache/cached_dir_st.h \ + src/feature/dircache/conscache.h \ + src/feature/dircache/consdiffmgr.h \ + src/feature/dircache/directory.h \ + src/feature/dircache/dirserv.h \ + src/feature/dirclient/dir_server_st.h \ + src/feature/dirclient/download_status_st.h \ + src/feature/dircommon/consdiff.h \ + src/feature/dircommon/dir_connection_st.h \ + src/feature/dircommon/fp_pair.h \ + src/feature/dircommon/vote_timing_st.h \ + src/feature/dircommon/voting_schedule.h \ + src/feature/hibernate/hibernate.h \ + src/feature/hs/hs_cache.h \ + src/feature/hs/hs_cell.h \ + src/feature/hs/hs_circuit.h \ + src/feature/hs/hs_circuitmap.h \ + src/feature/hs/hs_client.h \ + src/feature/hs/hs_common.h \ + src/feature/hs/hs_config.h \ + src/feature/hs/hs_control.h \ + src/feature/hs/hs_descriptor.h \ + src/feature/hs/hs_ident.h \ + src/feature/hs/hs_intropoint.h \ + src/feature/hs/hs_service.h \ + src/feature/hs/hs_stats.h \ + src/feature/hs/hsdir_index_st.h \ + src/feature/hs_common/replaycache.h \ + src/feature/hs_common/shared_random_client.h \ + src/feature/nodelist/authority_cert_st.h \ + src/feature/nodelist/desc_store_st.h \ + src/feature/nodelist/document_signature_st.h \ + src/feature/nodelist/extrainfo_st.h \ + src/feature/nodelist/microdesc.h \ + src/feature/nodelist/microdesc_st.h \ + src/feature/nodelist/networkstatus.h \ + src/feature/nodelist/networkstatus_sr_info_st.h \ + src/feature/nodelist/networkstatus_st.h \ + src/feature/nodelist/networkstatus_voter_info_st.h \ + src/feature/nodelist/node_st.h \ + src/feature/nodelist/nodelist.h \ + src/feature/nodelist/parsecommon.h \ + src/feature/nodelist/routerinfo_st.h \ + src/feature/nodelist/routerlist.h \ + src/feature/nodelist/routerlist_st.h \ + src/feature/nodelist/routerparse.h \ + src/feature/nodelist/routerset.h \ + src/feature/nodelist/routerstatus_st.h \ + src/feature/nodelist/signed_descriptor_st.h \ + src/feature/nodelist/torcert.h \ + src/feature/nodelist/vote_routerstatus_st.h \ + src/feature/relay/dns.h \ + src/feature/relay/dns_structs.h \ + src/feature/relay/ext_orport.h \ + src/feature/relay/router.h \ + src/feature/relay/routerkeys.h \ + src/feature/rend/rend_authorized_client_st.h \ + src/feature/rend/rend_encoded_v2_service_descriptor_st.h \ + src/feature/rend/rend_intro_point_st.h \ + src/feature/rend/rend_service_descriptor_st.h \ + src/feature/rend/rendcache.h \ + src/feature/rend/rendclient.h \ + src/feature/rend/rendcommon.h \ + src/feature/rend/rendmid.h \ + src/feature/rend/rendservice.h \ + src/feature/stats/geoip.h \ + src/feature/stats/rephist.h + +noinst_HEADERS += \ + src/app/config/auth_dirs.inc \ + src/app/config/fallback_dirs.inc + +# This may someday want to be an installed file? +noinst_HEADERS += src/feature/api/tor_api.h + +micro-revision.i: FORCE + $(AM_V_at)rm -f micro-revision.tmp; \ + if test -r "$(top_srcdir)/.git" && \ + test -x "`which git 2>&1;true`"; then \ + HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \ + echo \"$$HASH\" > micro-revision.tmp; \ + fi; \ + if test ! -f micro-revision.tmp; then \ + if test ! -f micro-revision.i; then \ + echo '""' > micro-revision.i; \ + fi; \ + elif test ! -f micro-revision.i || \ + test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \ + mv micro-revision.tmp micro-revision.i; \ + fi; \ + rm -f micro-revision.tmp; \ + true + +CLEANFILES+= micro-revision.i micro-revision.tmp + +FORCE: diff --git a/src/or/connection.c b/src/core/mainloop/connection.c index 7283a81043..ed789d5208 100644 --- a/src/or/connection.c +++ b/src/core/mainloop/connection.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,64 +55,84 @@ **/ #define CONNECTION_PRIVATE -#include "or.h" -#include "bridges.h" -#include "buffers.h" -#include "buffers_tls.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" /* * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ #define TOR_CHANNEL_INTERNAL_ #define CONNECTION_PRIVATE -#include "backtrace.h" -#include "channel.h" -#include "channeltls.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "dns.h" -#include "dnsserv.h" -#include "dos.h" -#include "entrynodes.h" -#include "ext_orport.h" -#include "geoip.h" -#include "main.h" -#include "hibernate.h" -#include "hs_common.h" -#include "hs_ident.h" -#include "nodelist.h" -#include "proto_http.h" -#include "proto_socks.h" -#include "policies.h" -#include "reasons.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "transports.h" -#include "routerparse.h" -#include "sandbox.h" +#include "lib/err/backtrace.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/relay/dns.h" +#include "feature/client/dnsserv.h" +#include "core/or/dos.h" +#include "feature/client/entrynodes.h" +#include "feature/relay/ext_orport.h" +#include "feature/stats/geoip.h" +#include "core/mainloop/main.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_ident.h" +#include "feature/nodelist/nodelist.h" +#include "core/proto/proto_http.h" +#include "core/proto/proto_socks.h" +#include "core/or/policies.h" +#include "core/or/reasons.h" +#include "core/or/relay.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/client/transports.h" +#include "feature/nodelist/routerparse.h" +#include "lib/sandbox/sandbox.h" +#include "lib/net/buffers_net.h" +#include "lib/tls/tortls.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/compress/compress.h" #ifdef HAVE_PWD_H #include <pwd.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + #ifdef HAVE_SYS_UN_H #include <sys/socket.h> #include <sys/un.h> #endif +#include "feature/dircommon/dir_connection_st.h" +#include "feature/control/control_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/listener_connection_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/port_cfg_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "core/or/socks_request_st.h" + static connection_t *connection_listener_new( const struct sockaddr *listensockaddr, socklen_t listensocklen, int type, @@ -167,6 +187,27 @@ static smartlist_t *outgoing_addrs = NULL; /**************************************************************/ +/** Convert a connection_t* to an listener_connection_t*; assert if the cast + * is invalid. */ +listener_connection_t * +TO_LISTENER_CONN(connection_t *c) +{ + tor_assert(c->magic == LISTENER_CONNECTION_MAGIC); + return DOWNCAST(listener_connection_t, c); +} + +size_t +connection_get_inbuf_len(connection_t *conn) +{ + return conn->inbuf ? buf_datalen(conn->inbuf) : 0; +} + +size_t +connection_get_outbuf_len(connection_t *conn) +{ + return conn->outbuf ? buf_datalen(conn->outbuf) : 0; +} + /** * Return the human-readable name for the connection type <b>type</b> */ @@ -583,9 +624,9 @@ connection_free_minimal(connection_t *conn) /* Owww, this shouldn't happen, but... */ log_info(LD_CHANNEL, "Freeing orconn at %p, saw channel %p with ID " - U64_FORMAT " left un-NULLed", + "%"PRIu64 " left un-NULLed", or_conn, TLS_CHAN_TO_BASE(or_conn->chan), - U64_PRINTF_ARG( + ( TLS_CHAN_TO_BASE(or_conn->chan)->global_identifier)); if (!CHANNEL_FINISHED(TLS_CHAN_TO_BASE(or_conn->chan))) { channel_close_for_error(TLS_CHAN_TO_BASE(or_conn->chan)); @@ -4111,6 +4152,13 @@ connection_write_to_buf_impl_,(const char *string, size_t len, connection_write_to_buf_commit(conn, written); } +void +connection_buf_add_compress(const char *string, size_t len, + dir_connection_t *conn, int done) +{ + connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1); +} + /** * Add all bytes from <b>buf</b> to <b>conn</b>'s outbuf, draining them * from <b>buf</b>. (If the connection is marked and will soon be closed, @@ -4815,6 +4863,20 @@ kill_conn_list_for_oos, (smartlist_t *conns)) smartlist_len(conns)); } +/** Check if a connection is on the way out so the OOS handler doesn't try + * to kill more than it needs. */ +int +connection_is_moribund(connection_t *conn) +{ + if (conn != NULL && + (conn->conn_array_index < 0 || + conn->marked_for_close)) { + return 1; + } else { + return 0; + } +} + /** Out-of-Sockets handler; n_socks is the current number of open * sockets, and failed is non-zero if a socket exhaustion related * error immediately preceded this call. This is where to do @@ -4937,16 +4999,16 @@ connection_dump_buffer_mem_stats(int severity) } tor_log(severity, LD_GENERAL, - "In buffers for %d connections: "U64_FORMAT" used/"U64_FORMAT" allocated", + "In buffers for %d connections: %"PRIu64" used/%"PRIu64" allocated", smartlist_len(conns), - U64_PRINTF_ARG(total_used), U64_PRINTF_ARG(total_alloc)); + (total_used), (total_alloc)); for (i=CONN_TYPE_MIN_; i <= CONN_TYPE_MAX_; ++i) { if (!n_conns_by_type[i]) continue; tor_log(severity, LD_GENERAL, - " For %d %s connections: "U64_FORMAT" used/"U64_FORMAT" allocated", + " For %d %s connections: %"PRIu64" used/%"PRIu64" allocated", n_conns_by_type[i], conn_type_to_string(i), - U64_PRINTF_ARG(used_by_type[i]), U64_PRINTF_ARG(alloc_by_type[i])); + (used_by_type[i]), (alloc_by_type[i])); } } @@ -5267,4 +5329,3 @@ clock_skew_warning, (const connection_t *conn, long apparent_skew, int trusted, tor_free(warn); tor_free(ext_source); } - diff --git a/src/or/connection.h b/src/core/mainloop/connection.h index ad3129c9d8..3419ee65e8 100644 --- a/src/or/connection.h +++ b/src/core/mainloop/connection.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,74 @@ #ifndef TOR_CONNECTION_H #define TOR_CONNECTION_H -/* XXXX For buf_datalen in inline function */ -#include "buffers.h" +listener_connection_t *TO_LISTENER_CONN(connection_t *); + +struct buf_t; + +#define CONN_TYPE_MIN_ 3 +/** Type for sockets listening for OR connections. */ +#define CONN_TYPE_OR_LISTENER 3 +/** A bidirectional TLS connection transmitting a sequence of cells. + * May be from an OR to an OR, or from an OP to an OR. */ +#define CONN_TYPE_OR 4 +/** A TCP connection from an onion router to a stream's destination. */ +#define CONN_TYPE_EXIT 5 +/** Type for sockets listening for SOCKS connections. */ +#define CONN_TYPE_AP_LISTENER 6 +/** A SOCKS proxy connection from the user application to the onion + * proxy. */ +#define CONN_TYPE_AP 7 +/** Type for sockets listening for HTTP connections to the directory server. */ +#define CONN_TYPE_DIR_LISTENER 8 +/** Type for HTTP connections to the directory server. */ +#define CONN_TYPE_DIR 9 +/* Type 10 is unused. */ +/** Type for listening for connections from user interface process. */ +#define CONN_TYPE_CONTROL_LISTENER 11 +/** Type for connections from user interface process. */ +#define CONN_TYPE_CONTROL 12 +/** Type for sockets listening for transparent connections redirected by pf or + * netfilter. */ +#define CONN_TYPE_AP_TRANS_LISTENER 13 +/** Type for sockets listening for transparent connections redirected by + * natd. */ +#define CONN_TYPE_AP_NATD_LISTENER 14 +/** Type for sockets listening for DNS requests. */ +#define CONN_TYPE_AP_DNS_LISTENER 15 + +/** Type for connections from the Extended ORPort. */ +#define CONN_TYPE_EXT_OR 16 +/** Type for sockets listening for Extended ORPort connections. */ +#define CONN_TYPE_EXT_OR_LISTENER 17 +/** Type for sockets listening for HTTP CONNECT tunnel connections. */ +#define CONN_TYPE_AP_HTTP_CONNECT_LISTENER 18 + +#define CONN_TYPE_MAX_ 19 +/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in + * connection_t. */ + +/* Proxy client handshake states */ +/* We use a proxy but we haven't even connected to it yet. */ +#define PROXY_INFANT 1 +/* We use an HTTP proxy and we've sent the CONNECT command. */ +#define PROXY_HTTPS_WANT_CONNECT_OK 2 +/* We use a SOCKS4 proxy and we've sent the CONNECT command. */ +#define PROXY_SOCKS4_WANT_CONNECT_OK 3 +/* We use a SOCKS5 proxy and we try to negotiate without + any authentication . */ +#define PROXY_SOCKS5_WANT_AUTH_METHOD_NONE 4 +/* We use a SOCKS5 proxy and we try to negotiate with + Username/Password authentication . */ +#define PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929 5 +/* We use a SOCKS5 proxy and we just sent our credentials. */ +#define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6 +/* We use a SOCKS5 proxy and we just sent our CONNECT command. */ +#define PROXY_SOCKS5_WANT_CONNECT_OK 7 +/* We use a proxy and we CONNECTed successfully!. */ +#define PROXY_CONNECTED 8 + +/** State for any listener connection. */ +#define LISTENER_STATE_READY 0 const char *conn_type_to_string(int type); const char *conn_state_to_string(int type, int state); @@ -150,39 +216,17 @@ MOCK_DECL(void, connection_write_to_buf_impl_, /* DOCDOC connection_write_to_buf */ static void connection_buf_add(const char *string, size_t len, connection_t *conn); -/* DOCDOC connection_write_to_buf_compress */ -static void connection_buf_add_compress(const char *string, size_t len, - dir_connection_t *conn, int done); static inline void connection_buf_add(const char *string, size_t len, connection_t *conn) { connection_write_to_buf_impl_(string, len, conn, 0); } -static inline void -connection_buf_add_compress(const char *string, size_t len, - dir_connection_t *conn, int done) -{ - connection_write_to_buf_impl_(string, len, TO_CONN(conn), done ? -1 : 1); -} -void connection_buf_add_buf(connection_t *conn, buf_t *buf); - -/* DOCDOC connection_get_inbuf_len */ -static size_t connection_get_inbuf_len(connection_t *conn); -/* DOCDOC connection_get_outbuf_len */ -static size_t connection_get_outbuf_len(connection_t *conn); - -static inline size_t -connection_get_inbuf_len(connection_t *conn) -{ - return conn->inbuf ? buf_datalen(conn->inbuf) : 0; -} - -static inline size_t -connection_get_outbuf_len(connection_t *conn) -{ - return conn->outbuf ? buf_datalen(conn->outbuf) : 0; -} +void connection_buf_add_compress(const char *string, size_t len, + dir_connection_t *conn, int done); +void connection_buf_add_buf(connection_t *conn, struct buf_t *buf); +size_t connection_get_inbuf_len(connection_t *conn); +size_t connection_get_outbuf_len(connection_t *conn); connection_t *connection_get_by_global_id(uint64_t id); connection_t *connection_get_by_type(int type); @@ -259,22 +303,27 @@ MOCK_DECL(void, clock_skew_warning, log_domain_mask_t domain, const char *received, const char *source)); -/** Check if a connection is on the way out so the OOS handler doesn't try - * to kill more than it needs. */ -static inline int -connection_is_moribund(connection_t *conn) -{ - if (conn != NULL && - (conn->conn_array_index < 0 || - conn->marked_for_close)) { - return 1; - } else { - return 0; - } -} - +int connection_is_moribund(connection_t *conn); void connection_check_oos(int n_socks, int failed); +/** Execute the statement <b>stmt</b>, which may log events concerning the + * connection <b>conn</b>. To prevent infinite loops, disable log messages + * being sent to controllers if <b>conn</b> is a control connection. + * + * Stmt must not contain any return or goto statements. + */ +#define CONN_LOG_PROTECT(conn, stmt) \ + STMT_BEGIN \ + int _log_conn_is_control; \ + tor_assert(conn); \ + _log_conn_is_control = (conn->type == CONN_TYPE_CONTROL); \ + if (_log_conn_is_control) \ + disable_control_logging(); \ + STMT_BEGIN stmt; STMT_END; \ + if (_log_conn_is_control) \ + enable_control_logging(); \ + STMT_END + #ifdef CONNECTION_PRIVATE STATIC void connection_free_minimal(connection_t *conn); @@ -292,4 +341,3 @@ MOCK_DECL(STATIC smartlist_t *, pick_oos_victims, (int n)); #endif /* defined(CONNECTION_PRIVATE) */ #endif /* !defined(TOR_CONNECTION_H) */ - diff --git a/src/or/cpuworker.c b/src/core/mainloop/cpuworker.c index 15ef6869cf..a372db3f17 100644 --- a/src/or/cpuworker.c +++ b/src/core/mainloop/cpuworker.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,20 +17,23 @@ * <li>and for calculating diffs and compressing them in consdiffmgr.c. * </ul> **/ -#include "or.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "connection_or.h" -#include "config.h" -#include "cpuworker.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "main.h" -#include "onion.h" -#include "rephist.h" -#include "router.h" -#include "workqueue.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/connection_or.h" +#include "app/config/config.h" +#include "core/mainloop/cpuworker.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "core/mainloop/main.h" +#include "core/crypto/onion.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "lib/evloop/workqueue.h" + +#include "core/or/or_circuit_st.h" +#include "lib/intmath/weakrng.h" static void queue_pending_tasks(void); @@ -280,7 +283,7 @@ get_overhead_for_onionskins(uint32_t *usec_out, double *frac_out, onionskins_usec_internal[onionskin_type]; *usec_out = (uint32_t)(overhead / onionskins_n_processed[onionskin_type]); - *frac_out = U64_TO_DBL(overhead) / onionskins_usec_internal[onionskin_type]; + *frac_out = ((double)overhead) / onionskins_usec_internal[onionskin_type]; return 0; } @@ -594,4 +597,3 @@ cpuworker_cancel_circ_handshake(or_circuit_t *circ) circ->workqueue_entry = NULL; } } - diff --git a/src/or/cpuworker.h b/src/core/mainloop/cpuworker.h index d39851325f..50812b2dab 100644 --- a/src/or/cpuworker.h +++ b/src/core/mainloop/cpuworker.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/main.c b/src/core/mainloop/main.c index 9dce158b33..c5773ddfc1 100644 --- a/src/or/main.c +++ b/src/core/mainloop/main.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -47,80 +47,98 @@ **/ #define MAIN_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "backtrace.h" -#include "bridges.h" -#include "buffers.h" -#include "buffers_tls.h" -#include "channel.h" -#include "channeltls.h" -#include "channelpadding.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitmux_ewma.h" -#include "command.h" -#include "compress.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "consdiffmgr.h" -#include "control.h" -#include "cpuworker.h" -#include "crypto_s2k.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirserv.h" -#include "dns.h" -#include "dnsserv.h" -#include "dos.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hibernate.h" -#include "hs_cache.h" -#include "hs_circuitmap.h" -#include "hs_client.h" -#include "keypin.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "ntmain.h" -#include "onion.h" -#include "periodic.h" -#include "policies.h" -#include "protover.h" -#include "transports.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "scheduler.h" -#include "statefile.h" -#include "status.h" -#include "tor_api.h" -#include "tor_api_internal.h" -#include "util_process.h" -#include "ext_orport.h" -#ifdef USE_DMALLOC -#include <dmalloc.h> -#endif -#include "memarea.h" -#include "sandbox.h" +#include "core/or/or.h" +#include "feature/client/addressmap.h" +#include "lib/err/backtrace.h" +#include "feature/client/bridges.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/channelpadding.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/command.h" +#include "lib/compress/compress.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/control/control.h" +#include "core/mainloop/cpuworker.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/relay/dns.h" +#include "feature/client/dnsserv.h" +#include "core/or/dos.h" +#include "feature/client/entrynodes.h" +#include "feature/stats/geoip.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_client.h" +#include "feature/dirauth/keypin.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "app/main/ntmain.h" +#include "core/crypto/onion.h" +#include "core/mainloop/periodic.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "feature/client/transports.h" +#include "core/or/relay.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "core/or/scheduler.h" +#include "app/config/statefile.h" +#include "core/or/status.h" +#include "feature/api/tor_api.h" +#include "feature/api/tor_api_internal.h" +#include "lib/process/waitpid.h" +#include "feature/relay/ext_orport.h" +#include "lib/memarea/memarea.h" +#include "lib/meminfo/meminfo.h" +#include "lib/osinfo/uname.h" +#include "lib/sandbox/sandbox.h" +#include "lib/fs/lockfile.h" +#include "lib/net/buffers_net.h" +#include "lib/tls/tortls.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/encoding/confline.h" +#include "lib/evloop/timers.h" #include <event2/event.h> -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random.h" +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/mode.h" +#include "feature/dirauth/shared_random.h" + +#include "core/or/cell_st.h" +#include "core/or/entry_connection_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/or_connection_st.h" +#include "app/config/or_state_st.h" +#include "core/or/port_cfg_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "core/or/socks_request_st.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif #ifdef HAVE_SYSTEMD # if defined(__COVERITY__) && !defined(__INCLUDE_LEVEL__) @@ -1262,9 +1280,9 @@ run_connection_housekeeping(int i, time_t now) } else if (!have_any_circuits && now - or_conn->idle_timeout >= chan->timestamp_last_had_circuits) { - log_info(LD_OR,"Expiring non-used OR connection "U64_FORMAT" to fd %d " + log_info(LD_OR,"Expiring non-used OR connection %"PRIu64" to fd %d " "(%s:%d) [no circuits for %d; timeout %d; %scanonical].", - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), (int)conn->s, conn->address, conn->port, (int)(now - chan->timestamp_last_had_circuits), or_conn->idle_timeout, @@ -2687,11 +2705,6 @@ do_hup(void) { const or_options_t *options = get_options(); -#ifdef USE_DMALLOC - dmalloc_log_stats(); - dmalloc_log_changed(0, 1, 0, 0); -#endif - log_notice(LD_GENERAL,"Received reload signal (hup). Reloading config and " "resetting internal state."); if (accounting_is_enabled(options)) @@ -3195,8 +3208,8 @@ static void dumpmemusage(int severity) { connection_dump_buffer_mem_stats(severity); - tor_log(severity, LD_GENERAL, "In rephist: "U64_FORMAT" used by %d Tors.", - U64_PRINTF_ARG(rephist_total_alloc), rephist_total_num); + tor_log(severity, LD_GENERAL, "In rephist: %"PRIu64" used by %d Tors.", + (rephist_total_alloc), rephist_total_num); dump_routerlist_mem_usage(severity); dump_cell_pool_usage(severity); dump_dns_mem_usage(severity); @@ -3259,28 +3272,28 @@ dumpstats(int severity) channel_listener_dumpstats(severity); tor_log(severity, LD_NET, - "Cells processed: "U64_FORMAT" padding\n" - " "U64_FORMAT" create\n" - " "U64_FORMAT" created\n" - " "U64_FORMAT" relay\n" - " ("U64_FORMAT" relayed)\n" - " ("U64_FORMAT" delivered)\n" - " "U64_FORMAT" destroy", - U64_PRINTF_ARG(stats_n_padding_cells_processed), - U64_PRINTF_ARG(stats_n_create_cells_processed), - U64_PRINTF_ARG(stats_n_created_cells_processed), - U64_PRINTF_ARG(stats_n_relay_cells_processed), - U64_PRINTF_ARG(stats_n_relay_cells_relayed), - U64_PRINTF_ARG(stats_n_relay_cells_delivered), - U64_PRINTF_ARG(stats_n_destroy_cells_processed)); + "Cells processed: %"PRIu64" padding\n" + " %"PRIu64" create\n" + " %"PRIu64" created\n" + " %"PRIu64" relay\n" + " (%"PRIu64" relayed)\n" + " (%"PRIu64" delivered)\n" + " %"PRIu64" destroy", + (stats_n_padding_cells_processed), + (stats_n_create_cells_processed), + (stats_n_created_cells_processed), + (stats_n_relay_cells_processed), + (stats_n_relay_cells_relayed), + (stats_n_relay_cells_delivered), + (stats_n_destroy_cells_processed)); if (stats_n_data_cells_packaged) tor_log(severity,LD_NET,"Average packaged cell fullness: %2.3f%%", - 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / - U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); + 100*(((double)stats_n_data_bytes_packaged) / + ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)) ); if (stats_n_data_cells_received) tor_log(severity,LD_NET,"Average delivered cell fullness: %2.3f%%", - 100*(U64_TO_DBL(stats_n_data_bytes_received) / - U64_TO_DBL(stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) ); + 100*(((double)stats_n_data_bytes_received) / + ((double)stats_n_data_cells_received*RELAY_PAYLOAD_SIZE)) ); cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_TAP, "TAP"); cpuworker_log_onionskin_overhead(severity, ONION_HANDSHAKE_TYPE_NTOR,"ntor"); @@ -3292,13 +3305,13 @@ dumpstats(int severity) if (elapsed) { tor_log(severity, LD_NET, - "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec reading", - U64_PRINTF_ARG(stats_n_bytes_read), + "Average bandwidth: %"PRIu64"/%d = %d bytes/sec reading", + (stats_n_bytes_read), (int)elapsed, (int) (stats_n_bytes_read/elapsed)); tor_log(severity, LD_NET, - "Average bandwidth: "U64_FORMAT"/%d = %d bytes/sec writing", - U64_PRINTF_ARG(stats_n_bytes_written), + "Average bandwidth: %"PRIu64"/%d = %d bytes/sec writing", + (stats_n_bytes_written), (int)elapsed, (int) (stats_n_bytes_written/elapsed)); } @@ -3631,7 +3644,7 @@ release_lockfile(void) * only the parts of memory that we won't touch. If !<b>postfork</b>, * Tor is shutting down and we should free everything. * - * Helps us find the real leaks with dmalloc and the like. Also valgrind + * Helps us find the real leaks with sanitizers and the like. Also valgrind * should then report 0 reachable in its leak report (in an ideal world -- * in practice libevent, SSL, libc etc never quite free everything). */ void @@ -3664,7 +3677,7 @@ tor_free_all(int postfork) routerparse_free_all(); ext_orport_free_all(); control_free_all(); - sandbox_free_getaddrinfo_cache(); + tor_free_getaddrinfo_cache(); protover_free_all(); bridges_free_all(); consdiffmgr_free_all(); @@ -3787,18 +3800,11 @@ tor_cleanup(void) timers_shutdown(); -#ifdef USE_DMALLOC - dmalloc_log_stats(); -#endif tor_free_all(0); /* We could move tor_free_all back into the ifdef below later, if it makes shutdown unacceptably slow. But for now, leave it here: it's helped us catch bugs in the past. */ crypto_global_cleanup(); -#ifdef USE_DMALLOC - dmalloc_log_unfreed(); - dmalloc_shutdown(); -#endif } /** Read/create keys as needed, and echo our fingerprint to stdout. */ @@ -3893,7 +3899,7 @@ init_addrinfo(void) // host name to sandbox gethostname(hname, sizeof(hname)); - sandbox_add_addrinfo(hname); + tor_add_addrinfo(hname); } static sandbox_cfg_t* @@ -4221,7 +4227,13 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) } #endif /* defined(_WIN32) */ - configure_backtrace_handler(get_version()); + { + int bt_err = configure_backtrace_handler(get_version()); + if (bt_err < 0) { + log_warn(LD_BUG, "Unable to install backtrace handler: %s", + strerror(-bt_err)); + } + } init_protocol_warning_severity_level(); update_approx_time(time(NULL)); @@ -4229,14 +4241,6 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) tor_compress_init(); init_logging(0); monotime_init(); -#ifdef USE_DMALLOC - { - /* Instruct OpenSSL to use our internal wrappers for malloc, - realloc and free. */ - int r = crypto_use_tor_alloc_functions(); - tor_assert(r == 0); - } -#endif /* defined(USE_DMALLOC) */ #ifdef NT_SERVICE { int done = 0; @@ -4305,4 +4309,3 @@ tor_run_main(const tor_main_configuration_t *tor_cfg) tor_cleanup(); return result; } - diff --git a/src/or/main.h b/src/core/mainloop/main.h index 9dbbc6e5ee..2b44596706 100644 --- a/src/or/main.h +++ b/src/core/mainloop/main.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -96,10 +96,12 @@ uint64_t get_main_loop_idle_count(void); void periodic_events_on_new_options(const or_options_t *options); void reschedule_per_second_timer(void); +struct token_bucket_rw_t; + extern time_t time_of_process_start; extern int quiet_level; -extern token_bucket_rw_t global_bucket; -extern token_bucket_rw_t global_relayed_bucket; +extern struct token_bucket_rw_t global_bucket; +extern struct token_bucket_rw_t global_relayed_bucket; #ifdef MAIN_PRIVATE STATIC void init_connection_lists(void); @@ -112,10 +114,9 @@ STATIC int get_my_roles(const or_options_t *options); extern smartlist_t *connection_array; /* We need the periodic_event_item_t definition. */ -#include "periodic.h" +#include "core/mainloop/periodic.h" extern periodic_event_item_t periodic_events[]; #endif #endif /* defined(MAIN_PRIVATE) */ #endif /* !defined(TOR_MAIN_H) */ - diff --git a/src/or/periodic.c b/src/core/mainloop/periodic.c index 92fa677f8f..c17c0c56d2 100644 --- a/src/or/periodic.c +++ b/src/core/mainloop/periodic.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,11 +11,12 @@ * that they fire. See periodic_events[] in main.c for examples. */ -#include "or.h" -#include "compat_libevent.h" -#include "config.h" -#include "main.h" -#include "periodic.h" +#include "core/or/or.h" +#include "lib/evloop/compat_libevent.h" +#include "app/config/config.h" +#include "core/mainloop/main.h" +#include "core/mainloop/periodic.h" +#include "lib/evloop/compat_libevent.h" /** We disable any interval greater than this number of seconds, on the * grounds that it is probably an absolute time mistakenly passed in as a @@ -169,4 +170,3 @@ periodic_event_disable(periodic_event_item_t *event) mainloop_event_cancel(event->ev); event->enabled = 0; } - diff --git a/src/or/periodic.h b/src/core/mainloop/periodic.h index e8208b2475..4c8c3c96cc 100644 --- a/src/or/periodic.h +++ b/src/core/mainloop/periodic.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PERIODIC_H diff --git a/src/core/or/addr_policy_st.h b/src/core/or/addr_policy_st.h new file mode 100644 index 0000000000..be3e9d8f01 --- /dev/null +++ b/src/core/or/addr_policy_st.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ADDR_POLICY_ST_H +#define TOR_ADDR_POLICY_ST_H + +#include "lib/cc/torint.h" +#include "lib/net/address.h" + +/** What action type does an address policy indicate: accept or reject? */ +typedef enum { + ADDR_POLICY_ACCEPT=1, + ADDR_POLICY_REJECT=2, +} addr_policy_action_t; +#define addr_policy_action_bitfield_t ENUM_BF(addr_policy_action_t) + +/** A reference-counted address policy rule. */ +typedef struct addr_policy_t { + int refcnt; /**< Reference count */ + /** What to do when the policy matches.*/ + addr_policy_action_bitfield_t policy_type:2; + unsigned int is_private:1; /**< True iff this is the pseudo-address, + * "private". */ + unsigned int is_canonical:1; /**< True iff this policy is the canonical + * copy (stored in a hash table to avoid + * duplication of common policies) */ + maskbits_t maskbits; /**< Accept/reject all addresses <b>a</b> such that the + * first <b>maskbits</b> bits of <b>a</b> match + * <b>addr</b>. */ + /** Base address to accept or reject. + * + * Note that wildcards are treated + * differntly depending on address family. An AF_UNSPEC address means + * "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means + * "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means + * "All IPv6 addresses". + **/ + tor_addr_t addr; + uint16_t prt_min; /**< Lowest port number to accept/reject. */ + uint16_t prt_max; /**< Highest port number to accept/reject. */ +} addr_policy_t; + +#endif diff --git a/src/core/or/address_set.c b/src/core/or/address_set.c new file mode 100644 index 0000000000..014e650d2d --- /dev/null +++ b/src/core/or/address_set.c @@ -0,0 +1,71 @@ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file address_set.c + * \brief Implementation for a set of addresses. + * + * This module was first written on a semi-emergency basis to improve the + * robustness of the anti-DoS module. As such, it's written in a pretty + * conservative way, and should be susceptible to improvement later on. + **/ + +#include "orconfig.h" +#include "core/or/address_set.h" +#include "lib/net/address.h" +#include "lib/container/bloomfilt.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "siphash.h" + +/* Wrap our hash function to have the signature that the bloom filter + * needs. */ +static uint64_t +bloomfilt_addr_hash(const struct sipkey *key, + const void *item) +{ + return tor_addr_keyed_hash(key, item); +} + +/** + * Allocate and return an address_set, suitable for holding up to + * <b>max_address_guess</b> distinct values. + */ +address_set_t * +address_set_new(int max_addresses_guess) +{ + uint8_t k[BLOOMFILT_KEY_LEN]; + crypto_rand((void*)k, sizeof(k)); + return bloomfilt_new(max_addresses_guess, bloomfilt_addr_hash, k); +} + +/** + * Add <b>addr</b> to <b>set</b>. + * + * All future queries for <b>addr</b> in set will return true. Removing + * items is not possible. + */ +void +address_set_add(address_set_t *set, const struct tor_addr_t *addr) +{ + bloomfilt_add(set, addr); +} + +/** As address_set_add(), but take an ipv4 address in host order. */ +void +address_set_add_ipv4h(address_set_t *set, uint32_t addr) +{ + tor_addr_t a; + tor_addr_from_ipv4h(&a, addr); + address_set_add(set, &a); +} + +/** + * Return true if <b>addr</b> is a member of <b>set</b>. (And probably, + * return false if <b>addr</b> is not a member of set.) + */ +int +address_set_probably_contains(const address_set_t *set, + const struct tor_addr_t *addr) +{ + return bloomfilt_probably_contains(set, addr); +} diff --git a/src/common/address_set.h b/src/core/or/address_set.h index 28d29f3fdf..2efa1cb03b 100644 --- a/src/common/address_set.h +++ b/src/core/or/address_set.h @@ -1,35 +1,31 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file address_set.h * \brief Types to handle sets of addresses. - * - * This module was first written on a semi-emergency basis to improve the - * robustness of the anti-DoS module. As such, it's written in a pretty - * conservative way, and should be susceptible to improvement later on. **/ #ifndef TOR_ADDRESS_SET_H #define TOR_ADDRESS_SET_H #include "orconfig.h" -#include "torint.h" +#include "lib/cc/torint.h" +#include "lib/container/bloomfilt.h" /** * An address_set_t represents a set of tor_addr_t values. The implementation * is probabilistic: false negatives cannot occur but false positives are * possible. */ -typedef struct address_set_t address_set_t; +typedef struct bloomfilt_t address_set_t; struct tor_addr_t; address_set_t *address_set_new(int max_addresses_guess); -void address_set_free(address_set_t *set); +#define address_set_free(set) bloomfilt_free(set) void address_set_add(address_set_t *set, const struct tor_addr_t *addr); void address_set_add_ipv4h(address_set_t *set, uint32_t addr); -int address_set_probably_contains(address_set_t *set, +int address_set_probably_contains(const address_set_t *set, const struct tor_addr_t *addr); #endif - diff --git a/src/core/or/cell_queue_st.h b/src/core/or/cell_queue_st.h new file mode 100644 index 0000000000..40110019bc --- /dev/null +++ b/src/core/or/cell_queue_st.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef PACKED_CELL_ST_H +#define PACKED_CELL_ST_H + +#include "tor_queue.h" + +/** A cell as packed for writing to the network. */ +struct packed_cell_t { + /** Next cell queued on this circuit. */ + TOR_SIMPLEQ_ENTRY(packed_cell_t) next; + char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ + uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell + * was inserted */ +}; + +/** A queue of cells on a circuit, waiting to be added to the + * or_connection_t's outbuf. */ +struct cell_queue_t { + /** Linked list of packed_cell_t*/ + TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head; + int n; /**< The number of cells in the queue. */ +}; + +#endif diff --git a/src/core/or/cell_st.h b/src/core/or/cell_st.h new file mode 100644 index 0000000000..6728e783b9 --- /dev/null +++ b/src/core/or/cell_st.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CELL_ST_H +#define CELL_ST_H + +/** Parsed onion routing cell. All communication between nodes + * is via cells. */ +struct cell_t { + circid_t circ_id; /**< Circuit which received the cell. */ + uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE, + * CELL_DESTROY, etc */ + uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */ +}; + +#endif + diff --git a/src/or/channel.c b/src/core/or/channel.c index c30e508018..476f31d5b4 100644 --- a/src/or/channel.c +++ b/src/core/or/channel.c @@ -1,5 +1,5 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -57,28 +57,31 @@ /* This one's for stuff only channel.c and the test suite should see */ #define CHANNEL_PRIVATE_ -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "channelpadding.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "config.h" -#include "connection_or.h" /* For var_cell_free() */ -#include "circuitmux.h" -#include "entrynodes.h" -#include "geoip.h" -#include "main.h" -#include "nodelist.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "scheduler.h" -#include "compat_time.h" -#include "networkstatus.h" -#include "rendservice.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/channelpadding.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "app/config/config.h" +#include "core/or/connection_or.h" /* For var_cell_free() */ +#include "core/or/circuitmux.h" +#include "feature/client/entrynodes.h" +#include "feature/stats/geoip.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/relay.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "core/or/scheduler.h" +#include "lib/time/compat_time.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/rend/rendservice.h" +#include "lib/evloop/timers.h" + +#include "core/or/cell_queue_st.h" /* Global lists of channels */ @@ -388,9 +391,9 @@ channel_register(channel_t *chan) if (chan->registered) return; log_debug(LD_CHANNEL, - "Registering channel %p (ID " U64_FORMAT ") " + "Registering channel %p (ID %"PRIu64 ") " "in state %s (%d) with digest %s", - chan, U64_PRINTF_ARG(chan->global_identifier), + chan, (chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->identity_digest, DIGEST_LEN)); @@ -418,9 +421,9 @@ channel_register(channel_t *chan) channel_add_to_digest_map(chan); } else { log_info(LD_CHANNEL, - "Channel %p (global ID " U64_FORMAT ") " + "Channel %p (global ID %"PRIu64 ") " "in state %s (%d) registered with no identity digest", - chan, U64_PRINTF_ARG(chan->global_identifier), + chan, (chan->global_identifier), channel_state_to_string(chan->state), chan->state); } } @@ -484,9 +487,9 @@ channel_listener_register(channel_listener_t *chan_l) if (chan_l->registered) return; log_debug(LD_CHANNEL, - "Registering channel listener %p (ID " U64_FORMAT ") " + "Registering channel listener %p (ID %"PRIu64 ") " "in state %s (%d)", - chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + chan_l, (chan_l->global_identifier), channel_listener_state_to_string(chan_l->state), chan_l->state); @@ -576,9 +579,9 @@ channel_add_to_digest_map(channel_t *chan) TOR_LIST_INSERT_HEAD(&ent->channel_list, chan, next_with_same_id); log_debug(LD_CHANNEL, - "Added channel %p (global ID " U64_FORMAT ") " + "Added channel %p (global ID %"PRIu64 ") " "to identity map in state %s (%d) with digest %s", - chan, U64_PRINTF_ARG(chan->global_identifier), + chan, (chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->identity_digest, DIGEST_LEN)); } @@ -615,18 +618,18 @@ channel_remove_from_digest_map(channel_t *chan) } log_debug(LD_CHANNEL, - "Removed channel %p (global ID " U64_FORMAT ") from " + "Removed channel %p (global ID %"PRIu64 ") from " "identity map in state %s (%d) with digest %s", - chan, U64_PRINTF_ARG(chan->global_identifier), + chan, (chan->global_identifier), channel_state_to_string(chan->state), chan->state, hex_str(chan->identity_digest, DIGEST_LEN)); } else { /* Shouldn't happen */ log_warn(LD_BUG, - "Trying to remove channel %p (global ID " U64_FORMAT ") with " + "Trying to remove channel %p (global ID %"PRIu64 ") with " "digest %s from identity map, but couldn't find any with " "that digest", - chan, U64_PRINTF_ARG(chan->global_identifier), + chan, (chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN)); } } @@ -880,8 +883,8 @@ channel_free_(channel_t *chan) tor_assert(!(chan->registered)); log_debug(LD_CHANNEL, - "Freeing channel " U64_FORMAT " at %p", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Freeing channel %"PRIu64 " at %p", + (chan->global_identifier), chan); /* Get this one out of the scheduler */ scheduler_release_channel(chan); @@ -926,8 +929,8 @@ channel_listener_free_(channel_listener_t *chan_l) if (!chan_l) return; log_debug(LD_CHANNEL, - "Freeing channel_listener_t " U64_FORMAT " at %p", - U64_PRINTF_ARG(chan_l->global_identifier), + "Freeing channel_listener_t %"PRIu64 " at %p", + (chan_l->global_identifier), chan_l); /* It must be closed or errored */ @@ -953,8 +956,8 @@ channel_force_xfree(channel_t *chan) tor_assert(chan); log_debug(LD_CHANNEL, - "Force-freeing channel " U64_FORMAT " at %p", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Force-freeing channel %"PRIu64 " at %p", + (chan->global_identifier), chan); /* Get this one out of the scheduler */ scheduler_release_channel(chan); @@ -997,8 +1000,8 @@ channel_listener_force_xfree(channel_listener_t *chan_l) tor_assert(chan_l); log_debug(LD_CHANNEL, - "Force-freeing channel_listener_t " U64_FORMAT " at %p", - U64_PRINTF_ARG(chan_l->global_identifier), + "Force-freeing channel_listener_t %"PRIu64 " at %p", + (chan_l->global_identifier), chan_l); /* Call a free method if there is one */ @@ -1037,8 +1040,8 @@ channel_listener_set_listener_fn(channel_listener_t *chan_l, log_debug(LD_CHANNEL, "Setting listener callback for channel listener %p " - "(global ID " U64_FORMAT ") to %p", - chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + "(global ID %"PRIu64 ") to %p", + chan_l, (chan_l->global_identifier), listener); chan_l->listener = listener; @@ -1137,9 +1140,9 @@ channel_mark_for_close(channel_t *chan) return; log_debug(LD_CHANNEL, - "Closing channel %p (global ID " U64_FORMAT ") " + "Closing channel %p (global ID %"PRIu64 ") " "by request", - chan, U64_PRINTF_ARG(chan->global_identifier)); + chan, (chan->global_identifier)); /* Note closing by request from above */ chan->reason_for_closing = CHANNEL_CLOSE_REQUESTED; @@ -1177,9 +1180,9 @@ channel_listener_mark_for_close(channel_listener_t *chan_l) chan_l->state == CHANNEL_LISTENER_STATE_ERROR) return; log_debug(LD_CHANNEL, - "Closing channel listener %p (global ID " U64_FORMAT ") " + "Closing channel listener %p (global ID %"PRIu64 ") " "by request", - chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + chan_l, (chan_l->global_identifier)); /* Note closing by request from above */ chan_l->reason_for_closing = CHANNEL_LISTENER_CLOSE_REQUESTED; @@ -1215,9 +1218,9 @@ channel_close_from_lower_layer(channel_t *chan) return; log_debug(LD_CHANNEL, - "Closing channel %p (global ID " U64_FORMAT ") " + "Closing channel %p (global ID %"PRIu64 ") " "due to lower-layer event", - chan, U64_PRINTF_ARG(chan->global_identifier)); + chan, (chan->global_identifier)); /* Note closing by event from below */ chan->reason_for_closing = CHANNEL_CLOSE_FROM_BELOW; @@ -1300,8 +1303,8 @@ channel_clear_identity_digest(channel_t *chan) log_debug(LD_CHANNEL, "Clearing remote endpoint digest on channel %p with " - "global ID " U64_FORMAT, - chan, U64_PRINTF_ARG(chan->global_identifier)); + "global ID %"PRIu64, + chan, (chan->global_identifier)); state_not_in_map = CHANNEL_CONDEMNED(chan); @@ -1331,8 +1334,8 @@ channel_set_identity_digest(channel_t *chan, log_debug(LD_CHANNEL, "Setting remote endpoint digest on channel %p with " - "global ID " U64_FORMAT " to digest %s", - chan, U64_PRINTF_ARG(chan->global_identifier), + "global ID %"PRIu64 " to digest %s", + chan, (chan->global_identifier), identity_digest ? hex_str(identity_digest, DIGEST_LEN) : "(null)"); @@ -1388,8 +1391,8 @@ channel_clear_remote_end(channel_t *chan) log_debug(LD_CHANNEL, "Clearing remote endpoint identity on channel %p with " - "global ID " U64_FORMAT, - chan, U64_PRINTF_ARG(chan->global_identifier)); + "global ID %"PRIu64, + chan, (chan->global_identifier)); state_not_in_map = CHANNEL_CONDEMNED(chan); @@ -1472,13 +1475,13 @@ channel_write_packed_cell(channel_t *chan, packed_cell_t *cell) if (CHANNEL_IS_CLOSING(chan)) { log_debug(LD_CHANNEL, "Discarding %p on closing channel %p with " - "global ID "U64_FORMAT, cell, chan, - U64_PRINTF_ARG(chan->global_identifier)); + "global ID %"PRIu64, cell, chan, + (chan->global_identifier)); goto end; } log_debug(LD_CHANNEL, "Writing %p to channel %p with global ID " - U64_FORMAT, cell, chan, U64_PRINTF_ARG(chan->global_identifier)); + "%"PRIu64, cell, chan, (chan->global_identifier)); ret = write_packed_cell(chan, cell); @@ -1515,9 +1518,9 @@ channel_change_state_(channel_t *chan, channel_state_t to_state) if (from_state == to_state) { log_debug(LD_CHANNEL, "Got no-op transition from \"%s\" to itself on channel %p" - "(global ID " U64_FORMAT ")", + "(global ID %"PRIu64 ")", channel_state_to_string(to_state), - chan, U64_PRINTF_ARG(chan->global_identifier)); + chan, (chan->global_identifier)); return; } @@ -1529,10 +1532,10 @@ channel_change_state_(channel_t *chan, channel_state_t to_state) } log_debug(LD_CHANNEL, - "Changing state of channel %p (global ID " U64_FORMAT + "Changing state of channel %p (global ID %"PRIu64 ") from \"%s\" to \"%s\"", chan, - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), channel_state_to_string(chan->state), channel_state_to_string(to_state)); @@ -1635,9 +1638,9 @@ channel_listener_change_state(channel_listener_t *chan_l, if (from_state == to_state) { log_debug(LD_CHANNEL, "Got no-op transition from \"%s\" to itself on channel " - "listener %p (global ID " U64_FORMAT ")", + "listener %p (global ID %"PRIu64 ")", channel_listener_state_to_string(to_state), - chan_l, U64_PRINTF_ARG(chan_l->global_identifier)); + chan_l, (chan_l->global_identifier)); return; } @@ -1649,9 +1652,9 @@ channel_listener_change_state(channel_listener_t *chan_l, } log_debug(LD_CHANNEL, - "Changing state of channel listener %p (global ID " U64_FORMAT + "Changing state of channel listener %p (global ID %"PRIu64 "from \"%s\" to \"%s\"", - chan_l, U64_PRINTF_ARG(chan_l->global_identifier), + chan_l, (chan_l->global_identifier), channel_listener_state_to_string(chan_l->state), channel_listener_state_to_string(to_state)); @@ -1800,8 +1803,8 @@ channel_listener_process_incoming(channel_listener_t *listener) log_debug(LD_CHANNEL, "Processing queue of incoming connections for channel " - "listener %p (global ID " U64_FORMAT ")", - listener, U64_PRINTF_ARG(listener->global_identifier)); + "listener %p (global ID %"PRIu64 ")", + listener, (listener->global_identifier)); if (!(listener->incoming_list)) return; @@ -1810,12 +1813,12 @@ channel_listener_process_incoming(channel_listener_t *listener) tor_assert(chan); log_debug(LD_CHANNEL, - "Handling incoming channel %p (" U64_FORMAT ") " - "for listener %p (" U64_FORMAT ")", + "Handling incoming channel %p (%"PRIu64 ") " + "for listener %p (%"PRIu64 ")", chan, - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), listener, - U64_PRINTF_ARG(listener->global_identifier)); + (listener->global_identifier)); /* Make sure this is set correctly */ channel_mark_incoming(chan); listener->listener(listener, chan); @@ -1921,10 +1924,10 @@ channel_listener_queue_incoming(channel_listener_t *listener, tor_assert(incoming); log_debug(LD_CHANNEL, - "Queueing incoming channel %p (global ID " U64_FORMAT ") on " - "channel listener %p (global ID " U64_FORMAT ")", - incoming, U64_PRINTF_ARG(incoming->global_identifier), - listener, U64_PRINTF_ARG(listener->global_identifier)); + "Queueing incoming channel %p (global ID %"PRIu64 ") on " + "channel listener %p (global ID %"PRIu64 ")", + incoming, (incoming->global_identifier), + listener, (listener->global_identifier)); /* Do we need to queue it, or can we just call the listener right away? */ if (!(listener->listener)) need_to_queue = 1; @@ -1981,8 +1984,8 @@ channel_process_cell(channel_t *chan, cell_t *cell) log_debug(LD_CHANNEL, "Processing incoming cell_t %p for channel %p (global ID " - U64_FORMAT ")", cell, chan, - U64_PRINTF_ARG(chan->global_identifier)); + "%"PRIu64 ")", cell, chan, + (chan->global_identifier)); chan->cell_handler(chan, cell); } @@ -2022,8 +2025,8 @@ channel_send_destroy(circid_t circ_id, channel_t *chan, int reason) tor_assert(chan); if (circ_id == 0) { log_warn(LD_BUG, "Attempted to send a destroy cell for circID 0 " - "on a channel " U64_FORMAT " at %p in state %s (%d)", - U64_PRINTF_ARG(chan->global_identifier), + "on a channel %"PRIu64 " at %p in state %s (%d)", + (chan->global_identifier), chan, channel_state_to_string(chan->state), chan->state); return 0; @@ -2035,14 +2038,14 @@ channel_send_destroy(circid_t circ_id, channel_t *chan, int reason) circuitmux_append_destroy_cell(chan, chan->cmux, circ_id, reason); log_debug(LD_OR, "Sending destroy (circID %u) on channel %p " - "(global ID " U64_FORMAT ")", + "(global ID %"PRIu64 ")", (unsigned)circ_id, chan, - U64_PRINTF_ARG(chan->global_identifier)); + (chan->global_identifier)); } else { log_warn(LD_BUG, "Someone called channel_send_destroy() for circID %u " - "on a channel " U64_FORMAT " at %p in state %s (%d)", - (unsigned)circ_id, U64_PRINTF_ARG(chan->global_identifier), + "on a channel %"PRIu64 " at %p in state %s (%d)", + (unsigned)circ_id, (chan->global_identifier), chan, channel_state_to_string(chan->state), chan->state); } @@ -2176,9 +2179,9 @@ channel_free_list(smartlist_t *channels, int mark_for_close) /* Deregister and free it */ tor_assert(curr); log_debug(LD_CHANNEL, - "Cleaning up channel %p (global ID " U64_FORMAT ") " + "Cleaning up channel %p (global ID %"PRIu64 ") " "in state %s (%d)", - curr, U64_PRINTF_ARG(curr->global_identifier), + curr, (curr->global_identifier), channel_state_to_string(curr->state), curr->state); /* Detach circuits early so they can find the channel */ if (curr->cmux) { @@ -2207,9 +2210,9 @@ channel_listener_free_list(smartlist_t *listeners, int mark_for_close) /* Deregister and free it */ tor_assert(curr); log_debug(LD_CHANNEL, - "Cleaning up channel listener %p (global ID " U64_FORMAT ") " + "Cleaning up channel listener %p (global ID %"PRIu64 ") " "in state %s (%d)", - curr, U64_PRINTF_ARG(curr->global_identifier), + curr, (curr->global_identifier), channel_listener_state_to_string(curr->state), curr->state); channel_listener_unregister(curr); if (mark_for_close) { @@ -2532,33 +2535,33 @@ channel_dump_statistics, (channel_t *chan, int severity)) age = (double)(now - chan->timestamp_created); tor_log(severity, LD_GENERAL, - "Channel " U64_FORMAT " (at %p) with transport %s is in state " + "Channel %"PRIu64 " (at %p) with transport %s is in state " "%s (%d)", - U64_PRINTF_ARG(chan->global_identifier), chan, + (chan->global_identifier), chan, channel_describe_transport(chan), channel_state_to_string(chan->state), chan->state); tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " was created at " U64_FORMAT - " (" U64_FORMAT " seconds ago) " - "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->timestamp_created), - U64_PRINTF_ARG(now - chan->timestamp_created), - U64_PRINTF_ARG(chan->timestamp_active), - U64_PRINTF_ARG(now - chan->timestamp_active)); + " * Channel %"PRIu64 " was created at %"PRIu64 + " (%"PRIu64 " seconds ago) " + "and last active at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan->global_identifier), + (uint64_t)(chan->timestamp_created), + (uint64_t)(now - chan->timestamp_created), + (uint64_t)(chan->timestamp_active), + (uint64_t)(now - chan->timestamp_active)); /* Handle digest. */ if (!tor_digest_is_zero(chan->identity_digest)) { tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " says it is connected " + " * Channel %"PRIu64 " says it is connected " "to an OR with digest %s", - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), hex_str(chan->identity_digest, DIGEST_LEN)); } else { tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " does not know the digest" + " * Channel %"PRIu64 " does not know the digest" " of the OR it is connected to", - U64_PRINTF_ARG(chan->global_identifier)); + (chan->global_identifier)); } /* Handle remote address and descriptions */ @@ -2567,10 +2570,10 @@ channel_dump_statistics, (channel_t *chan, int severity)) char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); remote_addr_str = tor_addr_to_str_dup(&remote_addr); tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " says its remote address" + " * Channel %"PRIu64 " says its remote address" " is %s, and gives a canonical description of \"%s\" and an " "actual description of \"%s\"", - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), safe_str(remote_addr_str), safe_str(channel_get_canonical_remote_descr(chan)), safe_str(actual)); @@ -2579,10 +2582,10 @@ channel_dump_statistics, (channel_t *chan, int severity)) } else { char *actual = tor_strdup(channel_get_actual_remote_descr(chan)); tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " does not know its remote " + " * Channel %"PRIu64 " does not know its remote " "address, but gives a canonical description of \"%s\" and an " "actual description of \"%s\"", - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), channel_get_canonical_remote_descr(chan), actual); tor_free(actual); @@ -2590,9 +2593,9 @@ channel_dump_statistics, (channel_t *chan, int severity)) /* Handle marks */ tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has these marks: %s %s %s " + " * Channel %"PRIu64 " has these marks: %s %s %s " "%s %s %s", - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), channel_is_bad_for_new_circs(chan) ? "bad_for_new_circs" : "!bad_for_new_circs", channel_is_canonical(chan) ? @@ -2609,9 +2612,9 @@ channel_dump_statistics, (channel_t *chan, int severity)) /* Describe circuits */ tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has %d active circuits out of" + " * Channel %"PRIu64 " has %d active circuits out of" " %d in total", - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), (chan->cmux != NULL) ? circuitmux_num_active_circuits(chan->cmux) : 0, (chan->cmux != NULL) ? @@ -2619,78 +2622,78 @@ channel_dump_statistics, (channel_t *chan, int severity)) /* Describe timestamps */ tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " was last used by a " - "client at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->timestamp_client), - U64_PRINTF_ARG(now - chan->timestamp_client)); + " * Channel %"PRIu64 " was last used by a " + "client at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan->global_identifier), + (uint64_t)(chan->timestamp_client), + (uint64_t)(now - chan->timestamp_client)); tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " last received a cell " - "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->timestamp_recv), - U64_PRINTF_ARG(now - chan->timestamp_recv)); + " * Channel %"PRIu64 " last received a cell " + "at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan->global_identifier), + (uint64_t)(chan->timestamp_recv), + (uint64_t)(now - chan->timestamp_recv)); tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " last transmitted a cell " - "at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->timestamp_xmit), - U64_PRINTF_ARG(now - chan->timestamp_xmit)); + " * Channel %"PRIu64 " last transmitted a cell " + "at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan->global_identifier), + (uint64_t)(chan->timestamp_xmit), + (uint64_t)(now - chan->timestamp_xmit)); /* Describe counters and rates */ tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has received " - U64_FORMAT " bytes in " U64_FORMAT " cells and transmitted " - U64_FORMAT " bytes in " U64_FORMAT " cells", - U64_PRINTF_ARG(chan->global_identifier), - U64_PRINTF_ARG(chan->n_bytes_recved), - U64_PRINTF_ARG(chan->n_cells_recved), - U64_PRINTF_ARG(chan->n_bytes_xmitted), - U64_PRINTF_ARG(chan->n_cells_xmitted)); + " * Channel %"PRIu64 " has received " + "%"PRIu64 " bytes in %"PRIu64 " cells and transmitted " + "%"PRIu64 " bytes in %"PRIu64 " cells", + (chan->global_identifier), + (chan->n_bytes_recved), + (chan->n_cells_recved), + (chan->n_bytes_xmitted), + (chan->n_cells_xmitted)); if (now > chan->timestamp_created && chan->timestamp_created > 0) { if (chan->n_bytes_recved > 0) { avg = (double)(chan->n_bytes_recved) / age; tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has averaged %f " + " * Channel %"PRIu64 " has averaged %f " "bytes received per second", - U64_PRINTF_ARG(chan->global_identifier), avg); + (chan->global_identifier), avg); } if (chan->n_cells_recved > 0) { avg = (double)(chan->n_cells_recved) / age; if (avg >= 1.0) { tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has averaged %f " + " * Channel %"PRIu64 " has averaged %f " "cells received per second", - U64_PRINTF_ARG(chan->global_identifier), avg); + (chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has averaged %f " + " * Channel %"PRIu64 " has averaged %f " "seconds between received cells", - U64_PRINTF_ARG(chan->global_identifier), interval); + (chan->global_identifier), interval); } } if (chan->n_bytes_xmitted > 0) { avg = (double)(chan->n_bytes_xmitted) / age; tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has averaged %f " + " * Channel %"PRIu64 " has averaged %f " "bytes transmitted per second", - U64_PRINTF_ARG(chan->global_identifier), avg); + (chan->global_identifier), avg); } if (chan->n_cells_xmitted > 0) { avg = (double)(chan->n_cells_xmitted) / age; if (avg >= 1.0) { tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has averaged %f " + " * Channel %"PRIu64 " has averaged %f " "cells transmitted per second", - U64_PRINTF_ARG(chan->global_identifier), avg); + (chan->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; tor_log(severity, LD_GENERAL, - " * Channel " U64_FORMAT " has averaged %f " + " * Channel %"PRIu64 " has averaged %f " "seconds between transmitted cells", - U64_PRINTF_ARG(chan->global_identifier), interval); + (chan->global_identifier), interval); } } } @@ -2715,29 +2718,29 @@ channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) age = (double)(now - chan_l->timestamp_created); tor_log(severity, LD_GENERAL, - "Channel listener " U64_FORMAT " (at %p) with transport %s is in " + "Channel listener %"PRIu64 " (at %p) with transport %s is in " "state %s (%d)", - U64_PRINTF_ARG(chan_l->global_identifier), chan_l, + (chan_l->global_identifier), chan_l, channel_listener_describe_transport(chan_l), channel_listener_state_to_string(chan_l->state), chan_l->state); tor_log(severity, LD_GENERAL, - " * Channel listener " U64_FORMAT " was created at " U64_FORMAT - " (" U64_FORMAT " seconds ago) " - "and last active at " U64_FORMAT " (" U64_FORMAT " seconds ago)", - U64_PRINTF_ARG(chan_l->global_identifier), - U64_PRINTF_ARG(chan_l->timestamp_created), - U64_PRINTF_ARG(now - chan_l->timestamp_created), - U64_PRINTF_ARG(chan_l->timestamp_active), - U64_PRINTF_ARG(now - chan_l->timestamp_active)); + " * Channel listener %"PRIu64 " was created at %"PRIu64 + " (%"PRIu64 " seconds ago) " + "and last active at %"PRIu64 " (%"PRIu64 " seconds ago)", + (chan_l->global_identifier), + (uint64_t)(chan_l->timestamp_created), + (uint64_t)(now - chan_l->timestamp_created), + (uint64_t)(chan_l->timestamp_active), + (uint64_t)(now - chan_l->timestamp_active)); tor_log(severity, LD_GENERAL, - " * Channel listener " U64_FORMAT " last accepted an incoming " - "channel at " U64_FORMAT " (" U64_FORMAT " seconds ago) " - "and has accepted " U64_FORMAT " channels in total", - U64_PRINTF_ARG(chan_l->global_identifier), - U64_PRINTF_ARG(chan_l->timestamp_accepted), - U64_PRINTF_ARG(now - chan_l->timestamp_accepted), - U64_PRINTF_ARG(chan_l->n_accepted)); + " * Channel listener %"PRIu64 " last accepted an incoming " + "channel at %"PRIu64 " (%"PRIu64 " seconds ago) " + "and has accepted %"PRIu64 " channels in total", + (chan_l->global_identifier), + (uint64_t)(chan_l->timestamp_accepted), + (uint64_t)(now - chan_l->timestamp_accepted), + (uint64_t)(chan_l->n_accepted)); /* * If it's sensible to do so, get the rate of incoming channels on this @@ -2749,15 +2752,15 @@ channel_listener_dump_statistics(channel_listener_t *chan_l, int severity) avg = (double)(chan_l->n_accepted) / age; if (avg >= 1.0) { tor_log(severity, LD_GENERAL, - " * Channel listener " U64_FORMAT " has averaged %f incoming " + " * Channel listener %"PRIu64 " has averaged %f incoming " "channels per second", - U64_PRINTF_ARG(chan_l->global_identifier), avg); + (chan_l->global_identifier), avg); } else if (avg >= 0.0) { interval = 1.0 / avg; tor_log(severity, LD_GENERAL, - " * Channel listener " U64_FORMAT " has averaged %f seconds " + " * Channel listener %"PRIu64 " has averaged %f seconds " "between incoming channels", - U64_PRINTF_ARG(chan_l->global_identifier), interval); + (chan_l->global_identifier), interval); } } @@ -3475,4 +3478,3 @@ channel_update_bad_for_new_circs(const char *digest, int force) channel_rsa_id_group_set_badness(&(*iter)->channel_list, force); } } - diff --git a/src/or/channel.h b/src/core/or/channel.h index 6cf8cd7f72..b3d97a9add 100644 --- a/src/or/channel.h +++ b/src/core/or/channel.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,15 @@ #ifndef TOR_CHANNEL_H #define TOR_CHANNEL_H -#include "or.h" -#include "circuitmux.h" -#include "timers.h" -#include "handles.h" +#include "core/or/or.h" +#include "core/or/circuitmux.h" +#include "lib/container/handles.h" +#include "lib/crypt_ops/crypto_ed25519.h" + +#include "tor_queue.h" + +#define tor_timer_t timeout +struct tor_timer_t; /* Channel handler function pointer typedefs */ typedef void (*channel_listener_fn_ptr)(channel_listener_t *, channel_t *); @@ -30,6 +35,141 @@ typedef enum { CHANNEL_USED_FOR_USER_TRAFFIC, } channel_usage_info_t; +/** Possible rules for generating circuit IDs on an OR connection. */ +typedef enum { + CIRC_ID_TYPE_LOWER=0, /**< Pick from 0..1<<15-1. */ + CIRC_ID_TYPE_HIGHER=1, /**< Pick from 1<<15..1<<16-1. */ + /** The other side of a connection is an OP: never create circuits to it, + * and let it use any circuit ID it wants. */ + CIRC_ID_TYPE_NEITHER=2 +} circ_id_type_t; +#define circ_id_type_bitfield_t ENUM_BF(circ_id_type_t) + +/* channel states for channel_t */ + +typedef enum { + /* + * Closed state - channel is inactive + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSING + * Permitted transitions to: + * - CHANNEL_STATE_OPENING + */ + CHANNEL_STATE_CLOSED = 0, + /* + * Opening state - channel is trying to connect + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSED + * Permitted transitions to: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_ERROR + * - CHANNEL_STATE_OPEN + */ + CHANNEL_STATE_OPENING, + /* + * Open state - channel is active and ready for use + * + * Permitted transitions from: + * - CHANNEL_STATE_MAINT + * - CHANNEL_STATE_OPENING + * Permitted transitions to: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_ERROR + * - CHANNEL_STATE_MAINT + */ + CHANNEL_STATE_OPEN, + /* + * Maintenance state - channel is temporarily offline for subclass specific + * maintenance activities such as TLS renegotiation. + * + * Permitted transitions from: + * - CHANNEL_STATE_OPEN + * Permitted transitions to: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_ERROR + * - CHANNEL_STATE_OPEN + */ + CHANNEL_STATE_MAINT, + /* + * Closing state - channel is shutting down + * + * Permitted transitions from: + * - CHANNEL_STATE_MAINT + * - CHANNEL_STATE_OPEN + * Permitted transitions to: + * - CHANNEL_STATE_CLOSED, + * - CHANNEL_STATE_ERROR + */ + CHANNEL_STATE_CLOSING, + /* + * Error state - channel has experienced a permanent error + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_MAINT + * - CHANNEL_STATE_OPENING + * - CHANNEL_STATE_OPEN + * Permitted transitions to: + * - None + */ + CHANNEL_STATE_ERROR, + /* + * Placeholder for maximum state value + */ + CHANNEL_STATE_LAST +} channel_state_t; + +/* channel listener states for channel_listener_t */ + +typedef enum { + /* + * Closed state - channel listener is inactive + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_CLOSING + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_LISTENING + */ + CHANNEL_LISTENER_STATE_CLOSED = 0, + /* + * Listening state - channel listener is listening for incoming + * connections + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_CLOSED + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_CLOSING + * - CHANNEL_LISTENER_STATE_ERROR + */ + CHANNEL_LISTENER_STATE_LISTENING, + /* + * Closing state - channel listener is shutting down + * + * Permitted transitions from: + * - CHANNEL_LISTENER_STATE_LISTENING + * Permitted transitions to: + * - CHANNEL_LISTENER_STATE_CLOSED, + * - CHANNEL_LISTENER_STATE_ERROR + */ + CHANNEL_LISTENER_STATE_CLOSING, + /* + * Error state - channel listener has experienced a permanent error + * + * Permitted transitions from: + * - CHANNEL_STATE_CLOSING + * - CHANNEL_STATE_LISTENING + * Permitted transitions to: + * - None + */ + CHANNEL_LISTENER_STATE_ERROR, + /* + * Placeholder for maximum state value + */ + CHANNEL_LISTENER_STATE_LAST +} channel_listener_state_t; + /** * Channel struct; see the channel_t typedef in or.h. A channel is an * abstract interface for the OR-to-OR connection, similar to connection_or_t, @@ -92,7 +232,7 @@ struct channel_s { monotime_coarse_t next_padding_time; /** The callback pointer for the padding callbacks */ - tor_timer_t *padding_timer; + struct tor_timer_t *padding_timer; /** The handle to this channel (to free on canceled timers) */ struct channel_handle_t *timer_handle; @@ -251,7 +391,7 @@ struct channel_s { * necessarily its true identity. Don't believe this identity unless * authentication has happened. */ - ed25519_public_key_t ed25519_identity; + struct ed25519_public_key_t ed25519_identity; /** * Linked list of channels with the same RSA identity digest, for use with @@ -470,8 +610,8 @@ void channel_mark_incoming(channel_t *chan); void channel_mark_outgoing(channel_t *chan); void channel_mark_remote(channel_t *chan); void channel_set_identity_digest(channel_t *chan, - const char *identity_digest, - const ed25519_public_key_t *ed_identity); + const char *identity_digest, + const struct ed25519_public_key_t *ed_identity); void channel_listener_change_state(channel_listener_t *chan_l, channel_listener_state_t to_state); @@ -521,10 +661,10 @@ int channel_send_destroy(circid_t circ_id, channel_t *chan, channel_t * channel_connect(const tor_addr_t *addr, uint16_t port, const char *rsa_id_digest, - const ed25519_public_key_t *ed_id); + const struct ed25519_public_key_t *ed_id); channel_t * channel_get_for_extend(const char *rsa_id_digest, - const ed25519_public_key_t *ed_id, + const struct ed25519_public_key_t *ed_id, const tor_addr_t *target_addr, const char **msg_out, int *launch_out); @@ -537,7 +677,7 @@ int channel_is_better(channel_t *a, channel_t *b); channel_t * channel_find_by_global_id(uint64_t global_identifier); channel_t * channel_find_by_remote_identity(const char *rsa_id_digest, - const ed25519_public_key_t *ed_id); + const struct ed25519_public_key_t *ed_id); /** For things returned by channel_find_by_remote_digest(), walk the list. * The RSA key will match for all returned elements; the Ed25519 key might not. @@ -635,6 +775,6 @@ int packed_cell_is_destroy(channel_t *chan, HANDLE_DECL(channel, channel_s,) #define channel_handle_free(h) \ FREE_AND_NULL(channel_handle_t, channel_handle_free_, (h)) +#undef tor_timer_t #endif /* !defined(TOR_CHANNEL_H) */ - diff --git a/src/or/channelpadding.c b/src/core/or/channelpadding.c index a8b9a2b47b..b8cfd33d50 100644 --- a/src/or/channelpadding.c +++ b/src/core/or/channelpadding.c @@ -1,27 +1,31 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2015, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* TOR_CHANNEL_INTERNAL_ define needed for an O(1) implementation of * channelpadding_channel_to_channelinfo() */ #define TOR_CHANNEL_INTERNAL_ -#include "or.h" -#include "channel.h" -#include "channelpadding.h" -#include "channeltls.h" -#include "config.h" -#include "networkstatus.h" -#include "connection.h" -#include "connection_or.h" -#include "crypto_rand.h" -#include "main.h" -#include "rephist.h" -#include "router.h" -#include "compat_time.h" -#include "rendservice.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/channelpadding.h" +#include "core/or/channeltls.h" +#include "app/config/config.h" +#include "feature/nodelist/networkstatus.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/mainloop/main.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "lib/time/compat_time.h" +#include "feature/rend/rendservice.h" +#include "lib/evloop/timers.h" + +#include "core/or/cell_st.h" +#include "core/or/or_connection_st.h" STATIC int32_t channelpadding_get_netflow_inactive_timeout_ms( const channel_t *); @@ -279,10 +283,10 @@ channelpadding_update_padding_for_channel(channel_t *chan, pad_vars->ito_high_ms); log_fn(LOG_INFO,LD_OR, - "Negotiated padding=%d, lo=%d, hi=%d on "U64_FORMAT, + "Negotiated padding=%d, lo=%d, hi=%d on %"PRIu64, chan->padding_enabled, chan->padding_timeout_low_ms, chan->padding_timeout_high_ms, - U64_PRINTF_ARG(chan->global_identifier)); + (chan->global_identifier)); return 1; } @@ -390,13 +394,13 @@ channelpadding_send_padding_cell_for_callback(channel_t *chan) monotime_coarse_get(&now); log_fn(LOG_INFO,LD_OR, - "Sending netflow keepalive on "U64_FORMAT" to %s (%s) after " - I64_FORMAT" ms. Delta "I64_FORMAT"ms", - U64_PRINTF_ARG(chan->global_identifier), + "Sending netflow keepalive on %"PRIu64" to %s (%s) after " + "%"PRId64" ms. Delta %"PRId64"ms", + (chan->global_identifier), safe_str_client(chan->get_remote_descr(chan, 0)), safe_str_client(hex_str(chan->identity_digest, DIGEST_LEN)), - I64_PRINTF_ARG(monotime_coarse_diff_msec(&chan->timestamp_xfer,&now)), - I64_PRINTF_ARG( + (monotime_coarse_diff_msec(&chan->timestamp_xfer,&now)), + ( monotime_coarse_diff_msec(&chan->next_padding_time,&now))); } @@ -536,9 +540,9 @@ channelpadding_compute_time_until_pad_for_netflow(channel_t *chan) if (ms_till_pad > DFLT_NETFLOW_INACTIVE_KEEPALIVE_MAX) { tor_fragile_assert(); log_warn(LD_BUG, - "Channel padding timeout scheduled "I64_FORMAT"ms in the future. " + "Channel padding timeout scheduled %"PRId64"ms in the future. " "Did the monotonic clock just jump?", - I64_PRINTF_ARG(ms_till_pad)); + (ms_till_pad)); return 0; /* Clock jumped: Send padding now */ } @@ -562,8 +566,8 @@ channelpadding_compute_time_until_pad_for_netflow(channel_t *chan) int severity = (ms_till_pad < -NETFLOW_MISSED_WINDOW) ? LOG_NOTICE : LOG_INFO; log_fn(severity, LD_OR, - "Channel padding timeout scheduled "I64_FORMAT"ms in the past. ", - I64_PRINTF_ARG(-ms_till_pad)); + "Channel padding timeout scheduled %"PRId64"ms in the past. ", + (-ms_till_pad)); return 0; /* Clock jumped: Send padding now */ } @@ -694,8 +698,8 @@ channelpadding_reduce_padding_on_channel(channel_t *chan) chan->padding_timeout_high_ms = consensus_nf_ito_high_reduced; log_fn(LOG_INFO,LD_OR, - "Reduced padding on channel "U64_FORMAT": lo=%d, hi=%d", - U64_PRINTF_ARG(chan->global_identifier), + "Reduced padding on channel %"PRIu64": lo=%d, hi=%d", + (chan->global_identifier), chan->padding_timeout_low_ms, chan->padding_timeout_high_ms); } @@ -794,4 +798,3 @@ channelpadding_decide_to_pad_channel(channel_t *chan) return CHANNELPADDING_PADLATER; } } - diff --git a/src/or/channelpadding.h b/src/core/or/channelpadding.h index 58bf741d5c..7eddbdbe2d 100644 --- a/src/or/channelpadding.h +++ b/src/core/or/channelpadding.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2015, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,7 @@ #ifndef TOR_CHANNELPADDING_H #define TOR_CHANNELPADDING_H -#include "channelpadding_negotiation.h" +#include "trunnel/channelpadding_negotiation.h" #define CHANNELPADDING_TOR2WEB_PARAM "nf_pad_tor2web" #define CHANNELPADDING_TOR2WEB_DEFAULT 1 diff --git a/src/or/channeltls.c b/src/core/or/channeltls.c index 54d94f6109..87f5a02b75 100644 --- a/src/or/channeltls.c +++ b/src/core/or/channeltls.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,27 +38,38 @@ #define CHANNELTLS_PRIVATE -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "command.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "control.h" -#include "entrynodes.h" -#include "link_handshake.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "scheduler.h" -#include "torcert.h" -#include "networkstatus.h" -#include "channelpadding_negotiation.h" -#include "channelpadding.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/circuitmux.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/command.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "feature/client/entrynodes.h" +#include "trunnel/link_handshake.h" +#include "core/or/relay.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "core/or/scheduler.h" +#include "feature/nodelist/torcert.h" +#include "feature/nodelist/networkstatus.h" +#include "trunnel/channelpadding_negotiation.h" +#include "core/or/channelpadding.h" + +#include "core/or/cell_st.h" +#include "core/or/cell_queue_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/or_handshake_certs_st.h" +#include "core/or/or_handshake_state_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "core/or/var_cell_st.h" + +#include "lib/tls/tortls.h" /** How many CELL_PADDING cells have we received, ever? */ uint64_t stats_n_padding_cells_processed = 0; @@ -183,19 +194,19 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, log_debug(LD_CHANNEL, "In channel_tls_connect() for channel %p " - "(global id " U64_FORMAT ")", + "(global id %"PRIu64 ")", tlschan, - U64_PRINTF_ARG(chan->global_identifier)); + (chan->global_identifier)); if (is_local_addr(addr)) { log_debug(LD_CHANNEL, - "Marking new outgoing channel " U64_FORMAT " at %p as local", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Marking new outgoing channel %"PRIu64 " at %p as local", + (chan->global_identifier), chan); channel_mark_local(chan); } else { log_debug(LD_CHANNEL, - "Marking new outgoing channel " U64_FORMAT " at %p as remote", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Marking new outgoing channel %"PRIu64 " at %p as remote", + (chan->global_identifier), chan); channel_mark_remote(chan); } @@ -211,8 +222,8 @@ channel_tls_connect(const tor_addr_t *addr, uint16_t port, } log_debug(LD_CHANNEL, - "Got orconn %p for channel with global id " U64_FORMAT, - tlschan->conn, U64_PRINTF_ARG(chan->global_identifier)); + "Got orconn %p for channel with global id %"PRIu64, + tlschan->conn, (chan->global_identifier)); goto done; @@ -262,8 +273,8 @@ channel_tls_start_listener(void) channel_tls_listener = listener; log_debug(LD_CHANNEL, - "Starting TLS channel listener %p with global id " U64_FORMAT, - listener, U64_PRINTF_ARG(listener->global_identifier)); + "Starting TLS channel listener %p with global id %"PRIu64, + listener, (listener->global_identifier)); channel_listener_register(listener); } else listener = channel_tls_listener; @@ -292,9 +303,9 @@ channel_tls_free_all(void) */ old_listener = channel_tls_listener; log_debug(LD_CHANNEL, - "Closing channel_tls_listener with ID " U64_FORMAT + "Closing channel_tls_listener with ID %"PRIu64 " at %p.", - U64_PRINTF_ARG(old_listener->global_identifier), + (old_listener->global_identifier), old_listener); channel_listener_unregister(old_listener); channel_listener_mark_for_close(old_listener); @@ -326,13 +337,13 @@ channel_tls_handle_incoming(or_connection_t *orconn) if (is_local_addr(&(TO_CONN(orconn)->addr))) { log_debug(LD_CHANNEL, - "Marking new incoming channel " U64_FORMAT " at %p as local", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Marking new incoming channel %"PRIu64 " at %p as local", + (chan->global_identifier), chan); channel_mark_local(chan); } else { log_debug(LD_CHANNEL, - "Marking new incoming channel " U64_FORMAT " at %p as remote", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Marking new incoming channel %"PRIu64 " at %p as remote", + (chan->global_identifier), chan); channel_mark_remote(chan); } @@ -422,8 +433,8 @@ channel_tls_describe_transport_method(channel_t *chan) if (buf) tor_free(buf); tor_asprintf(&buf, - "TLS channel (connection " U64_FORMAT ")", - U64_PRINTF_ARG(id)); + "TLS channel (connection %"PRIu64 ")", + (id)); rv = buf; } else { @@ -484,8 +495,8 @@ channel_tls_get_overhead_estimate_method(channel_t *chan) } log_debug(LD_CHANNEL, - "Estimated overhead ratio for TLS chan " U64_FORMAT " is %f", - U64_PRINTF_ARG(chan->global_identifier), overhead); + "Estimated overhead ratio for TLS chan %"PRIu64 " is %f", + (chan->global_identifier), overhead); return overhead; } @@ -616,8 +627,8 @@ channel_tls_has_queued_writes_method(channel_t *chan) if (!(tlschan->conn)) { log_info(LD_CHANNEL, "something called has_queued_writes on a tlschan " - "(%p with ID " U64_FORMAT " but no conn", - chan, U64_PRINTF_ARG(chan->global_identifier)); + "(%p with ID %"PRIu64 " but no conn", + chan, (chan->global_identifier)); } outbuf_len = (tlschan->conn != NULL) ? @@ -684,8 +695,8 @@ channel_tls_matches_extend_info_method(channel_t *chan, if (!(tlschan->conn)) { log_info(LD_CHANNEL, "something called matches_extend_info on a tlschan " - "(%p with ID " U64_FORMAT " but no conn", - chan, U64_PRINTF_ARG(chan->global_identifier)); + "(%p with ID %"PRIu64 " but no conn", + chan, (chan->global_identifier)); return 0; } @@ -714,8 +725,8 @@ channel_tls_matches_target_method(channel_t *chan, if (!(tlschan->conn)) { log_info(LD_CHANNEL, "something called matches_target on a tlschan " - "(%p with ID " U64_FORMAT " but no conn", - chan, U64_PRINTF_ARG(chan->global_identifier)); + "(%p with ID %"PRIu64 " but no conn", + chan, (chan->global_identifier)); return 0; } @@ -797,8 +808,8 @@ channel_tls_write_cell_method(channel_t *chan, cell_t *cell) } else { log_info(LD_CHANNEL, "something called write_cell on a tlschan " - "(%p with ID " U64_FORMAT " but no conn", - chan, U64_PRINTF_ARG(chan->global_identifier)); + "(%p with ID %"PRIu64 " but no conn", + chan, (chan->global_identifier)); } return written; @@ -830,8 +841,8 @@ channel_tls_write_packed_cell_method(channel_t *chan, } else { log_info(LD_CHANNEL, "something called write_packed_cell on a tlschan " - "(%p with ID " U64_FORMAT " but no conn", - chan, U64_PRINTF_ARG(chan->global_identifier)); + "(%p with ID %"PRIu64 " but no conn", + chan, (chan->global_identifier)); return -1; } @@ -859,8 +870,8 @@ channel_tls_write_var_cell_method(channel_t *chan, var_cell_t *var_cell) } else { log_info(LD_CHANNEL, "something called write_var_cell on a tlschan " - "(%p with ID " U64_FORMAT " but no conn", - chan, U64_PRINTF_ARG(chan->global_identifier)); + "(%p with ID %"PRIu64 " but no conn", + chan, (chan->global_identifier)); } return written; @@ -1332,15 +1343,15 @@ channel_tls_update_marks(or_connection_t *conn) if (is_local_addr(&(TO_CONN(conn)->addr))) { if (!channel_is_local(chan)) { log_debug(LD_CHANNEL, - "Marking channel " U64_FORMAT " at %p as local", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Marking channel %"PRIu64 " at %p as local", + (chan->global_identifier), chan); channel_mark_local(chan); } } else { if (channel_is_local(chan)) { log_debug(LD_CHANNEL, - "Marking channel " U64_FORMAT " at %p as remote", - U64_PRINTF_ARG(chan->global_identifier), chan); + "Marking channel %"PRIu64 " at %p as remote", + (chan->global_identifier), chan); channel_mark_remote(chan); } } @@ -2445,4 +2456,3 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan) #undef ERR } - diff --git a/src/or/channeltls.h b/src/core/or/channeltls.h index d9c4239c3a..4a10d51d9f 100644 --- a/src/or/channeltls.h +++ b/src/core/or/channeltls.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,11 @@ #ifndef TOR_CHANNELTLS_H #define TOR_CHANNELTLS_H -#include "or.h" -#include "channel.h" +#include "core/or/or.h" +#include "core/or/channel.h" + +struct ed25519_public_key_t; +struct curve25519_public_key_t; #define BASE_CHAN_TO_TLS(c) (channel_tls_from_base((c))) #define TLS_CHAN_TO_BASE(c) (channel_tls_to_base((c))) @@ -30,7 +33,7 @@ struct channel_tls_s { channel_t * channel_tls_connect(const tor_addr_t *addr, uint16_t port, const char *id_digest, - const ed25519_public_key_t *ed_id); + const struct ed25519_public_key_t *ed_id); channel_listener_t * channel_tls_get_listener(void); channel_listener_t * channel_tls_start_listener(void); channel_t * channel_tls_handle_incoming(or_connection_t *orconn); @@ -72,4 +75,3 @@ STATIC void channel_tls_process_authenticate_cell(var_cell_t *cell, #endif /* defined(CHANNELTLS_PRIVATE) */ #endif /* !defined(TOR_CHANNELTLS_H) */ - diff --git a/src/core/or/circuit_st.h b/src/core/or/circuit_st.h new file mode 100644 index 0000000000..2e33b37b01 --- /dev/null +++ b/src/core/or/circuit_st.h @@ -0,0 +1,182 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CIRCUIT_ST_H +#define CIRCUIT_ST_H + +#include "core/or/or.h" + +#include "core/or/cell_queue_st.h" + +struct hs_token_t; + +/** "magic" value for an origin_circuit_t */ +#define ORIGIN_CIRCUIT_MAGIC 0x35315243u +/** "magic" value for an or_circuit_t */ +#define OR_CIRCUIT_MAGIC 0x98ABC04Fu +/** "magic" value for a circuit that would have been freed by circuit_free, + * but which we're keeping around until a cpuworker reply arrives. See + * circuit_free() for more documentation. */ +#define DEAD_CIRCUIT_MAGIC 0xdeadc14c + +/** + * A circuit is a path over the onion routing + * network. Applications can connect to one end of the circuit, and can + * create exit connections at the other end of the circuit. AP and exit + * connections have only one circuit associated with them (and thus these + * connection types are closed when the circuit is closed), whereas + * OR connections multiplex many circuits at once, and stay standing even + * when there are no circuits running over them. + * + * A circuit_t structure can fill one of two roles. First, a or_circuit_t + * links two connections together: either an edge connection and an OR + * connection, or two OR connections. (When joined to an OR connection, a + * circuit_t affects only cells sent to a particular circID on that + * connection. When joined to an edge connection, a circuit_t affects all + * data.) + + * Second, an origin_circuit_t holds the cipher keys and state for sending data + * along a given circuit. At the OP, it has a sequence of ciphers, each + * of which is shared with a single OR along the circuit. Separate + * ciphers are used for data going "forward" (away from the OP) and + * "backward" (towards the OP). At the OR, a circuit has only two stream + * ciphers: one for data going forward, and one for data going backward. + */ +struct circuit_t { + uint32_t magic; /**< For memory and type debugging: must equal + * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */ + + /** The channel that is next in this circuit. */ + channel_t *n_chan; + + /** + * The circuit_id used in the next (forward) hop of this circuit; + * this is unique to n_chan, but this ordered pair is globally + * unique: + * + * (n_chan->global_identifier, n_circ_id) + */ + circid_t n_circ_id; + + /** + * Circuit mux associated with n_chan to which this circuit is attached; + * NULL if we have no n_chan. + */ + circuitmux_t *n_mux; + + /** Queue of cells waiting to be transmitted on n_chan */ + cell_queue_t n_chan_cells; + + /** + * The hop to which we want to extend this circuit. Should be NULL if + * the circuit has attached to a channel. + */ + extend_info_t *n_hop; + + /** True iff we are waiting for n_chan_cells to become less full before + * allowing p_streams to add any more cells. (Origin circuit only.) */ + unsigned int streams_blocked_on_n_chan : 1; + /** True iff we are waiting for p_chan_cells to become less full before + * allowing n_streams to add any more cells. (OR circuit only.) */ + unsigned int streams_blocked_on_p_chan : 1; + + /** True iff we have queued a delete backwards on this circuit, but not put + * it on the output buffer. */ + unsigned int p_delete_pending : 1; + /** True iff we have queued a delete forwards on this circuit, but not put + * it on the output buffer. */ + unsigned int n_delete_pending : 1; + + /** True iff this circuit has received a DESTROY cell in either direction */ + unsigned int received_destroy : 1; + + uint8_t state; /**< Current status of this circuit. */ + uint8_t purpose; /**< Why are we creating this circuit? */ + + /** How many relay data cells can we package (read from edge streams) + * on this circuit before we receive a circuit-level sendme cell asking + * for more? */ + int package_window; + /** How many relay data cells will we deliver (write to edge streams) + * on this circuit? When deliver_window gets low, we send some + * circuit-level sendme cells to indicate that we're willing to accept + * more. */ + int deliver_window; + + /** Temporary field used during circuits_handle_oom. */ + uint32_t age_tmp; + + /** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */ + struct create_cell_t *n_chan_create_cell; + + /** When did circuit construction actually begin (ie send the + * CREATE cell or begin cannibalization). + * + * Note: This timer will get reset if we decide to cannibalize + * a circuit. It may also get reset during certain phases of hidden + * service circuit use. + * + * We keep this timestamp with a higher resolution than most so that the + * circuit-build-time tracking code can get millisecond resolution. + */ + struct timeval timestamp_began; + + /** This timestamp marks when the init_circuit_base constructor ran. */ + struct timeval timestamp_created; + + /** When the circuit was first used, or 0 if the circuit is clean. + * + * XXXX Note that some code will artificially adjust this value backward + * in time in order to indicate that a circuit shouldn't be used for new + * streams, but that it can stay alive as long as it has streams on it. + * That's a kludge we should fix. + * + * XXX The CBT code uses this field to record when HS-related + * circuits entered certain states. This usage probably won't + * interfere with this field's primary purpose, but we should + * document it more thoroughly to make sure of that. + * + * XXX The SocksPort option KeepaliveIsolateSOCKSAuth will artificially + * adjust this value forward each time a suitable stream is attached to an + * already constructed circuit, potentially keeping the circuit alive + * indefinitely. + */ + time_t timestamp_dirty; + + uint16_t marked_for_close; /**< Should we close this circuit at the end of + * the main loop? (If true, holds the line number + * where this circuit was marked.) */ + const char *marked_for_close_file; /**< For debugging: in which file was this + * circuit marked for close? */ + /** For what reason (See END_CIRC_REASON...) is this circuit being closed? + * This field is set in circuit_mark_for_close and used later in + * circuit_about_to_free. */ + int marked_for_close_reason; + /** As marked_for_close_reason, but reflects the underlying reason for + * closing this circuit. + */ + int marked_for_close_orig_reason; + + /** Unique ID for measuring tunneled network status requests. */ + uint64_t dirreq_id; + + /** Index in smartlist of all circuits (global_circuitlist). */ + int global_circuitlist_idx; + + /** Various statistics about cells being added to or removed from this + * circuit's queues; used only if CELL_STATS events are enabled and + * cleared after being sent to control port. */ + smartlist_t *testing_cell_stats; + + /** If set, points to an HS token that this circuit might be carrying. + * Used by the HS circuitmap. */ + struct hs_token_t *hs_token; + /** Hashtable node: used to look up the circuit by its HS token using the HS + circuitmap. */ + HT_ENTRY(circuit_t) hs_circuitmap_node; +}; + +#endif diff --git a/src/or/circuitbuild.c b/src/core/or/circuitbuild.c index 3d1c9c1abf..e22ddabde3 100644 --- a/src/or/circuitbuild.c +++ b/src/core/or/circuitbuild.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,43 +27,54 @@ #define CIRCUITBUILD_PRIVATE -#include "or.h" -#include "bridges.h" -#include "channel.h" -#include "circpathbias.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "core/or/channel.h" +#include "feature/client/circpathbias.h" #define CIRCUITBUILD_PRIVATE -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "command.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "entrynodes.h" -#include "hs_ntor.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "onion.h" -#include "onion_tap.h" -#include "onion_fast.h" -#include "policies.h" -#include "relay.h" -#include "relay_crypto.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "transports.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "core/or/circuituse.h" +#include "core/or/command.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircache/directory.h" +#include "feature/client/entrynodes.h" +#include "core/crypto/hs_ntor.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/crypto/onion.h" +#include "core/crypto/onion_tap.h" +#include "core/crypto/onion_fast.h" +#include "core/or/policies.h" +#include "core/or/relay.h" +#include "core/crypto/relay_crypto.h" +#include "feature/rend/rendcommon.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "feature/client/transports.h" + +#include "core/or/cell_st.h" +#include "core/or/cpath_build_state_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" static channel_t * channel_connect_for_circuit(const tor_addr_t *addr, uint16_t port, @@ -191,11 +202,11 @@ get_unique_circ_id_by_chan(channel_t *chan) chan->cmux); log_warn(LD_CIRC, " Circuitmux on this channel has %u circuits, " - "of which %u are active. It says it has "I64_FORMAT + "of which %u are active. It says it has %"PRId64 " destroy cells queued.", circuitmux_num_circuits(chan->cmux), circuitmux_num_active_circuits(chan->cmux), - I64_PRINTF_ARG(queued_destroys)); + (queued_destroys)); /* Change this into "if (1)" in order to get more information about * possible failure modes here. You'll need to know how to use gdb with @@ -1139,20 +1150,20 @@ circuit_note_clock_jumped(int64_t seconds_elapsed, bool was_idle) { int severity = server_mode(get_options()) ? LOG_WARN : LOG_NOTICE; if (was_idle) { - tor_log(severity, LD_GENERAL, "Tor has been idle for "I64_FORMAT + tor_log(severity, LD_GENERAL, "Tor has been idle for %"PRId64 " seconds; assuming established circuits no longer work.", - I64_PRINTF_ARG(seconds_elapsed)); + (seconds_elapsed)); } else { tor_log(severity, LD_GENERAL, - "Your system clock just jumped "I64_FORMAT" seconds %s; " + "Your system clock just jumped %"PRId64" seconds %s; " "assuming established circuits no longer work.", - I64_PRINTF_ARG( + ( seconds_elapsed >=0 ? seconds_elapsed : -seconds_elapsed), seconds_elapsed >=0 ? "forward" : "backward"); } - control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME="I64_FORMAT + control_event_general_status(LOG_WARN, "CLOCK_JUMPED TIME=%"PRId64 " IDLE=%d", - I64_PRINTF_ARG(seconds_elapsed), was_idle?1:0); + (seconds_elapsed), was_idle?1:0); /* so we log when it works again */ note_that_we_maybe_cant_complete_circuits(); control_event_client_status(severity, "CIRCUIT_NOT_ESTABLISHED REASON=%s", diff --git a/src/or/circuitbuild.h b/src/core/or/circuitbuild.h index 0184898e29..9f5d99c2a5 100644 --- a/src/or/circuitbuild.h +++ b/src/core/or/circuitbuild.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,9 @@ #ifndef TOR_CIRCUITBUILD_H #define TOR_CIRCUITBUILD_H +struct ed25519_public_key_t; +struct curve25519_public_key_t; + int route_len_for_purpose(uint8_t purpose, extend_info_t *exit_ei); char *circuit_list_path(origin_circuit_t *circ, int verbose); char *circuit_list_path_for_controller(origin_circuit_t *circ); @@ -52,9 +55,9 @@ int circuit_extend_to_new_exit(origin_circuit_t *circ, extend_info_t *info); void onion_append_to_cpath(crypt_path_t **head_ptr, crypt_path_t *new_hop); extend_info_t *extend_info_new(const char *nickname, const char *rsa_id_digest, - const ed25519_public_key_t *ed_id, + const struct ed25519_public_key_t *ed_id, crypto_pk_t *onion_key, - const curve25519_public_key_t *ntor_key, + const struct curve25519_public_key_t *ntor_key, const tor_addr_t *addr, uint16_t port); extend_info_t *extend_info_from_node(const node_t *r, int for_direct_connect); extend_info_t *extend_info_dup(extend_info_t *info); @@ -91,8 +94,10 @@ onion_pick_cpath_exit(origin_circuit_t *circ, extend_info_t *exit_ei, int is_hs_v3_rp_circuit); #if defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS) -STATIC const node_t *pick_tor2web_rendezvous_node(router_crn_flags_t flags, - const or_options_t *options); +enum router_crn_flags_t; +STATIC const node_t *pick_tor2web_rendezvous_node( + enum router_crn_flags_t flags, + const or_options_t *options); unsigned int cpath_get_n_hops(crypt_path_t **head_ptr); #endif /* defined(ENABLE_TOR2WEB_MODE) || defined(TOR_UNIT_TESTS) */ @@ -100,4 +105,3 @@ unsigned int cpath_get_n_hops(crypt_path_t **head_ptr); #endif /* defined(CIRCUITBUILD_PRIVATE) */ #endif /* !defined(TOR_CIRCUITBUILD_H) */ - diff --git a/src/or/circuitlist.c b/src/core/or/circuitlist.c index 45fff7cc17..f39e05ecd1 100644 --- a/src/or/circuitlist.c +++ b/src/core/or/circuitlist.c @@ -1,7 +1,7 @@ /* Copyright 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -51,46 +51,58 @@ * logic, which was originally circuit-focused. **/ #define CIRCUITLIST_PRIVATE -#include "torint.h" /* TOR_PRIuSZ */ - -#include "or.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitstats.h" -#include "connection.h" -#include "config.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "entrynodes.h" -#include "main.h" -#include "hs_circuit.h" -#include "hs_circuitmap.h" -#include "hs_ident.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "onion.h" -#include "onion_fast.h" -#include "policies.h" -#include "relay.h" -#include "relay_crypto.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rephist.h" -#include "routerlist.h" -#include "routerset.h" -#include "channelpadding.h" -#include "compress_lzma.h" -#include "compress_zlib.h" -#include "compress_zstd.h" +#include "lib/cc/torint.h" /* TOR_PRIuSZ */ + +#include "core/or/or.h" +#include "core/or/channel.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/circuitstats.h" +#include "core/mainloop/connection.h" +#include "app/config/config.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "feature/dircache/directory.h" +#include "feature/client/entrynodes.h" +#include "core/mainloop/main.h" +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_ident.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/crypto/onion.h" +#include "core/crypto/onion_fast.h" +#include "core/or/policies.h" +#include "core/or/relay.h" +#include "core/crypto/relay_crypto.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/stats/rephist.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "core/or/channelpadding.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_lzma.h" +#include "lib/compress/compress_zlib.h" +#include "lib/compress/compress_zstd.h" +#include "lib/container/buffers.h" #include "ht.h" +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_reference_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/edge_connection_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" + /********* START VARIABLES **********/ /** A global list of all circuits at this hop. */ @@ -126,6 +138,31 @@ static int any_opened_circs_cached_val = 0; /********* END VARIABLES ************/ +or_circuit_t * +TO_OR_CIRCUIT(circuit_t *x) +{ + tor_assert(x->magic == OR_CIRCUIT_MAGIC); + return DOWNCAST(or_circuit_t, x); +} +const or_circuit_t * +CONST_TO_OR_CIRCUIT(const circuit_t *x) +{ + tor_assert(x->magic == OR_CIRCUIT_MAGIC); + return DOWNCAST(or_circuit_t, x); +} +origin_circuit_t * +TO_ORIGIN_CIRCUIT(circuit_t *x) +{ + tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); + return DOWNCAST(origin_circuit_t, x); +} +const origin_circuit_t * +CONST_TO_ORIGIN_CIRCUIT(const circuit_t *x) +{ + tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); + return DOWNCAST(origin_circuit_t, x); +} + /** A map from channel and circuit ID to circuit. (Lookup performance is * very important here, since we need to do it every time a cell arrives.) */ typedef struct chan_circid_circuit_map_t { @@ -966,9 +1003,9 @@ origin_circuit_new(void) } log_info(LD_CIRC, - "Circuit " U64_FORMAT " chose an idle timeout of %d based on " + "Circuit %"PRIu32" chose an idle timeout of %d based on " "%d seconds of predictive building remaining.", - U64_PRINTF_ARG(circ->global_identifier), + (circ->global_identifier), circ->circuit_idle_timeout, prediction_time_remaining); } @@ -1355,9 +1392,9 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan, if (found && found->circuit) { log_debug(LD_CIRC, "circuit_get_by_circid_channel_impl() returning circuit %p for" - " circ_id %u, channel ID " U64_FORMAT " (%p)", + " circ_id %u, channel ID %"PRIu64 " (%p)", found->circuit, (unsigned)circ_id, - U64_PRINTF_ARG(chan->global_identifier), chan); + (chan->global_identifier), chan); if (found_entry_out) *found_entry_out = 1; return found->circuit; @@ -1365,10 +1402,10 @@ circuit_get_by_circid_channel_impl(circid_t circ_id, channel_t *chan, log_debug(LD_CIRC, "circuit_get_by_circid_channel_impl() found %s for" - " circ_id %u, channel ID " U64_FORMAT " (%p)", + " circ_id %u, channel ID %"PRIu64 " (%p)", found ? "placeholder" : "nothing", (unsigned)circ_id, - U64_PRINTF_ARG(chan->global_identifier), chan); + (chan->global_identifier), chan); if (found_entry_out) *found_entry_out = found ? 1 : 0; @@ -2567,10 +2604,10 @@ circuits_handle_oom(size_t current_allocation) done_recovering_mem: - log_notice(LD_GENERAL, "Removed "U64_FORMAT" bytes by killing %d circuits; " + log_notice(LD_GENERAL, "Removed %"TOR_PRIuSZ" bytes by killing %d circuits; " "%d circuits remain alive. Also killed %d non-linked directory " "connections.", - U64_PRINTF_ARG(mem_recovered), + mem_recovered, n_circuits_killed, smartlist_len(circlist) - n_circuits_killed, n_dirconns_killed); @@ -2703,4 +2740,3 @@ assert_circuit_ok,(const circuit_t *c)) tor_assert(!or_circ || !or_circ->rend_splice); } } - diff --git a/src/core/or/circuitlist.h b/src/core/or/circuitlist.h new file mode 100644 index 0000000000..b069604a1e --- /dev/null +++ b/src/core/or/circuitlist.h @@ -0,0 +1,247 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file circuitlist.h + * \brief Header file for circuitlist.c. + **/ + +#ifndef TOR_CIRCUITLIST_H +#define TOR_CIRCUITLIST_H + +#include "lib/testsupport/testsupport.h" +#include "feature/hs/hs_ident.h" + +/** Circuit state: I'm the origin, still haven't done all my handshakes. */ +#define CIRCUIT_STATE_BUILDING 0 +/** Circuit state: Waiting to process the onionskin. */ +#define CIRCUIT_STATE_ONIONSKIN_PENDING 1 +/** Circuit state: I'd like to deliver a create, but my n_chan is still + * connecting. */ +#define CIRCUIT_STATE_CHAN_WAIT 2 +/** Circuit state: the circuit is open but we don't want to actually use it + * until we find out if a better guard will be available. + */ +#define CIRCUIT_STATE_GUARD_WAIT 3 +/** Circuit state: onionskin(s) processed, ready to send/receive cells. */ +#define CIRCUIT_STATE_OPEN 4 + +#define CIRCUIT_PURPOSE_MIN_ 1 + +/* these circuits were initiated elsewhere */ +#define CIRCUIT_PURPOSE_OR_MIN_ 1 +/** OR-side circuit purpose: normal circuit, at OR. */ +#define CIRCUIT_PURPOSE_OR 1 +/** OR-side circuit purpose: At OR, from the service, waiting for intro from + * clients. */ +#define CIRCUIT_PURPOSE_INTRO_POINT 2 +/** OR-side circuit purpose: At OR, from the client, waiting for the service. + */ +#define CIRCUIT_PURPOSE_REND_POINT_WAITING 3 +/** OR-side circuit purpose: At OR, both circuits have this purpose. */ +#define CIRCUIT_PURPOSE_REND_ESTABLISHED 4 +#define CIRCUIT_PURPOSE_OR_MAX_ 4 + +/* these circuits originate at this node */ + +/* here's how circ client-side purposes work: + * normal circuits are C_GENERAL. + * circuits that are c_introducing are either on their way to + * becoming open, or they are open and waiting for a + * suitable rendcirc before they send the intro. + * circuits that are c_introduce_ack_wait have sent the intro, + * but haven't gotten a response yet. + * circuits that are c_establish_rend are either on their way + * to becoming open, or they are open and have sent the + * establish_rendezvous cell but haven't received an ack. + * circuits that are c_rend_ready are open and have received a + * rend ack, but haven't heard from the service yet. if they have a + * buildstate->pending_final_cpath then they're expecting a + * cell from the service, else they're not. + * circuits that are c_rend_ready_intro_acked are open, and + * some intro circ has sent its intro and received an ack. + * circuits that are c_rend_joined are open, have heard from + * the service, and are talking to it. + */ +/** Client-side circuit purpose: Normal circuit, with cpath. */ +#define CIRCUIT_PURPOSE_C_GENERAL 5 +#define CIRCUIT_PURPOSE_C_HS_MIN_ 6 +/** Client-side circuit purpose: at the client, connecting to intro point. */ +#define CIRCUIT_PURPOSE_C_INTRODUCING 6 +/** Client-side circuit purpose: at the client, sent INTRODUCE1 to intro point, + * waiting for ACK/NAK. */ +#define CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT 7 +/** Client-side circuit purpose: at the client, introduced and acked, closing. + */ +#define CIRCUIT_PURPOSE_C_INTRODUCE_ACKED 8 +/** Client-side circuit purpose: at the client, waiting for ack. */ +#define CIRCUIT_PURPOSE_C_ESTABLISH_REND 9 +/** Client-side circuit purpose: at the client, waiting for the service. */ +#define CIRCUIT_PURPOSE_C_REND_READY 10 +/** Client-side circuit purpose: at the client, waiting for the service, + * INTRODUCE has been acknowledged. */ +#define CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED 11 +/** Client-side circuit purpose: at the client, rendezvous established. */ +#define CIRCUIT_PURPOSE_C_REND_JOINED 12 +/** This circuit is used for getting hsdirs */ +#define CIRCUIT_PURPOSE_C_HSDIR_GET 13 +#define CIRCUIT_PURPOSE_C_HS_MAX_ 13 +/** This circuit is used for build time measurement only */ +#define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 14 +#define CIRCUIT_PURPOSE_C_MAX_ 14 + +#define CIRCUIT_PURPOSE_S_HS_MIN_ 15 +/** Hidden-service-side circuit purpose: at the service, waiting for + * introductions. */ +#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 15 +/** Hidden-service-side circuit purpose: at the service, successfully + * established intro. */ +#define CIRCUIT_PURPOSE_S_INTRO 16 +/** Hidden-service-side circuit purpose: at the service, connecting to rend + * point. */ +#define CIRCUIT_PURPOSE_S_CONNECT_REND 17 +/** Hidden-service-side circuit purpose: at the service, rendezvous + * established. */ +#define CIRCUIT_PURPOSE_S_REND_JOINED 18 +/** This circuit is used for uploading hsdirs */ +#define CIRCUIT_PURPOSE_S_HSDIR_POST 19 +#define CIRCUIT_PURPOSE_S_HS_MAX_ 19 + +/** A testing circuit; not meant to be used for actual traffic. */ +#define CIRCUIT_PURPOSE_TESTING 20 +/** A controller made this circuit and Tor should not use it. */ +#define CIRCUIT_PURPOSE_CONTROLLER 21 +/** This circuit is used for path bias probing only */ +#define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 22 + +/** This circuit is used for vanguards/restricted paths. + * + * This type of circuit is *only* created preemptively and never + * on-demand. When an HS operation needs to take place (e.g. connect to an + * intro point), these circuits are then cannibalized and repurposed to the + * actual needed HS purpose. */ +#define CIRCUIT_PURPOSE_HS_VANGUARDS 23 + +#define CIRCUIT_PURPOSE_MAX_ 23 +/** A catch-all for unrecognized purposes. Currently we don't expect + * to make or see any circuits with this purpose. */ +#define CIRCUIT_PURPOSE_UNKNOWN 255 + +/** True iff the circuit purpose <b>p</b> is for a circuit that + * originated at this node. */ +#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_) +/** True iff the circuit purpose <b>p</b> is for a circuit that originated + * here to serve as a client. (Hidden services don't count here.) */ +#define CIRCUIT_PURPOSE_IS_CLIENT(p) \ + ((p)> CIRCUIT_PURPOSE_OR_MAX_ && \ + (p)<=CIRCUIT_PURPOSE_C_MAX_) +/** True iff the circuit_t <b>c</b> is actually an origin_circuit_t. */ +#define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose)) +/** True iff the circuit purpose <b>p</b> is for an established rendezvous + * circuit. */ +#define CIRCUIT_PURPOSE_IS_ESTABLISHED_REND(p) \ + ((p) == CIRCUIT_PURPOSE_C_REND_JOINED || \ + (p) == CIRCUIT_PURPOSE_S_REND_JOINED) +/** True iff the circuit_t c is actually an or_circuit_t */ +#define CIRCUIT_IS_ORCIRC(c) (((circuit_t *)(c))->magic == OR_CIRCUIT_MAGIC) + +/** True iff this circuit purpose should count towards the global + * pending rate limit (set by MaxClientCircuitsPending). We count all + * general purpose circuits, as well as the first step of client onion + * service connections (HSDir gets). */ +#define CIRCUIT_PURPOSE_COUNTS_TOWARDS_MAXPENDING(p) \ + ((p) == CIRCUIT_PURPOSE_C_GENERAL || \ + (p) == CIRCUIT_PURPOSE_C_HSDIR_GET) + +/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert + * if the cast is impossible. */ +or_circuit_t *TO_OR_CIRCUIT(circuit_t *); +const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *); +/** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t. + * Assert if the cast is impossible. */ +origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *); +const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT(const circuit_t *); + +MOCK_DECL(smartlist_t *, circuit_get_global_list, (void)); +smartlist_t *circuit_get_global_origin_circuit_list(void); +int circuit_any_opened_circuits(void); +int circuit_any_opened_circuits_cached(void); +void circuit_cache_opened_circuit_state(int circuits_are_opened); + +const char *circuit_state_to_string(int state); +const char *circuit_purpose_to_controller_string(uint8_t purpose); +const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); +const char *circuit_purpose_to_string(uint8_t purpose); +void circuit_dump_by_conn(connection_t *conn, int severity); +void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id, + channel_t *chan); +void circuit_set_n_circid_chan(circuit_t *circ, circid_t id, + channel_t *chan); +void channel_mark_circid_unusable(channel_t *chan, circid_t id); +void channel_mark_circid_usable(channel_t *chan, circid_t id); +time_t circuit_id_when_marked_unusable_on_channel(circid_t circ_id, + channel_t *chan); +void circuit_set_state(circuit_t *circ, uint8_t state); +void circuit_close_all_marked(void); +int32_t circuit_initial_package_window(void); +origin_circuit_t *origin_circuit_new(void); +or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan); +circuit_t *circuit_get_by_circid_channel(circid_t circ_id, + channel_t *chan); +circuit_t * +circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, + channel_t *chan); +int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan); +circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn); +void circuit_unlink_all_from_channel(channel_t *chan, int reason); +origin_circuit_t *circuit_get_by_global_id(uint32_t id); +origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data( + const rend_data_t *rend_data); +origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, + const uint8_t *digest, uint8_t purpose); +origin_circuit_t *circuit_get_next_service_intro_circ(origin_circuit_t *start); +origin_circuit_t *circuit_get_next_service_rp_circ(origin_circuit_t *start); +origin_circuit_t *circuit_get_next_service_hsdir_circ(origin_circuit_t *start); +origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, + extend_info_t *info, int flags); +void circuit_mark_all_unused_circs(void); +void circuit_mark_all_dirty_circs_as_unusable(void); +MOCK_DECL(void, circuit_mark_for_close_, (circuit_t *circ, int reason, + int line, const char *file)); +int circuit_get_cpath_len(origin_circuit_t *circ); +int circuit_get_cpath_opened_len(const origin_circuit_t *); +void circuit_clear_cpath(origin_circuit_t *circ); +crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum); +void circuit_get_all_pending_on_channel(smartlist_t *out, + channel_t *chan); +int circuit_count_pending_on_channel(channel_t *chan); + +#define circuit_mark_for_close(c, reason) \ + circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__) + +void assert_cpath_layer_ok(const crypt_path_t *cp); +MOCK_DECL(void, assert_circuit_ok,(const circuit_t *c)); +void circuit_free_all(void); +void circuits_handle_oom(size_t current_allocation); + +void circuit_clear_testing_cell_stats(circuit_t *circ); + +void channel_note_destroy_pending(channel_t *chan, circid_t id); +MOCK_DECL(void, channel_note_destroy_not_pending, + (channel_t *chan, circid_t id)); + +smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void); + +#ifdef CIRCUITLIST_PRIVATE +STATIC void circuit_free_(circuit_t *circ); +#define circuit_free(circ) FREE_AND_NULL(circuit_t, circuit_free_, (circ)) +STATIC size_t n_cells_in_circ_queues(const circuit_t *c); +STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now); +STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now); +STATIC uint32_t circuit_max_queued_item_age(const circuit_t *c, uint32_t now); +#endif /* defined(CIRCUITLIST_PRIVATE) */ + +#endif /* !defined(TOR_CIRCUITLIST_H) */ diff --git a/src/or/circuitmux.c b/src/core/or/circuitmux.c index f9f5faa057..f55386df23 100644 --- a/src/or/circuitmux.c +++ b/src/core/or/circuitmux.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -69,11 +69,15 @@ * made to attach all existing circuits to the new policy. **/ -#include "or.h" -#include "channel.h" -#include "circuitlist.h" -#include "circuitmux.h" -#include "relay.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitmux.h" +#include "core/or/relay.h" + +#include "core/or/cell_queue_st.h" +#include "core/or/destroy_cell_queue_st.h" +#include "core/or/or_circuit_st.h" /* * Private typedefs for circuitmux.c @@ -316,10 +320,10 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out) } else { /* Complain and move on */ log_warn(LD_CIRC, - "Circuit %u/channel " U64_FORMAT " had direction == " + "Circuit %u/channel %"PRIu64 " had direction == " "CELL_DIRECTION_IN, but isn't an or_circuit_t", (unsigned)to_remove->circ_id, - U64_PRINTF_ARG(to_remove->chan_id)); + (to_remove->chan_id)); } /* Free policy-specific data if we have it */ @@ -340,15 +344,15 @@ circuitmux_detach_all_circuits(circuitmux_t *cmux, smartlist_t *detached_out) } else { /* Complain and move on */ log_warn(LD_CIRC, - "Couldn't find circuit %u (for channel " U64_FORMAT ")", + "Couldn't find circuit %u (for channel %"PRIu64 ")", (unsigned)to_remove->circ_id, - U64_PRINTF_ARG(to_remove->chan_id)); + (to_remove->chan_id)); } } else { /* Complain and move on */ log_warn(LD_CIRC, - "Couldn't find channel " U64_FORMAT " (for circuit id %u)", - U64_PRINTF_ARG(to_remove->chan_id), + "Couldn't find channel %"PRIu64 " (for circuit id %u)", + (to_remove->chan_id), (unsigned)to_remove->circ_id); } @@ -424,17 +428,17 @@ circuitmux_free_(circuitmux_t *cmux) global_destroy_ctr -= cmux->destroy_cell_queue.n; log_debug(LD_CIRC, "Freeing cmux at %p with %u queued destroys; the last cmux " - "destroy balance was "I64_FORMAT", global is "I64_FORMAT, + "destroy balance was %"PRId64", global is %"PRId64, cmux, cmux->destroy_cell_queue.n, - I64_PRINTF_ARG(cmux->destroy_ctr), - I64_PRINTF_ARG(global_destroy_ctr)); + (cmux->destroy_ctr), + (global_destroy_ctr)); } else { log_debug(LD_CIRC, "Freeing cmux at %p with no queued destroys, the cmux destroy " - "balance was "I64_FORMAT", global is "I64_FORMAT, + "balance was %"PRId64", global is %"PRId64, cmux, - I64_PRINTF_ARG(cmux->destroy_ctr), - I64_PRINTF_ARG(global_destroy_ctr)); + (cmux->destroy_ctr), + (global_destroy_ctr)); } destroy_cell_queue_clear(&cmux->destroy_cell_queue); @@ -831,9 +835,9 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, * directions match and update the cell count and active circuit count. */ log_info(LD_CIRC, - "Circuit %u on channel " U64_FORMAT " was already attached to " + "Circuit %u on channel %"PRIu64 " was already attached to " "cmux %p (trying to attach to %p)", - (unsigned)circ_id, U64_PRINTF_ARG(channel_id), + (unsigned)circ_id, (channel_id), ((direction == CELL_DIRECTION_OUT) ? circ->n_mux : TO_OR_CIRCUIT(circ)->p_mux), cmux); @@ -865,8 +869,8 @@ circuitmux_attach_circuit,(circuitmux_t *cmux, circuit_t *circ, * counts. */ log_debug(LD_CIRC, - "Attaching circuit %u on channel " U64_FORMAT " to cmux %p", - (unsigned)circ_id, U64_PRINTF_ARG(channel_id), cmux); + "Attaching circuit %u on channel %"PRIu64 " to cmux %p", + (unsigned)circ_id, (channel_id), cmux); /* * Assert that the circuit doesn't already have a mux for this @@ -1237,11 +1241,11 @@ circuitmux_notify_xmit_destroy(circuitmux_t *cmux) --(cmux->destroy_ctr); --(global_destroy_ctr); log_debug(LD_CIRC, - "Cmux at %p sent a destroy, cmux counter is now "I64_FORMAT", " - "global counter is now "I64_FORMAT, + "Cmux at %p sent a destroy, cmux counter is now %"PRId64", " + "global counter is now %"PRId64, cmux, - I64_PRINTF_ARG(cmux->destroy_ctr), - I64_PRINTF_ARG(global_destroy_ctr)); + (cmux->destroy_ctr), + (global_destroy_ctr)); } /*DOCDOC */ @@ -1258,10 +1262,10 @@ circuitmux_append_destroy_cell(channel_t *chan, ++global_destroy_ctr; log_debug(LD_CIRC, "Cmux at %p queued a destroy for circ %u, cmux counter is now " - I64_FORMAT", global counter is now "I64_FORMAT, + "%"PRId64", global counter is now %"PRId64, cmux, circ_id, - I64_PRINTF_ARG(cmux->destroy_ctr), - I64_PRINTF_ARG(global_destroy_ctr)); + (cmux->destroy_ctr), + (global_destroy_ctr)); /* XXXX Duplicate code from append_cell_to_circuit_queue */ if (!channel_has_queued_writes(chan)) { @@ -1299,12 +1303,12 @@ circuitmux_count_queued_destroy_cells(const channel_t *chan, n_destroy_cells != manual_total || n_destroy_cells != manual_total_in_map) { log_warn(LD_BUG, " Discrepancy in counts for queued destroy cells on " - "circuitmux. n="I64_FORMAT". queue_size="I64_FORMAT". " - "manual_total="I64_FORMAT". manual_total_in_map="I64_FORMAT".", - I64_PRINTF_ARG(n_destroy_cells), - I64_PRINTF_ARG(destroy_queue_size), - I64_PRINTF_ARG(manual_total), - I64_PRINTF_ARG(manual_total_in_map)); + "circuitmux. n=%"PRId64". queue_size=%"PRId64". " + "manual_total=%"PRId64". manual_total_in_map=%"PRId64".", + (n_destroy_cells), + (destroy_queue_size), + (manual_total), + (manual_total_in_map)); } return n_destroy_cells; diff --git a/src/or/circuitmux.h b/src/core/or/circuitmux.h index 336e128c76..31bf81463b 100644 --- a/src/or/circuitmux.h +++ b/src/core/or/circuitmux.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_CIRCUITMUX_H #define TOR_CIRCUITMUX_H -#include "or.h" -#include "testsupport.h" +#include "core/or/or.h" +#include "lib/testsupport/testsupport.h" typedef struct circuitmux_policy_s circuitmux_policy_t; typedef struct circuitmux_policy_data_s circuitmux_policy_data_t; diff --git a/src/or/circuitmux_ewma.c b/src/core/or/circuitmux_ewma.c index e5d5a14581..deca81f0ac 100644 --- a/src/or/circuitmux_ewma.c +++ b/src/core/or/circuitmux_ewma.c @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -34,11 +34,12 @@ #include <math.h> -#include "or.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "crypto_rand.h" -#include "networkstatus.h" +#include "core/or/or.h" +#include "core/or/circuitmux.h" +#include "core/or/circuitmux_ewma.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/nodelist/networkstatus.h" +#include "app/config/or_options_st.h" /*** EWMA parameter #defines ***/ @@ -826,4 +827,3 @@ circuitmux_ewma_free_all(void) { ewma_ticks_initialized = 0; } - diff --git a/src/or/circuitmux_ewma.h b/src/core/or/circuitmux_ewma.h index f0c4c36095..8e87830a80 100644 --- a/src/or/circuitmux_ewma.h +++ b/src/core/or/circuitmux_ewma.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* * Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_CIRCUITMUX_EWMA_H #define TOR_CIRCUITMUX_EWMA_H -#include "or.h" -#include "circuitmux.h" +#include "core/or/or.h" +#include "core/or/circuitmux.h" /* The public EWMA policy callbacks object. */ extern circuitmux_policy_t ewma_policy; diff --git a/src/or/circuitstats.c b/src/core/or/circuitstats.c index 94f75c590f..63cd21540d 100644 --- a/src/or/circuitstats.c +++ b/src/core/or/circuitstats.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,21 +25,28 @@ #define CIRCUITSTATS_PRIVATE -#include "or.h" -#include "circuitbuild.h" -#include "circuitstats.h" -#include "config.h" -#include "confparse.h" -#include "control.h" -#include "crypto_rand.h" -#include "main.h" -#include "networkstatus.h" -#include "rendclient.h" -#include "rendservice.h" -#include "router.h" -#include "statefile.h" -#include "circuitlist.h" -#include "circuituse.h" +#include "core/or/or.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitstats.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendservice.h" +#include "feature/relay/router.h" +#include "app/config/statefile.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "lib/math/fp.h" +#include "lib/time/tvdiff.h" +#include "lib/encoding/confline.h" + +#include "core/or/crypt_path_st.h" +#include "core/or/origin_circuit_st.h" +#include "app/config/or_state_st.h" #undef log #include <math.h> @@ -706,8 +713,8 @@ circuit_build_times_handle_completed_hop(origin_circuit_t *circ) * Switch their purpose and wait. */ if (circ->base_.purpose != CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT) { log_info(LD_CIRC, - "Deciding to timeout circuit "U64_FORMAT"\n", - U64_PRINTF_ARG(circ->global_identifier)); + "Deciding to timeout circuit %"PRIu32"\n", + (circ->global_identifier)); circuit_build_times_mark_circ_as_measurement_only(circ); } } @@ -1943,4 +1950,3 @@ cbt_control_event_buildtimeout_set(const circuit_build_times_t *cbt, tor_free(args); } - diff --git a/src/or/circuitstats.h b/src/core/or/circuitstats.h index 86116cb7f8..174730d035 100644 --- a/src/or/circuitstats.h +++ b/src/core/or/circuitstats.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,6 +21,9 @@ int circuit_build_times_disabled(const or_options_t *options); int circuit_build_times_disabled_(const or_options_t *options, int ignore_consensus); +/** A build_time_t is milliseconds */ +typedef uint32_t build_time_t; + int circuit_build_times_enough_to_compute(const circuit_build_times_t *cbt); void circuit_build_times_update_state(const circuit_build_times_t *cbt, or_state_t *state); @@ -47,6 +50,89 @@ double circuit_build_times_close_rate(const circuit_build_times_t *cbt); void circuit_build_times_update_last_circ(circuit_build_times_t *cbt); void circuit_build_times_mark_circ_as_measurement_only(origin_circuit_t *circ); +/** Total size of the circuit timeout history to accumulate. + * 1000 is approx 2.5 days worth of continual-use circuits. */ +#define CBT_NCIRCUITS_TO_OBSERVE 1000 + +/** Width of the histogram bins in milliseconds */ +#define CBT_BIN_WIDTH ((build_time_t)50) + +/** Number of modes to use in the weighted-avg computation of Xm */ +#define CBT_DEFAULT_NUM_XM_MODES 3 +#define CBT_MIN_NUM_XM_MODES 1 +#define CBT_MAX_NUM_XM_MODES 20 + +/** + * CBT_BUILD_ABANDONED is our flag value to represent a force-closed + * circuit (Aka a 'right-censored' pareto value). + */ +#define CBT_BUILD_ABANDONED ((build_time_t)(INT32_MAX-1)) +#define CBT_BUILD_TIME_MAX ((build_time_t)(INT32_MAX)) + +/** Save state every 10 circuits */ +#define CBT_SAVE_STATE_EVERY 10 + +/* Circuit build times consensus parameters */ + +/** + * How long to wait before actually closing circuits that take too long to + * build in terms of CDF quantile. + */ +#define CBT_DEFAULT_CLOSE_QUANTILE 95 +#define CBT_MIN_CLOSE_QUANTILE CBT_MIN_QUANTILE_CUTOFF +#define CBT_MAX_CLOSE_QUANTILE CBT_MAX_QUANTILE_CUTOFF + +/** + * How many circuits count as recent when considering if the + * connection has gone gimpy or changed. + */ +#define CBT_DEFAULT_RECENT_CIRCUITS 20 +#define CBT_MIN_RECENT_CIRCUITS 3 +#define CBT_MAX_RECENT_CIRCUITS 1000 + +/** + * Maximum count of timeouts that finish the first hop in the past + * RECENT_CIRCUITS before calculating a new timeout. + * + * This tells us whether to abandon timeout history and set + * the timeout back to whatever circuit_build_times_get_initial_timeout() + * gives us. + */ +#define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10) +#define CBT_MIN_MAX_RECENT_TIMEOUT_COUNT 3 +#define CBT_MAX_MAX_RECENT_TIMEOUT_COUNT 10000 + +/** Minimum circuits before estimating a timeout */ +#define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100 +#define CBT_MIN_MIN_CIRCUITS_TO_OBSERVE 1 +#define CBT_MAX_MIN_CIRCUITS_TO_OBSERVE 10000 + +/** Cutoff percentile on the CDF for our timeout estimation. */ +#define CBT_DEFAULT_QUANTILE_CUTOFF 80 +#define CBT_MIN_QUANTILE_CUTOFF 10 +#define CBT_MAX_QUANTILE_CUTOFF 99 +double circuit_build_times_quantile_cutoff(void); + +/** How often in seconds should we build a test circuit */ +#define CBT_DEFAULT_TEST_FREQUENCY 10 +#define CBT_MIN_TEST_FREQUENCY 1 +#define CBT_MAX_TEST_FREQUENCY INT32_MAX + +/** Lowest allowable value for CircuitBuildTimeout in milliseconds */ +#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (1500) +#define CBT_MIN_TIMEOUT_MIN_VALUE 500 +#define CBT_MAX_TIMEOUT_MIN_VALUE INT32_MAX + +/** Initial circuit build timeout in milliseconds */ +#define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000) +#define CBT_MIN_TIMEOUT_INITIAL_VALUE CBT_MIN_TIMEOUT_MIN_VALUE +#define CBT_MAX_TIMEOUT_INITIAL_VALUE INT32_MAX +int32_t circuit_build_times_initial_timeout(void); + +#if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < CBT_MIN_MAX_RECENT_TIMEOUT_COUNT +#error "RECENT_CIRCUITS is set too low." +#endif + #ifdef CIRCUITSTATS_PRIVATE STATIC double circuit_build_times_calculate_timeout(circuit_build_times_t *cbt, double quantile); @@ -73,6 +159,21 @@ int circuit_build_times_network_check_live(const circuit_build_times_t *cbt); void circuit_build_times_network_circ_success(circuit_build_times_t *cbt); #ifdef CIRCUITSTATS_PRIVATE +/** Information about the state of our local network connection */ +typedef struct { + /** The timestamp we last completed a TLS handshake or received a cell */ + time_t network_last_live; + /** If the network is not live, how many timeouts has this caused? */ + int nonlive_timeouts; + /** Circular array of circuits that have made it to the first hop. Slot is + * 1 if circuit timed out, 0 if circuit succeeded */ + int8_t *timeouts_after_firsthop; + /** Number of elements allocated for the above array */ + int num_recent_circs; + /** Index into circular array. */ + int after_firsthop_idx; +} network_liveness_t; + /** Structure for circuit build times history */ struct circuit_build_times_s { /** The circular array of recorded build times in milliseconds */ @@ -110,4 +211,3 @@ struct circuit_build_times_s { #endif /* defined(CIRCUITSTATS_PRIVATE) */ #endif /* !defined(TOR_CIRCUITSTATS_H) */ - diff --git a/src/or/circuituse.c b/src/core/or/circuituse.c index 8e007ce920..a3b9eb1713 100644 --- a/src/or/circuituse.c +++ b/src/core/or/circuituse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,34 +27,45 @@ * logic in circuitstats.c. **/ -#include "or.h" -#include "addressmap.h" -#include "bridges.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "entrynodes.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_circuit.h" -#include "hs_ident.h" -#include "hs_stats.h" -#include "nodelist.h" -#include "networkstatus.h" -#include "policies.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" +#include "core/or/or.h" +#include "feature/client/addressmap.h" +#include "feature/client/bridges.h" +#include "core/or/channel.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/control/control.h" +#include "feature/dircache/directory.h" +#include "feature/client/entrynodes.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_ident.h" +#include "feature/hs/hs_stats.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/networkstatus.h" +#include "core/or/policies.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "lib/math/fp.h" +#include "lib/time/tvdiff.h" + +#include "core/or/cpath_build_state_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" static void circuit_expire_old_circuits_clientside(void); static void circuit_increment_failure_count(void); @@ -708,9 +719,8 @@ circuit_expire_building(void) circuit_build_times_enough_to_compute(get_circuit_build_times())) { log_info(LD_CIRC, - "Deciding to count the timeout for circuit "U64_FORMAT"\n", - U64_PRINTF_ARG( - TO_ORIGIN_CIRCUIT(victim)->global_identifier)); + "Deciding to count the timeout for circuit %"PRIu32"\n", + TO_ORIGIN_CIRCUIT(victim)->global_identifier); /* Circuits are allowed to last longer for measurement. * Switch their purpose and wait. */ @@ -1499,10 +1509,10 @@ circuit_expire_old_circuits_clientside(void) circ->purpose <= CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED) || circ->purpose == CIRCUIT_PURPOSE_S_CONNECT_REND) { log_info(LD_CIRC, - "Closing circuit "U64_FORMAT + "Closing circuit %"PRIu32 " that has been unused for %ld msec.", - U64_PRINTF_ARG(TO_ORIGIN_CIRCUIT(circ)->global_identifier), - tv_mdiff(&circ->timestamp_began, &now)); + TO_ORIGIN_CIRCUIT(circ)->global_identifier, + tv_mdiff(&circ->timestamp_began, &now)); circuit_mark_for_close(circ, END_CIRC_REASON_FINISHED); } else if (!TO_ORIGIN_CIRCUIT(circ)->is_ancient) { /* Server-side rend joined circuits can end up really old, because @@ -3143,4 +3153,3 @@ circuit_read_valid_data(origin_circuit_t *circ, uint16_t relay_body_len) tor_add_u32_nowrap(circ->n_overhead_read_circ_bw, RELAY_PAYLOAD_SIZE-relay_body_len); } - diff --git a/src/or/circuituse.h b/src/core/or/circuituse.h index 6458bd6908..b65e85d170 100644 --- a/src/or/circuituse.h +++ b/src/core/or/circuituse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/command.c b/src/core/or/command.c index 39950f41bf..461e49b629 100644 --- a/src/or/command.c +++ b/src/core/or/command.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -36,25 +36,30 @@ * callbacks registered in command_setup_channel(), * called when channels are created in circuitbuild.c */ -#include "or.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "command.h" -#include "connection.h" -#include "connection_or.h" -#include "config.h" -#include "control.h" -#include "cpuworker.h" -#include "crypto_util.h" -#include "dos.h" -#include "hibernate.h" -#include "nodelist.h" -#include "onion.h" -#include "rephist.h" -#include "relay.h" -#include "router.h" -#include "routerlist.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/command.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "core/mainloop/cpuworker.h" +#include "lib/crypt_ops/crypto_util.h" +#include "core/or/dos.h" +#include "feature/hibernate/hibernate.h" +#include "feature/nodelist/nodelist.h" +#include "core/crypto/onion.h" +#include "feature/stats/rephist.h" +#include "core/or/relay.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" + +#include "core/or/cell_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/var_cell_st.h" /** How many CELL_CREATE cells have we received, ever? */ uint64_t stats_n_create_cells_processed = 0; @@ -244,10 +249,10 @@ command_process_create_cell(cell_t *cell, channel_t *chan) tor_assert(chan); log_debug(LD_OR, - "Got a CREATE cell for circ_id %u on channel " U64_FORMAT + "Got a CREATE cell for circ_id %u on channel %"PRIu64 " (%p)", (unsigned)cell->circ_id, - U64_PRINTF_ARG(chan->global_identifier), chan); + (chan->global_identifier), chan); /* First thing we do, even though the cell might be invalid, is inform the * DoS mitigation subsystem layer of this event. Validation is done by this diff --git a/src/or/command.h b/src/core/or/command.h index c0d1996cbb..83ffd8dccd 100644 --- a/src/or/command.h +++ b/src/core/or/command.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_COMMAND_H #define TOR_COMMAND_H -#include "channel.h" +#include "core/or/channel.h" void command_process_cell(channel_t *chan, cell_t *cell); void command_process_var_cell(channel_t *chan, var_cell_t *cell); diff --git a/src/or/connection_edge.c b/src/core/or/connection_edge.c index 046369af60..8e8a5e21ca 100644 --- a/src/or/connection_edge.c +++ b/src/core/or/connection_edge.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,47 +55,58 @@ **/ #define CONNECTION_EDGE_PRIVATE -#include "or.h" - -#include "backtrace.h" - -#include "addressmap.h" -#include "buffers.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_util.h" -#include "dns.h" -#include "dnsserv.h" -#include "directory.h" -#include "dirserv.h" -#include "hibernate.h" -#include "hs_common.h" -#include "hs_cache.h" -#include "hs_client.h" -#include "hs_circuit.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "proto_http.h" -#include "proto_socks.h" -#include "reasons.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "circuitbuild.h" +#include "core/or/or.h" + +#include "lib/err/backtrace.h" + +#include "feature/client/addressmap.h" +#include "lib/container/buffers.h" +#include "core/or/channel.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/relay/dns.h" +#include "feature/client/dnsserv.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_circuit.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/proto/proto_http.h" +#include "core/proto/proto_socks.h" +#include "core/or/reasons.h" +#include "core/or/relay.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "core/or/circuitbuild.h" + +#include "core/or/cell_st.h" +#include "core/or/cpath_build_state_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" +#include "lib/evloop/compat_libevent.h" #ifdef HAVE_LINUX_TYPES_H #include <linux/types.h> @@ -137,6 +148,30 @@ static int connection_exit_connect_dir(edge_connection_t *exitconn); static int consider_plaintext_ports(entry_connection_t *conn, uint16_t port); static int connection_ap_supports_optimistic_data(const entry_connection_t *); +/** Convert a connection_t* to an edge_connection_t*; assert if the cast is + * invalid. */ +edge_connection_t * +TO_EDGE_CONN(connection_t *c) +{ + tor_assert(c->magic == EDGE_CONNECTION_MAGIC || + c->magic == ENTRY_CONNECTION_MAGIC); + return DOWNCAST(edge_connection_t, c); +} + +entry_connection_t * +TO_ENTRY_CONN(connection_t *c) +{ + tor_assert(c->magic == ENTRY_CONNECTION_MAGIC); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); +} + +entry_connection_t * +EDGE_TO_ENTRY_CONN(edge_connection_t *c) +{ + tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC); + return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); +} + /** An AP stream has failed/finished. If it hasn't already sent back * a socks reply, send one now (based on endreason). Also set * has_sent_end to 1, and mark the conn. @@ -3165,9 +3200,9 @@ connection_ap_handshake_socks_reply(entry_connection_t *conn, char *reply, !CIRCUIT_IS_ORIGIN(conn->edge_.on_circuit)) { if (endreason != END_STREAM_REASON_RESOLVEFAILED) { log_info(LD_BUG, - "No origin circuit for successful SOCKS stream "U64_FORMAT + "No origin circuit for successful SOCKS stream %"PRIu64 ". Reason: %d", - U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier), + (ENTRY_TO_CONN(conn)->global_identifier), endreason); } /* @@ -4187,4 +4222,3 @@ connection_edge_free_all(void) pending_entry_connections = NULL; mainloop_event_free(attach_pending_entry_connections_ev); } - diff --git a/src/or/connection_edge.h b/src/core/or/connection_edge.h index c6583d3845..24968b2778 100644 --- a/src/or/connection_edge.h +++ b/src/core/or/connection_edge.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,9 +12,61 @@ #ifndef TOR_CONNECTION_EDGE_H #define TOR_CONNECTION_EDGE_H -#include "testsupport.h" - -#define connection_mark_unattached_ap(conn, endreason) \ +#include "lib/testsupport/testsupport.h" + +edge_connection_t *TO_EDGE_CONN(connection_t *); +entry_connection_t *TO_ENTRY_CONN(connection_t *); +entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *); + +#define EXIT_CONN_STATE_MIN_ 1 +/** State for an exit connection: waiting for response from DNS farm. */ +#define EXIT_CONN_STATE_RESOLVING 1 +/** State for an exit connection: waiting for connect() to finish. */ +#define EXIT_CONN_STATE_CONNECTING 2 +/** State for an exit connection: open and ready to transmit data. */ +#define EXIT_CONN_STATE_OPEN 3 +/** State for an exit connection: waiting to be removed. */ +#define EXIT_CONN_STATE_RESOLVEFAILED 4 +#define EXIT_CONN_STATE_MAX_ 4 + +/* The AP state values must be disjoint from the EXIT state values. */ +#define AP_CONN_STATE_MIN_ 5 +/** State for a SOCKS connection: waiting for SOCKS request. */ +#define AP_CONN_STATE_SOCKS_WAIT 5 +/** State for a SOCKS connection: got a y.onion URL; waiting to receive + * rendezvous descriptor. */ +#define AP_CONN_STATE_RENDDESC_WAIT 6 +/** The controller will attach this connection to a circuit; it isn't our + * job to do so. */ +#define AP_CONN_STATE_CONTROLLER_WAIT 7 +/** State for a SOCKS connection: waiting for a completed circuit. */ +#define AP_CONN_STATE_CIRCUIT_WAIT 8 +/** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */ +#define AP_CONN_STATE_CONNECT_WAIT 9 +/** State for a SOCKS connection: sent RESOLVE, waiting for RESOLVED. */ +#define AP_CONN_STATE_RESOLVE_WAIT 10 +/** State for a SOCKS connection: ready to send and receive. */ +#define AP_CONN_STATE_OPEN 11 +/** State for a transparent natd connection: waiting for original + * destination. */ +#define AP_CONN_STATE_NATD_WAIT 12 +/** State for an HTTP tunnel: waiting for an HTTP CONNECT command. */ +#define AP_CONN_STATE_HTTP_CONNECT_WAIT 13 +#define AP_CONN_STATE_MAX_ 13 + +#define EXIT_PURPOSE_MIN_ 1 +/** This exit stream wants to do an ordinary connect. */ +#define EXIT_PURPOSE_CONNECT 1 +/** This exit stream wants to do a resolve (either normal or reverse). */ +#define EXIT_PURPOSE_RESOLVE 2 +#define EXIT_PURPOSE_MAX_ 2 + +/** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding + * edge connection is not attached to any circuit. */ +#define AP_CONN_STATE_IS_UNATTACHED(s) \ + ((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT) + +#define connection_mark_unattached_ap(conn, endreason) \ connection_mark_unattached_ap_((conn), (endreason), __LINE__, SHORT_FILE__) MOCK_DECL(void,connection_mark_unattached_ap_, @@ -194,4 +246,3 @@ STATIC int connection_ap_process_http_connect(entry_connection_t *conn); #endif /* defined(CONNECTION_EDGE_PRIVATE) */ #endif /* !defined(TOR_CONNECTION_EDGE_H) */ - diff --git a/src/or/connection_or.c b/src/core/or/connection_or.c index 7898fbd42e..159ee96266 100644 --- a/src/or/connection_or.c +++ b/src/core/or/connection_or.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,46 +20,58 @@ * * This module also implements the client side of the v3 Tor link handshake, **/ -#include "or.h" -#include "bridges.h" -#include "buffers.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "lib/container/buffers.h" /* * Define this so we get channel internal functions, since we're implementing * part of a subclass (channel_tls_t). */ #define TOR_CHANNEL_INTERNAL_ #define CONNECTION_OR_PRIVATE -#include "channel.h" -#include "channeltls.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "command.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "main.h" -#include "link_handshake.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "proto_cell.h" -#include "reasons.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "ext_orport.h" -#include "scheduler.h" -#include "torcert.h" -#include "channelpadding.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "core/or/command.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/entrynodes.h" +#include "feature/stats/geoip.h" +#include "core/mainloop/main.h" +#include "trunnel/link_handshake.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/proto/proto_cell.h" +#include "core/or/reasons.h" +#include "core/or/relay.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/relay/ext_orport.h" +#include "core/or/scheduler.h" +#include "feature/nodelist/torcert.h" +#include "core/or/channelpadding.h" + +#include "core/or/cell_st.h" +#include "core/or/cell_queue_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/or_handshake_certs_st.h" +#include "core/or/or_handshake_state_st.h" +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "core/or/var_cell_st.h" +#include "lib/crypt_ops/crypto_format.h" + +#include "lib/tls/tortls.h" static int connection_tls_finish_handshake(or_connection_t *conn); static int connection_or_launch_v3_or_handshake(or_connection_t *conn); @@ -86,6 +98,15 @@ static void connection_or_check_canonicity(or_connection_t *conn, /**************************************************************/ +/** Convert a connection_t* to an or_connection_t*; assert if the cast is + * invalid. */ +or_connection_t * +TO_OR_CONN(connection_t *c) +{ + tor_assert(c->magic == OR_CONNECTION_MAGIC); + return DOWNCAST(or_connection_t, c); +} + /** Global map between Extended ORPort identifiers and OR * connections. */ static digestmap_t *orconn_ext_or_id_map = NULL; @@ -834,9 +855,9 @@ connection_or_set_canonical(or_connection_t *or_conn, TLS_CHAN_TO_BASE(or_conn->chan), is_canonical); log_info(LD_CIRC, - "Channel " U64_FORMAT " chose an idle timeout of %d.", + "Channel %"PRIu64 " chose an idle timeout of %d.", or_conn->chan ? - U64_PRINTF_ARG(TLS_CHAN_TO_BASE(or_conn->chan)->global_identifier):0, + (TLS_CHAN_TO_BASE(or_conn->chan)->global_identifier):0, or_conn->idle_timeout); } @@ -2973,4 +2994,3 @@ connection_or_send_authenticate_cell,(or_connection_t *conn, int authtype)) return 0; } - diff --git a/src/or/connection_or.h b/src/core/or/connection_or.h index 158eb1fdad..2d95fdea18 100644 --- a/src/or/connection_or.h +++ b/src/core/or/connection_or.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,38 @@ #ifndef TOR_CONNECTION_OR_H #define TOR_CONNECTION_OR_H +struct ed25519_public_key_t; +struct ed25519_keypair_t; + +or_connection_t *TO_OR_CONN(connection_t *); + +#define OR_CONN_STATE_MIN_ 1 +/** State for a connection to an OR: waiting for connect() to finish. */ +#define OR_CONN_STATE_CONNECTING 1 +/** State for a connection to an OR: waiting for proxy handshake to complete */ +#define OR_CONN_STATE_PROXY_HANDSHAKING 2 +/** State for an OR connection client: SSL is handshaking, not done + * yet. */ +#define OR_CONN_STATE_TLS_HANDSHAKING 3 +/** State for a connection to an OR: We're doing a second SSL handshake for + * renegotiation purposes. (V2 handshake only.) */ +#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4 +/** State for a connection at an OR: We're waiting for the client to + * renegotiate (to indicate a v2 handshake) or send a versions cell (to + * indicate a v3 handshake) */ +#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5 +/** State for an OR connection: We're done with our SSL handshake, we've done + * renegotiation, but we haven't yet negotiated link protocol versions and + * sent a netinfo cell. */ +#define OR_CONN_STATE_OR_HANDSHAKING_V2 6 +/** State for an OR connection: We're done with our SSL handshake, but we + * haven't yet negotiated link protocol versions, done a V3 handshake, and + * sent a netinfo cell. */ +#define OR_CONN_STATE_OR_HANDSHAKING_V3 7 +/** State for an OR connection: Ready to send/receive cells. */ +#define OR_CONN_STATE_OPEN 8 +#define OR_CONN_STATE_MAX_ 8 + void connection_or_clear_identity(or_connection_t *conn); void connection_or_clear_identity_map(void); void clear_broken_connection_map(int disable); @@ -40,7 +72,7 @@ MOCK_DECL(or_connection_t *, connection_or_connect, (const tor_addr_t *addr, uint16_t port, const char *id_digest, - const ed25519_public_key_t *ed_id, + const struct ed25519_public_key_t *ed_id, channel_tls_t *chan)); void connection_or_close_normally(or_connection_t *orconn, int flush); @@ -58,14 +90,14 @@ void connection_or_set_canonical(or_connection_t *or_conn, int connection_init_or_handshake_state(or_connection_t *conn, int started_here); void connection_or_init_conn_from_address(or_connection_t *conn, - const tor_addr_t *addr, - uint16_t port, - const char *rsa_id_digest, - const ed25519_public_key_t *ed_id, - int started_here); + const tor_addr_t *addr, + uint16_t port, + const char *rsa_id_digest, + const struct ed25519_public_key_t *ed_id, + int started_here); int connection_or_client_learned_peer_id(or_connection_t *conn, const uint8_t *rsa_peer_id, - const ed25519_public_key_t *ed_peer_id); + const struct ed25519_public_key_t *ed_peer_id); time_t connection_or_client_used(or_connection_t *conn); MOCK_DECL(int, connection_or_get_num_circuits, (or_connection_t *conn)); void or_handshake_state_free_(or_handshake_state_t *state); @@ -92,11 +124,12 @@ int connection_or_send_auth_challenge_cell(or_connection_t *conn); int authchallenge_type_is_supported(uint16_t challenge_type); int authchallenge_type_is_better(uint16_t challenge_type_a, uint16_t challenge_type_b); -var_cell_t *connection_or_compute_authenticate_cell_body(or_connection_t *conn, - const int authtype, - crypto_pk_t *signing_key, - const ed25519_keypair_t *ed_signing_key, - int server); +var_cell_t *connection_or_compute_authenticate_cell_body( + or_connection_t *conn, + const int authtype, + crypto_pk_t *signing_key, + const struct ed25519_keypair_t *ed_signing_key, + int server); MOCK_DECL(int,connection_or_send_authenticate_cell, (or_connection_t *conn, int type)); @@ -130,4 +163,3 @@ extern int certs_cell_ed25519_disabled_for_testing; #endif #endif /* !defined(TOR_CONNECTION_OR_H) */ - diff --git a/src/core/or/connection_st.h b/src/core/or/connection_st.h new file mode 100644 index 0000000000..6c22478689 --- /dev/null +++ b/src/core/or/connection_st.h @@ -0,0 +1,149 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CONNECTION_ST_H +#define CONNECTION_ST_H + +struct buf_t; + +/* Values for connection_t.magic: used to make sure that downcasts (casts from +* connection_t to foo_connection_t) are safe. */ +#define BASE_CONNECTION_MAGIC 0x7C3C304Eu +#define OR_CONNECTION_MAGIC 0x7D31FF03u +#define EDGE_CONNECTION_MAGIC 0xF0374013u +#define ENTRY_CONNECTION_MAGIC 0xbb4a5703 +#define DIR_CONNECTION_MAGIC 0x9988ffeeu +#define CONTROL_CONNECTION_MAGIC 0x8abc765du +#define LISTENER_CONNECTION_MAGIC 0x1a1ac741u + +/** Description of a connection to another host or process, and associated + * data. + * + * A connection is named based on what it's connected to -- an "OR + * connection" has a Tor node on the other end, an "exit + * connection" has a website or other server on the other end, and an + * "AP connection" has an application proxy (and thus a user) on the + * other end. + * + * Every connection has a type and a state. Connections never change + * their type, but can go through many state changes in their lifetime. + * + * Every connection has two associated input and output buffers. + * Listeners don't use them. For non-listener connections, incoming + * data is appended to conn->inbuf, and outgoing data is taken from + * conn->outbuf. Connections differ primarily in the functions called + * to fill and drain these buffers. + */ +struct connection_t { + uint32_t magic; /**< For memory debugging: must equal one of + * *_CONNECTION_MAGIC. */ + + uint8_t state; /**< Current state of this connection. */ + unsigned int type:5; /**< What kind of connection is this? */ + unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */ + + /* The next fields are all one-bit booleans. Some are only applicable to + * connection subtypes, but we hold them here anyway, to save space. + */ + unsigned int read_blocked_on_bw:1; /**< Boolean: should we start reading + * again once the bandwidth throttler allows it? */ + unsigned int write_blocked_on_bw:1; /**< Boolean: should we start writing + * again once the bandwidth throttler allows + * writes? */ + unsigned int hold_open_until_flushed:1; /**< Despite this connection's being + * marked for close, do we flush it + * before closing it? */ + unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this + * conn? */ + /** Set to 1 when we're inside connection_flushed_some to keep us from + * calling connection_handle_write() recursively. */ + unsigned int in_flushed_some:1; + /** True if connection_handle_write is currently running on this connection. + */ + unsigned int in_connection_handle_write:1; + + /* For linked connections: + */ + unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */ + /** True iff we'd like to be notified about read events from the + * linked conn. */ + unsigned int reading_from_linked_conn:1; + /** True iff we're willing to write to the linked conn. */ + unsigned int writing_to_linked_conn:1; + /** True iff we're currently able to read on the linked conn, and our + * read_event should be made active with libevent. */ + unsigned int active_on_link:1; + /** True iff we've called connection_close_immediate() on this linked + * connection. */ + unsigned int linked_conn_is_closed:1; + + /** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */ + unsigned int proxy_state:4; + + /** Our socket; set to TOR_INVALID_SOCKET if this connection is closed, + * or has no socket. */ + tor_socket_t s; + int conn_array_index; /**< Index into the global connection array. */ + + struct event *read_event; /**< Libevent event structure. */ + struct event *write_event; /**< Libevent event structure. */ + struct buf_t *inbuf; /**< Buffer holding data read over this connection. */ + struct buf_t *outbuf; /**< Buffer holding data to write over this + * connection. */ + size_t outbuf_flushlen; /**< How much data should we try to flush from the + * outbuf? */ + time_t timestamp_last_read_allowed; /**< When was the last time libevent said + * we could read? */ + time_t timestamp_last_write_allowed; /**< When was the last time libevent + * said we could write? */ + + time_t timestamp_created; /**< When was this connection_t created? */ + + int socket_family; /**< Address family of this connection's socket. Usually + * AF_INET, but it can also be AF_UNIX, or AF_INET6 */ + tor_addr_t addr; /**< IP that socket "s" is directly connected to; + * may be the IP address for a proxy or pluggable transport, + * see "address" for the address of the final destination. + */ + uint16_t port; /**< If non-zero, port that socket "s" is directly connected + * to; may be the port for a proxy or pluggable transport, + * see "address" for the port at the final destination. */ + uint16_t marked_for_close; /**< Should we close this conn on the next + * iteration of the main loop? (If true, holds + * the line number where this connection was + * marked.) */ + const char *marked_for_close_file; /**< For debugging: in which file were + * we marked for close? */ + char *address; /**< FQDN (or IP) and port of the final destination for this + * connection; this is always the remote address, it is + * passed to a proxy or pluggable transport if one in use. + * See "addr" and "port" for the address that socket "s" is + * directly connected to. + * strdup into this, because free_connection() frees it. */ + /** Another connection that's connected to this one in lieu of a socket. */ + struct connection_t *linked_conn; + + /** Unique identifier for this connection on this Tor instance. */ + uint64_t global_identifier; + + /** Bytes read since last call to control_event_conn_bandwidth_used(). + * Only used if we're configured to emit CONN_BW events. */ + uint32_t n_read_conn_bw; + + /** Bytes written since last call to control_event_conn_bandwidth_used(). + * Only used if we're configured to emit CONN_BW events. */ + uint32_t n_written_conn_bw; +}; + +/** True iff <b>x</b> is an edge connection. */ +#define CONN_IS_EDGE(x) \ + ((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP) + +/** True iff the purpose of <b>conn</b> means that it's a server-side + * directory connection. */ +#define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER) + +#endif diff --git a/src/core/or/cpath_build_state_st.h b/src/core/or/cpath_build_state_st.h new file mode 100644 index 0000000000..1db7251132 --- /dev/null +++ b/src/core/or/cpath_build_state_st.h @@ -0,0 +1,38 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CIRCUIT_BUILD_STATE_ST_ST_H +#define CIRCUIT_BUILD_STATE_ST_ST_H + +/** Information used to build a circuit. */ +struct cpath_build_state_t { + /** Intended length of the final circuit. */ + int desired_path_len; + /** How to extend to the planned exit node. */ + extend_info_t *chosen_exit; + /** Whether every node in the circ must have adequate uptime. */ + unsigned int need_uptime : 1; + /** Whether every node in the circ must have adequate capacity. */ + unsigned int need_capacity : 1; + /** Whether the last hop was picked with exiting in mind. */ + unsigned int is_internal : 1; + /** Did we pick this as a one-hop tunnel (not safe for other streams)? + * These are for encrypted dir conns that exit to this router, not + * for arbitrary exits from the circuit. */ + unsigned int onehop_tunnel : 1; + /** The crypt_path_t to append after rendezvous: used for rendezvous. */ + crypt_path_t *pending_final_cpath; + /** A ref-counted reference to the crypt_path_t to append after + * rendezvous; used on the service side. */ + crypt_path_reference_t *service_pending_final_cpath_ref; + /** How many times has building a circuit for this task failed? */ + int failure_count; + /** At what time should we give up on this task? */ + time_t expiry_time; +}; + +#endif + diff --git a/src/core/or/crypt_path_reference_st.h b/src/core/or/crypt_path_reference_st.h new file mode 100644 index 0000000000..bb0e519233 --- /dev/null +++ b/src/core/or/crypt_path_reference_st.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CRYPT_PATH_REFERENCE_ST_H +#define CRYPT_PATH_REFERENCE_ST_H + +/** A reference-counted pointer to a crypt_path_t, used only to share + * the final rendezvous cpath to be used on a service-side rendezvous + * circuit among multiple circuits built in parallel to the same + * destination rendezvous point. */ +struct crypt_path_reference_t { + /** The reference count. */ + unsigned int refcount; + /** The pointer. Set to NULL when the crypt_path_t is put into use + * on an opened rendezvous circuit. */ + crypt_path_t *cpath; +}; + +#endif + diff --git a/src/core/or/crypt_path_st.h b/src/core/or/crypt_path_st.h new file mode 100644 index 0000000000..1380913360 --- /dev/null +++ b/src/core/or/crypt_path_st.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CRYPT_PATH_ST_H +#define CRYPT_PATH_ST_H + +#include "core/or/relay_crypto_st.h" +struct crypto_dh_t; + +#define CRYPT_PATH_MAGIC 0x70127012u + +struct fast_handshake_state_t; +struct ntor_handshake_state_t; +struct crypto_dh_t; +struct onion_handshake_state_t { + uint16_t tag; + union { + struct fast_handshake_state_t *fast; + struct crypto_dh_t *tap; + struct ntor_handshake_state_t *ntor; + } u; +}; + +/** Holds accounting information for a single step in the layered encryption + * performed by a circuit. Used only at the client edge of a circuit. */ +struct crypt_path_t { + uint32_t magic; + + /** Cryptographic state used for encrypting and authenticating relay + * cells to and from this hop. */ + relay_crypto_t crypto; + + /** Current state of the handshake as performed with the OR at this + * step. */ + onion_handshake_state_t handshake_state; + /** Diffie-hellman handshake state for performing an introduction + * operations */ + struct crypto_dh_t *rend_dh_handshake_state; + + /** Negotiated key material shared with the OR at this step. */ + char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ + + /** Information to extend to the OR at this step. */ + extend_info_t *extend_info; + + /** Is the circuit built to this step? Must be one of: + * - CPATH_STATE_CLOSED (The circuit has not been extended to this step) + * - CPATH_STATE_AWAITING_KEYS (We have sent an EXTEND/CREATE to this step + * and not received an EXTENDED/CREATED) + * - CPATH_STATE_OPEN (The circuit has been extended to this step) */ + uint8_t state; +#define CPATH_STATE_CLOSED 0 +#define CPATH_STATE_AWAITING_KEYS 1 +#define CPATH_STATE_OPEN 2 + struct crypt_path_t *next; /**< Link to next crypt_path_t in the circuit. + * (The list is circular, so the last node + * links to the first.) */ + struct crypt_path_t *prev; /**< Link to previous crypt_path_t in the + * circuit. */ + + int package_window; /**< How many cells are we allowed to originate ending + * at this step? */ + int deliver_window; /**< How many cells are we willing to deliver originating + * at this step? */ +}; + +#endif diff --git a/src/core/or/destroy_cell_queue_st.h b/src/core/or/destroy_cell_queue_st.h new file mode 100644 index 0000000000..2839b0bd11 --- /dev/null +++ b/src/core/or/destroy_cell_queue_st.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DESTROY_CELL_QUEUE_ST_H +#define DESTROY_CELL_QUEUE_ST_H + +/** A single queued destroy cell. */ +struct destroy_cell_t { + TOR_SIMPLEQ_ENTRY(destroy_cell_t) next; + circid_t circid; + uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell + * was inserted */ + uint8_t reason; +}; + +/** A queue of destroy cells on a channel. */ +struct destroy_cell_queue_t { + /** Linked list of packed_cell_t */ + TOR_SIMPLEQ_HEAD(dcell_simpleq, destroy_cell_t) head; + int n; /**< The number of cells in the queue. */ +}; + +#endif + diff --git a/src/or/dos.c b/src/core/or/dos.c index ee731accea..52879c34d7 100644 --- a/src/or/dos.c +++ b/src/core/or/dos.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* @@ -8,18 +8,22 @@ #define DOS_PRIVATE -#include "or.h" -#include "channel.h" -#include "config.h" -#include "crypto_rand.h" -#include "geoip.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "router.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/stats/geoip.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/relay.h" +#include "feature/relay/router.h" -#include "dos.h" +#include "core/or/dos.h" + +#include "core/or/or_connection_st.h" /* * Circuit creation denial of service mitigation. @@ -795,4 +799,3 @@ dos_init(void) /* To initialize, we only need to get the parameters. */ set_dos_parameters(NULL); } - diff --git a/src/or/dos.h b/src/core/or/dos.h index 5d35a2b12e..760ef11057 100644 --- a/src/or/dos.h +++ b/src/core/or/dos.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* diff --git a/src/core/or/edge_connection_st.h b/src/core/or/edge_connection_st.h new file mode 100644 index 0000000000..f4388c10e6 --- /dev/null +++ b/src/core/or/edge_connection_st.h @@ -0,0 +1,77 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef EDGE_CONNECTION_ST_H +#define EDGE_CONNECTION_ST_H + +#include "core/or/or.h" + +#include "core/or/connection_st.h" + +/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) + * connection, or an exit. */ +struct edge_connection_t { + connection_t base_; + + struct edge_connection_t *next_stream; /**< Points to the next stream at this + * edge, if any */ + int package_window; /**< How many more relay cells can I send into the + * circuit? */ + int deliver_window; /**< How many more relay cells can end at me? */ + + struct circuit_t *on_circuit; /**< The circuit (if any) that this edge + * connection is using. */ + + /** A pointer to which node in the circ this conn exits at. Set for AP + * connections and for hidden service exit connections. */ + struct crypt_path_t *cpath_layer; + /** What rendezvous service are we querying for (if an AP) or providing (if + * an exit)? */ + rend_data_t *rend_data; + + /* Hidden service connection identifier for edge connections. Used by the HS + * client-side code to identify client SOCKS connections and by the + * service-side code to match HS circuits with their streams. */ + struct hs_ident_edge_conn_t *hs_ident; + + uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit + * connection. Exit connections only. */ + uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell + * for this connection */ + + streamid_t stream_id; /**< The stream ID used for this edge connection on its + * circuit */ + + /** The reason why this connection is closing; passed to the controller. */ + uint16_t end_reason; + + /** Bytes read since last call to control_event_stream_bandwidth_used() */ + uint32_t n_read; + + /** Bytes written since last call to control_event_stream_bandwidth_used() */ + uint32_t n_written; + + /** True iff this connection is for a DNS request only. */ + unsigned int is_dns_request:1; + /** True iff this connection is for a PTR DNS request. (exit only) */ + unsigned int is_reverse_dns_lookup:1; + + unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge + * connections. Set once we've set the stream end, + * and check in connection_about_to_close_connection(). + */ + /** True iff we've blocked reading until the circuit has fewer queued + * cells. */ + unsigned int edge_blocked_on_circ:1; + + /** Unique ID for directory requests; this used to be in connection_t, but + * that's going away and being used on channels instead. We still tag + * edge connections with dirreq_id from circuits, so it's copied here. */ + uint64_t dirreq_id; +}; + +#endif + diff --git a/src/core/or/entry_connection_st.h b/src/core/or/entry_connection_st.h new file mode 100644 index 0000000000..ebaee2f1a6 --- /dev/null +++ b/src/core/or/entry_connection_st.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ENTRY_CONNECTION_ST_H +#define ENTRY_CONNECTION_ST_H + +#include "core/or/edge_connection_st.h" + +/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS + * connection, a DNS request, a TransPort connection or a NATD connection */ +struct entry_connection_t { + struct edge_connection_t edge_; + + /** Nickname of planned exit node -- used with .exit support. */ + /* XXX prop220: we need to make chosen_exit_name able to encode Ed IDs too. + * That's logically part of the UI parts for prop220 though. */ + char *chosen_exit_name; + + socks_request_t *socks_request; /**< SOCKS structure describing request (AP + * only.) */ + + /* === Isolation related, AP only. === */ + entry_port_cfg_t entry_cfg; + /** AP only: The newnym epoch in which we created this connection. */ + unsigned nym_epoch; + + /** AP only: The original requested address before we rewrote it. */ + char *original_dest_address; + /* Other fields to isolate on already exist. The ClientAddr is addr. The + ClientProtocol is a combination of type and socks_request-> + socks_version. SocksAuth is socks_request->username/password. + DestAddr is in socks_request->address. */ + + /** Number of times we've reassigned this application connection to + * a new circuit. We keep track because the timeout is longer if we've + * already retried several times. */ + uint8_t num_socks_retries; + + /** For AP connections only: buffer for data that we have sent + * optimistically, which we might need to re-send if we have to + * retry this connection. */ + struct buf_t *pending_optimistic_data; + /* For AP connections only: buffer for data that we previously sent + * optimistically which we are currently re-sending as we retry this + * connection. */ + struct buf_t *sending_optimistic_data; + + /** If this is a DNSPort connection, this field holds the pending DNS + * request that we're going to try to answer. */ + struct evdns_server_request *dns_server_request; + +#define DEBUGGING_17659 + +#ifdef DEBUGGING_17659 + uint16_t marked_pending_circ_line; + const char *marked_pending_circ_file; +#endif + +#define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10 + /** Number of times we've launched a circuit to handle this stream. If + * it gets too high, that could indicate an inconsistency between our + * "launch a circuit to handle this stream" logic and our "attach our + * stream to one of the available circuits" logic. */ + unsigned int num_circuits_launched:4; + + /** True iff this stream must attach to a one-hop circuit (e.g. for + * begin_dir). */ + unsigned int want_onehop:1; + /** True iff this stream should use a BEGIN_DIR relay command to establish + * itself rather than BEGIN (either via onehop or via a whole circuit). */ + unsigned int use_begindir:1; + + /** For AP connections only. If 1, and we fail to reach the chosen exit, + * stop requiring it. */ + unsigned int chosen_exit_optional:1; + /** For AP connections only. If non-zero, this exit node was picked as + * a result of the TrackHostExit, and the value decrements every time + * we fail to complete a circuit to our chosen exit -- if it reaches + * zero, abandon the associated mapaddress. */ + unsigned int chosen_exit_retries:3; + + /** True iff this is an AP connection that came from a transparent or + * NATd connection */ + unsigned int is_transparent_ap:1; + + /** For AP connections only: Set if this connection's target exit node + * allows optimistic data (that is, data sent on this stream before + * the exit has sent a CONNECTED cell) and we have chosen to use it. + */ + unsigned int may_use_optimistic_data : 1; +}; + +/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ +#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) + +#endif + diff --git a/src/core/or/entry_port_cfg_st.h b/src/core/or/entry_port_cfg_st.h new file mode 100644 index 0000000000..492fafbd6d --- /dev/null +++ b/src/core/or/entry_port_cfg_st.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ENTRY_PORT_CFG_ST_H +#define ENTRY_PORT_CFG_ST_H + +#include "lib/cc/torint.h" +#include "core/or/or.h" + +struct entry_port_cfg_t { + /* Client port types (socks, dns, trans, natd) only: */ + uint8_t isolation_flags; /**< Zero or more isolation flags */ + int session_group; /**< A session group, or -1 if this port is not in a + * session group. */ + + /* Socks only: */ + /** When both no-auth and user/pass are advertised by a SOCKS client, select + * no-auth. */ + unsigned int socks_prefer_no_auth : 1; + /** When ISO_SOCKSAUTH is in use, Keep-Alive circuits indefinitely. */ + unsigned int socks_iso_keep_alive : 1; + + /* Client port types only: */ + unsigned int ipv4_traffic : 1; + unsigned int ipv6_traffic : 1; + unsigned int prefer_ipv6 : 1; + unsigned int dns_request : 1; + unsigned int onion_traffic : 1; + + /** For a socks listener: should we cache IPv4/IPv6 DNS information that + * exit nodes tell us? + * + * @{ */ + unsigned int cache_ipv4_answers : 1; + unsigned int cache_ipv6_answers : 1; + /** @} */ + /** For a socks listeners: if we find an answer in our client-side DNS cache, + * should we use it? + * + * @{ */ + unsigned int use_cached_ipv4_answers : 1; + unsigned int use_cached_ipv6_answers : 1; + /** @} */ + /** For socks listeners: When we can automap an address to IPv4 or IPv6, + * do we prefer IPv6? */ + unsigned int prefer_ipv6_virtaddr : 1; + +}; + +#endif + diff --git a/src/core/or/extend_info_st.h b/src/core/or/extend_info_st.h new file mode 100644 index 0000000000..277766c4d6 --- /dev/null +++ b/src/core/or/extend_info_st.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef EXTEND_INFO_ST_H +#define EXTEND_INFO_ST_H + +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" + +/** Information on router used when extending a circuit. We don't need a + * full routerinfo_t to extend: we only need addr:port:keyid to build an OR + * connection, and onion_key to create the onionskin. Note that for onehop + * general-purpose tunnels, the onion_key is NULL. */ +struct extend_info_t { + char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for + * display. */ + /** Hash of this router's RSA identity key. */ + char identity_digest[DIGEST_LEN]; + /** Ed25519 identity for this router, if any. */ + ed25519_public_key_t ed_identity; + uint16_t port; /**< OR port. */ + tor_addr_t addr; /**< IP address. */ + crypto_pk_t *onion_key; /**< Current onionskin key. */ + curve25519_public_key_t curve25519_onion_key; +}; + +#endif diff --git a/src/or/git_revision.c b/src/core/or/git_revision.c index 8f326b8751..28ec1a7933 100644 --- a/src/or/git_revision.c +++ b/src/core/or/git_revision.c @@ -1,17 +1,16 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "git_revision.h" +#include "core/or/git_revision.h" /** String describing which Tor Git repository version the source was * built from. This string is generated by a bit of shell kludging in - * src/or/include.am, and is usually right. + * src/core/include.am, and is usually right. */ const char tor_git_revision[] = #ifndef _MSC_VER #include "micro-revision.i" #endif ""; - diff --git a/src/or/git_revision.h b/src/core/or/git_revision.h index 5613cb4335..02070cfd5e 100644 --- a/src/or/git_revision.h +++ b/src/core/or/git_revision.h @@ -1,6 +1,6 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_GIT_REVISION_H diff --git a/src/core/or/listener_connection_st.h b/src/core/or/listener_connection_st.h new file mode 100644 index 0000000000..ec350c1b0d --- /dev/null +++ b/src/core/or/listener_connection_st.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef LISTENER_CONNECTION_ST_H +#define LISTENER_CONNECTION_ST_H + +#include "core/or/connection_st.h" + +/** Subtype of connection_t; used for a listener socket. */ +struct listener_connection_t { + connection_t base_; + + /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points + * to the evdns_server_port it uses to listen to and answer connections. */ + struct evdns_server_port *dns_server_port; + + entry_port_cfg_t entry_cfg; + +}; + +#endif + diff --git a/src/core/or/or.h b/src/core/or/or.h new file mode 100644 index 0000000000..6edfd21dfb --- /dev/null +++ b/src/core/or/or.h @@ -0,0 +1,1088 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file or.h + * \brief Master header file for Tor-specific functionality. + **/ + +#ifndef TOR_OR_H +#define TOR_OR_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif + +#include "lib/arch/bytes.h" +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/container/map.h" +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/ctime/di_ops.h" +#include "lib/defs/dh_sizes.h" +#include "lib/encoding/binascii.h" +#include "lib/encoding/cstring.h" +#include "lib/encoding/time_fmt.h" +#include "lib/err/torerr.h" +#include "lib/fs/dir.h" +#include "lib/fs/files.h" +#include "lib/fs/mmap.h" +#include "lib/fs/path.h" +#include "lib/fs/userdb.h" +#include "lib/intmath/addsub.h" +#include "lib/intmath/bits.h" +#include "lib/intmath/cmp.h" +#include "lib/intmath/logic.h" +#include "lib/intmath/muldiv.h" +#include "lib/log/escape.h" +#include "lib/log/ratelim.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/address.h" +#include "lib/net/ipv4.h" +#include "lib/net/ipv6.h" +#include "lib/net/resolve.h" +#include "lib/net/socket.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/string/parse_int.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" +#include "lib/string/util_string.h" +#include "lib/testsupport/testsupport.h" +#include "lib/thread/threads.h" +#include "lib/time/compat_time.h" +#include "lib/wallclock/approx_time.h" +#include "lib/wallclock/timeval.h" + +#include "ht.h" + +// These, more than other includes, are for keeping the other struct +// definitions working. We should remove them when we minimize our includes. +#include "core/or/entry_port_cfg_st.h" + +struct ed25519_public_key_t; +struct curve25519_public_key_t; + +/* These signals are defined to help handle_control_signal work. + */ +#ifndef SIGHUP +#define SIGHUP 1 +#endif +#ifndef SIGINT +#define SIGINT 2 +#endif +#ifndef SIGUSR1 +#define SIGUSR1 10 +#endif +#ifndef SIGUSR2 +#define SIGUSR2 12 +#endif +#ifndef SIGTERM +#define SIGTERM 15 +#endif +/* Controller signals start at a high number so we don't + * conflict with system-defined signals. */ +#define SIGNEWNYM 129 +#define SIGCLEARDNSCACHE 130 +#define SIGHEARTBEAT 131 + +#if (SIZEOF_CELL_T != 0) +/* On Irix, stdlib.h defines a cell_t type, so we need to make sure + * that our stuff always calls cell_t something different. */ +#define cell_t tor_cell_t +#endif + +#ifdef ENABLE_TOR2WEB_MODE +#define NON_ANONYMOUS_MODE_ENABLED 1 +#endif + +/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */ +#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_)) + +/** Length of longest allowable configured nickname. */ +#define MAX_NICKNAME_LEN 19 +/** Length of a router identity encoded as a hexadecimal digest, plus + * possible dollar sign. */ +#define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1) +/** Maximum length of verbose router identifier: dollar sign, hex ID digest, + * equal sign or tilde, nickname. */ +#define MAX_VERBOSE_NICKNAME_LEN (1+HEX_DIGEST_LEN+1+MAX_NICKNAME_LEN) + +/** For HTTP parsing: Maximum number of bytes we'll accept in the headers + * of an HTTP request or response. */ +#define MAX_HEADERS_SIZE 50000 + +/** Maximum size, in bytes, of a single router descriptor uploaded to us + * as a directory authority. Caches and clients fetch whatever descriptors + * the authorities tell them to fetch, and don't care about size. */ +#define MAX_DESCRIPTOR_UPLOAD_SIZE 20000 + +/** Maximum size of a single extrainfo document, as above. */ +#define MAX_EXTRAINFO_UPLOAD_SIZE 50000 + +/** Minimum lifetime for an onion key in days. */ +#define MIN_ONION_KEY_LIFETIME_DAYS (1) + +/** Maximum lifetime for an onion key in days. */ +#define MAX_ONION_KEY_LIFETIME_DAYS (90) + +/** Default lifetime for an onion key in days. */ +#define DEFAULT_ONION_KEY_LIFETIME_DAYS (28) + +/** Minimum grace period for acceptance of an onion key in days. + * The maximum value is defined in proposal #274 as being the current network + * consensus parameter for "onion-key-rotation-days". */ +#define MIN_ONION_KEY_GRACE_PERIOD_DAYS (1) + +/** Default grace period for acceptance of an onion key in days. */ +#define DEFAULT_ONION_KEY_GRACE_PERIOD_DAYS (7) + +/** How often we should check the network consensus if it is time to rotate or + * expire onion keys. */ +#define ONION_KEY_CONSENSUS_CHECK_INTERVAL (60*60) + +/** How often do we rotate TLS contexts? */ +#define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60) + +/** How old do we allow a router to get before removing it + * from the router list? In seconds. */ +#define ROUTER_MAX_AGE (60*60*48) +/** How old can a router get before we (as a server) will no longer + * consider it live? In seconds. */ +#define ROUTER_MAX_AGE_TO_PUBLISH (60*60*24) +/** How old do we let a saved descriptor get before force-removing it? */ +#define OLD_ROUTER_DESC_MAX_AGE (60*60*24*5) + +/* Proxy client types */ +#define PROXY_NONE 0 +#define PROXY_CONNECT 1 +#define PROXY_SOCKS4 2 +#define PROXY_SOCKS5 3 +/* !!!! If there is ever a PROXY_* type over 3, we must grow the proxy_type + * field in or_connection_t */ + +/* Pluggable transport proxy type. Don't use this in or_connection_t, + * instead use the actual underlying proxy type (see above). */ +#define PROXY_PLUGGABLE 4 + +/** How many circuits do we want simultaneously in-progress to handle + * a given stream? */ +#define MIN_CIRCUITS_HANDLING_STREAM 2 + +/* These RELAY_COMMAND constants define values for relay cell commands, and +* must match those defined in tor-spec.txt. */ +#define RELAY_COMMAND_BEGIN 1 +#define RELAY_COMMAND_DATA 2 +#define RELAY_COMMAND_END 3 +#define RELAY_COMMAND_CONNECTED 4 +#define RELAY_COMMAND_SENDME 5 +#define RELAY_COMMAND_EXTEND 6 +#define RELAY_COMMAND_EXTENDED 7 +#define RELAY_COMMAND_TRUNCATE 8 +#define RELAY_COMMAND_TRUNCATED 9 +#define RELAY_COMMAND_DROP 10 +#define RELAY_COMMAND_RESOLVE 11 +#define RELAY_COMMAND_RESOLVED 12 +#define RELAY_COMMAND_BEGIN_DIR 13 +#define RELAY_COMMAND_EXTEND2 14 +#define RELAY_COMMAND_EXTENDED2 15 + +#define RELAY_COMMAND_ESTABLISH_INTRO 32 +#define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33 +#define RELAY_COMMAND_INTRODUCE1 34 +#define RELAY_COMMAND_INTRODUCE2 35 +#define RELAY_COMMAND_RENDEZVOUS1 36 +#define RELAY_COMMAND_RENDEZVOUS2 37 +#define RELAY_COMMAND_INTRO_ESTABLISHED 38 +#define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39 +#define RELAY_COMMAND_INTRODUCE_ACK 40 + +/* Reasons why an OR connection is closed. */ +#define END_OR_CONN_REASON_DONE 1 +#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */ +#define END_OR_CONN_REASON_OR_IDENTITY 3 +#define END_OR_CONN_REASON_CONNRESET 4 /* connection reset by peer */ +#define END_OR_CONN_REASON_TIMEOUT 5 +#define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */ +#define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */ +#define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */ +#define END_OR_CONN_REASON_PT_MISSING 9 /* PT failed or not available */ +#define END_OR_CONN_REASON_MISC 10 + +/* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for + * documentation of these. The values must match. */ +#define END_STREAM_REASON_MISC 1 +#define END_STREAM_REASON_RESOLVEFAILED 2 +#define END_STREAM_REASON_CONNECTREFUSED 3 +#define END_STREAM_REASON_EXITPOLICY 4 +#define END_STREAM_REASON_DESTROY 5 +#define END_STREAM_REASON_DONE 6 +#define END_STREAM_REASON_TIMEOUT 7 +#define END_STREAM_REASON_NOROUTE 8 +#define END_STREAM_REASON_HIBERNATING 9 +#define END_STREAM_REASON_INTERNAL 10 +#define END_STREAM_REASON_RESOURCELIMIT 11 +#define END_STREAM_REASON_CONNRESET 12 +#define END_STREAM_REASON_TORPROTOCOL 13 +#define END_STREAM_REASON_NOTDIRECTORY 14 +#define END_STREAM_REASON_ENTRYPOLICY 15 + +/* These high-numbered end reasons are not part of the official spec, + * and are not intended to be put in relay end cells. They are here + * to be more informative when sending back socks replies to the + * application. */ +/* XXXX 256 is no longer used; feel free to reuse it. */ +/** We were unable to attach the connection to any circuit at all. */ +/* XXXX the ways we use this one don't make a lot of sense. */ +#define END_STREAM_REASON_CANT_ATTACH 257 +/** We can't connect to any directories at all, so we killed our streams + * before they can time out. */ +#define END_STREAM_REASON_NET_UNREACHABLE 258 +/** This is a SOCKS connection, and the client used (or misused) the SOCKS + * protocol in a way we couldn't handle. */ +#define END_STREAM_REASON_SOCKSPROTOCOL 259 +/** This is a transparent proxy connection, but we can't extract the original + * target address:port. */ +#define END_STREAM_REASON_CANT_FETCH_ORIG_DEST 260 +/** This is a connection on the NATD port, and the destination IP:Port was + * either ill-formed or out-of-range. */ +#define END_STREAM_REASON_INVALID_NATD_DEST 261 +/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1); + * you don't want to do that over a randomly chosen exit */ +#define END_STREAM_REASON_PRIVATE_ADDR 262 +/** This is an HTTP tunnel connection and the client used or misused HTTP in a + * way we can't handle. + */ +#define END_STREAM_REASON_HTTPPROTOCOL 263 + +/** Bitwise-and this value with endreason to mask out all flags. */ +#define END_STREAM_REASON_MASK 511 + +/** Bitwise-or this with the argument to control_event_stream_status + * to indicate that the reason came from an END cell. */ +#define END_STREAM_REASON_FLAG_REMOTE 512 +/** Bitwise-or this with the argument to control_event_stream_status + * to indicate that we already sent a CLOSED stream event. */ +#define END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED 1024 +/** Bitwise-or this with endreason to indicate that we already sent + * a socks reply, and no further reply needs to be sent from + * connection_mark_unattached_ap(). */ +#define END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED 2048 + +/* 'type' values to use in RESOLVED cells. Specified in tor-spec.txt. */ +#define RESOLVED_TYPE_HOSTNAME 0 +#define RESOLVED_TYPE_IPV4 4 +#define RESOLVED_TYPE_IPV6 6 +#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0 +#define RESOLVED_TYPE_ERROR 0xF1 + +/* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE + * call; they only go to the controller for tracking */ + +/* Closing introduction point that were opened in parallel. */ +#define END_CIRC_REASON_IP_NOW_REDUNDANT -4 + +/** Our post-timeout circuit time measurement period expired. + * We must give up now */ +#define END_CIRC_REASON_MEASUREMENT_EXPIRED -3 + +/** We couldn't build a path for this circuit. */ +#define END_CIRC_REASON_NOPATH -2 +/** Catch-all "other" reason for closing origin circuits. */ +#define END_CIRC_AT_ORIGIN -1 + +/* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt + * section 5.4 for documentation of these. */ +#define END_CIRC_REASON_MIN_ 0 +#define END_CIRC_REASON_NONE 0 +#define END_CIRC_REASON_TORPROTOCOL 1 +#define END_CIRC_REASON_INTERNAL 2 +#define END_CIRC_REASON_REQUESTED 3 +#define END_CIRC_REASON_HIBERNATING 4 +#define END_CIRC_REASON_RESOURCELIMIT 5 +#define END_CIRC_REASON_CONNECTFAILED 6 +#define END_CIRC_REASON_OR_IDENTITY 7 +#define END_CIRC_REASON_CHANNEL_CLOSED 8 +#define END_CIRC_REASON_FINISHED 9 +#define END_CIRC_REASON_TIMEOUT 10 +#define END_CIRC_REASON_DESTROYED 11 +#define END_CIRC_REASON_NOSUCHSERVICE 12 +#define END_CIRC_REASON_MAX_ 12 + +/** Bitwise-OR this with the argument to circuit_mark_for_close() or + * control_event_circuit_status() to indicate that the reason was + * passed through from a destroy or truncate cell. */ +#define END_CIRC_REASON_FLAG_REMOTE 512 + +/** Length of 'y' portion of 'y.onion' URL. */ +#define REND_SERVICE_ID_LEN_BASE32 16 + +/** Length of 'y.onion' including '.onion' URL. */ +#define REND_SERVICE_ADDRESS_LEN (16+1+5) + +/** Length of a binary-encoded rendezvous service ID. */ +#define REND_SERVICE_ID_LEN 10 + +/** Time period for which a v2 descriptor will be valid. */ +#define REND_TIME_PERIOD_V2_DESC_VALIDITY (24*60*60) + +/** Time period within which two sets of v2 descriptors will be uploaded in + * parallel. */ +#define REND_TIME_PERIOD_OVERLAPPING_V2_DESCS (60*60) + +/** Number of non-consecutive replicas (i.e. distributed somewhere + * in the ring) for a descriptor. */ +#define REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS 2 + +/** Number of consecutive replicas for a descriptor. */ +#define REND_NUMBER_OF_CONSECUTIVE_REPLICAS 3 + +/** Length of v2 descriptor ID (32 base32 chars = 160 bits). */ +#define REND_DESC_ID_V2_LEN_BASE32 BASE32_DIGEST_LEN + +/** Length of the base32-encoded secret ID part of versioned hidden service + * descriptors. */ +#define REND_SECRET_ID_PART_LEN_BASE32 BASE32_DIGEST_LEN + +/** Length of the base32-encoded hash of an introduction point's + * identity key. */ +#define REND_INTRO_POINT_ID_LEN_BASE32 BASE32_DIGEST_LEN + +/** Length of the descriptor cookie that is used for client authorization + * to hidden services. */ +#define REND_DESC_COOKIE_LEN 16 + +/** Length of the base64-encoded descriptor cookie that is used for + * exchanging client authorization between hidden service and client. */ +#define REND_DESC_COOKIE_LEN_BASE64 22 + +/** Length of client identifier in encrypted introduction points for hidden + * service authorization type 'basic'. */ +#define REND_BASIC_AUTH_CLIENT_ID_LEN 4 + +/** Multiple of the number of clients to which the real number of clients + * is padded with fake clients for hidden service authorization type + * 'basic'. */ +#define REND_BASIC_AUTH_CLIENT_MULTIPLE 16 + +/** Length of client entry consisting of client identifier and encrypted + * session key for hidden service authorization type 'basic'. */ +#define REND_BASIC_AUTH_CLIENT_ENTRY_LEN (REND_BASIC_AUTH_CLIENT_ID_LEN \ + + CIPHER_KEY_LEN) + +/** Maximum size of v2 hidden service descriptors. */ +#define REND_DESC_MAX_SIZE (20 * 1024) + +/** Legal characters for use in authorized client names for a hidden + * service. */ +#define REND_LEGAL_CLIENTNAME_CHARACTERS \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-_" + +/** Maximum length of authorized client names for a hidden service. */ +#define REND_CLIENTNAME_MAX_LEN 16 + +/** Length of the rendezvous cookie that is used to connect circuits at the + * rendezvous point. */ +#define REND_COOKIE_LEN DIGEST_LEN + +/** Client authorization type that a hidden service performs. */ +typedef enum rend_auth_type_t { + REND_NO_AUTH = 0, + REND_BASIC_AUTH = 1, + REND_STEALTH_AUTH = 2, +} rend_auth_type_t; + +/** Client-side configuration of authorization for a hidden service. */ +typedef struct rend_service_authorization_t { + uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; + char onion_address[REND_SERVICE_ADDRESS_LEN+1]; + rend_auth_type_t auth_type; +} rend_service_authorization_t; + +/** Client- and server-side data that is used for hidden service connection + * establishment. Not all fields contain data depending on where this struct + * is used. */ +typedef struct rend_data_t { + /* Hidden service protocol version of this base object. */ + uint32_t version; + + /** List of HSDir fingerprints on which this request has been sent to. This + * contains binary identity digest of the directory of size DIGEST_LEN. */ + smartlist_t *hsdirs_fp; + + /** Rendezvous cookie used by both, client and service. */ + char rend_cookie[REND_COOKIE_LEN]; + + /** Number of streams associated with this rendezvous circuit. */ + int nr_streams; +} rend_data_t; + +typedef struct rend_data_v2_t { + /* Rendezvous base data. */ + rend_data_t base_; + + /** Onion address (without the .onion part) that a client requests. */ + char onion_address[REND_SERVICE_ID_LEN_BASE32+1]; + + /** Descriptor ID for each replicas computed from the onion address. If + * the onion address is empty, this array MUST be empty. We keep them so + * we know when to purge our entry in the last hsdir request table. */ + char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN]; + + /** (Optional) descriptor cookie that is used by a client. */ + char descriptor_cookie[REND_DESC_COOKIE_LEN]; + + /** Authorization type for accessing a service used by a client. */ + rend_auth_type_t auth_type; + + /** Descriptor ID for a client request. The control port command HSFETCH + * uses this. It's set if the descriptor query should only use this + * descriptor ID. */ + char desc_id_fetch[DIGEST_LEN]; + + /** Hash of the hidden service's PK used by a service. */ + char rend_pk_digest[DIGEST_LEN]; +} rend_data_v2_t; + +/* From a base rend_data_t object <b>d</d>, return the v2 object. */ +static inline +rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d) +{ + tor_assert(d); + tor_assert(d->version == 2); + return DOWNCAST(rend_data_v2_t, d); +} + +/* Stub because we can't include hs_ident.h. */ +struct hs_ident_edge_conn_t; +struct hs_ident_dir_conn_t; +struct hs_ident_circuit_t; + +typedef struct hsdir_index_t hsdir_index_t; + +/** Time interval for tracking replays of DH public keys received in + * INTRODUCE2 cells. Used only to avoid launching multiple + * simultaneous attempts to connect to the same rendezvous point. */ +#define REND_REPLAY_TIME_INTERVAL (5 * 60) + +/** Used to indicate which way a cell is going on a circuit. */ +typedef enum { + CELL_DIRECTION_IN=1, /**< The cell is moving towards the origin. */ + CELL_DIRECTION_OUT=2, /**< The cell is moving away from the origin. */ +} cell_direction_t; + +/** Initial value for both sides of a circuit transmission window when the + * circuit is initialized. Measured in cells. */ +#define CIRCWINDOW_START 1000 +#define CIRCWINDOW_START_MIN 100 +#define CIRCWINDOW_START_MAX 1000 +/** Amount to increment a circuit window when we get a circuit SENDME. */ +#define CIRCWINDOW_INCREMENT 100 +/** Initial value on both sides of a stream transmission window when the + * stream is initialized. Measured in cells. */ +#define STREAMWINDOW_START 500 +#define STREAMWINDOW_START_MAX 500 +/** Amount to increment a stream window when we get a stream SENDME. */ +#define STREAMWINDOW_INCREMENT 50 + +/** Maximum number of queued cells on a circuit for which we are the + * midpoint before we give up and kill it. This must be >= circwindow + * to avoid killing innocent circuits, and >= circwindow*2 to give + * leaky-pipe a chance of working someday. The ORCIRC_MAX_MIDDLE_KILL_THRESH + * ratio controls the margin of error between emitting a warning and + * killing the circuit. + */ +#define ORCIRC_MAX_MIDDLE_CELLS (CIRCWINDOW_START_MAX*2) +/** Ratio of hard (circuit kill) to soft (warning) thresholds for the + * ORCIRC_MAX_MIDDLE_CELLS tests. + */ +#define ORCIRC_MAX_MIDDLE_KILL_THRESH (1.1f) + +/* Cell commands. These values are defined in tor-spec.txt. */ +#define CELL_PADDING 0 +#define CELL_CREATE 1 +#define CELL_CREATED 2 +#define CELL_RELAY 3 +#define CELL_DESTROY 4 +#define CELL_CREATE_FAST 5 +#define CELL_CREATED_FAST 6 +#define CELL_VERSIONS 7 +#define CELL_NETINFO 8 +#define CELL_RELAY_EARLY 9 +#define CELL_CREATE2 10 +#define CELL_CREATED2 11 +#define CELL_PADDING_NEGOTIATE 12 + +#define CELL_VPADDING 128 +#define CELL_CERTS 129 +#define CELL_AUTH_CHALLENGE 130 +#define CELL_AUTHENTICATE 131 +#define CELL_AUTHORIZE 132 +#define CELL_COMMAND_MAX_ 132 + +/** How long to test reachability before complaining to the user. */ +#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60) + +/** Legal characters in a nickname. */ +#define LEGAL_NICKNAME_CHARACTERS \ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + +/** Name to use in client TLS certificates if no nickname is given. Once + * Tor 0.1.2.x is obsolete, we can remove this. */ +#define DEFAULT_CLIENT_NICKNAME "client" + +/** Name chosen by routers that don't configure nicknames */ +#define UNNAMED_ROUTER_NICKNAME "Unnamed" + +/** Number of bytes in a SOCKS4 header. */ +#define SOCKS4_NETWORK_LEN 8 + +/* + * Relay payload: + * Relay command [1 byte] + * Recognized [2 bytes] + * Stream ID [2 bytes] + * Partial SHA-1 [4 bytes] + * Length [2 bytes] + * Relay payload [498 bytes] + */ + +/** Number of bytes in a cell, minus cell header. */ +#define CELL_PAYLOAD_SIZE 509 +/** Number of bytes in a cell transmitted over the network, in the longest + * form */ +#define CELL_MAX_NETWORK_SIZE 514 + +/** Maximum length of a header on a variable-length cell. */ +#define VAR_CELL_MAX_HEADER_SIZE 7 + +static int get_cell_network_size(int wide_circ_ids); +static inline int get_cell_network_size(int wide_circ_ids) +{ + return wide_circ_ids ? CELL_MAX_NETWORK_SIZE : CELL_MAX_NETWORK_SIZE - 2; +} +static int get_var_cell_header_size(int wide_circ_ids); +static inline int get_var_cell_header_size(int wide_circ_ids) +{ + return wide_circ_ids ? VAR_CELL_MAX_HEADER_SIZE : + VAR_CELL_MAX_HEADER_SIZE - 2; +} +static int get_circ_id_size(int wide_circ_ids); +static inline int get_circ_id_size(int wide_circ_ids) +{ + return wide_circ_ids ? 4 : 2; +} + +/** Number of bytes in a relay cell's header (not including general cell + * header). */ +#define RELAY_HEADER_SIZE (1+2+2+4+2) +/** Largest number of bytes that can fit in a relay cell payload. */ +#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) + +/** Identifies a circuit on an or_connection */ +typedef uint32_t circid_t; +/** Identifies a stream on a circuit */ +typedef uint16_t streamid_t; + +/* channel_t typedef; struct channel_s is in channel.h */ + +typedef struct channel_s channel_t; + +/* channel_listener_t typedef; struct channel_listener_s is in channel.h */ + +typedef struct channel_listener_s channel_listener_t; + +/* TLS channel stuff */ + +typedef struct channel_tls_s channel_tls_t; + +/* circuitmux_t typedef; struct circuitmux_s is in circuitmux.h */ + +typedef struct circuitmux_s circuitmux_t; + +typedef struct cell_t cell_t; +typedef struct var_cell_t var_cell_t; +typedef struct packed_cell_t packed_cell_t; +typedef struct cell_queue_t cell_queue_t; +typedef struct destroy_cell_t destroy_cell_t; +typedef struct destroy_cell_queue_t destroy_cell_queue_t; +typedef struct ext_or_cmd_t ext_or_cmd_t; + +/** Beginning of a RELAY cell payload. */ +typedef struct { + uint8_t command; /**< The end-to-end relay command. */ + uint16_t recognized; /**< Used to tell whether cell is for us. */ + streamid_t stream_id; /**< Which stream is this cell associated with? */ + char integrity[4]; /**< Used to tell whether cell is corrupted. */ + uint16_t length; /**< How long is the payload body? */ +} relay_header_t; + +typedef struct socks_request_t socks_request_t; +typedef struct entry_port_cfg_t entry_port_cfg_t; +typedef struct server_port_cfg_t server_port_cfg_t; + +/** Minimum length of the random part of an AUTH_CHALLENGE cell. */ +#define OR_AUTH_CHALLENGE_LEN 32 + +/** + * @name Certificate types for CERTS cells. + * + * These values are defined by the protocol, and affect how an X509 + * certificate in a CERTS cell is interpreted and used. + * + * @{ */ +/** A certificate that authenticates a TLS link key. The subject key + * must match the key used in the TLS handshake; it must be signed by + * the identity key. */ +#define OR_CERT_TYPE_TLS_LINK 1 +/** A self-signed identity certificate. The subject key must be a + * 1024-bit RSA key. */ +#define OR_CERT_TYPE_ID_1024 2 +/** A certificate that authenticates a key used in an AUTHENTICATE cell + * in the v3 handshake. The subject key must be a 1024-bit RSA key; it + * must be signed by the identity key */ +#define OR_CERT_TYPE_AUTH_1024 3 +/* DOCDOC */ +#define OR_CERT_TYPE_RSA_ED_CROSSCERT 7 +/**@}*/ + +/** The first supported type of AUTHENTICATE cell. It contains + * a bunch of structures signed with an RSA1024 key. The signed + * structures include a HMAC using negotiated TLS secrets, and a digest + * of all cells sent or received before the AUTHENTICATE cell (including + * the random server-generated AUTH_CHALLENGE cell). + */ +#define AUTHTYPE_RSA_SHA256_TLSSECRET 1 +/** As AUTHTYPE_RSA_SHA256_TLSSECRET, but instead of using the + * negotiated TLS secrets, uses exported keying material from the TLS + * session as described in RFC 5705. + * + * Not used by today's tors, since everything that supports this + * also supports ED25519_SHA256_5705, which is better. + **/ +#define AUTHTYPE_RSA_SHA256_RFC5705 2 +/** As AUTHTYPE_RSA_SHA256_RFC5705, but uses an Ed25519 identity key to + * authenticate. */ +#define AUTHTYPE_ED25519_SHA256_RFC5705 3 +/* + * NOTE: authchallenge_type_is_better() relies on these AUTHTYPE codes + * being sorted in order of preference. If we someday add one with + * a higher numerical value that we don't like as much, we should revise + * authchallenge_type_is_better(). + */ + +/** The length of the part of the AUTHENTICATE cell body that the client and + * server can generate independently (when using RSA_SHA256_TLSSECRET). It + * contains everything except the client's timestamp, the client's randomly + * generated nonce, and the signature. */ +#define V3_AUTH_FIXED_PART_LEN (8+(32*6)) +/** The length of the part of the AUTHENTICATE cell body that the client + * signs. */ +#define V3_AUTH_BODY_LEN (V3_AUTH_FIXED_PART_LEN + 8 + 16) + +typedef struct or_handshake_certs_t or_handshake_certs_t; +typedef struct or_handshake_state_t or_handshake_state_t; + +/** Length of Extended ORPort connection identifier. */ +#define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */ +/* + * OR_CONN_HIGHWATER and OR_CONN_LOWWATER moved from connection_or.c so + * channeltls.c can see them too. + */ + +/** When adding cells to an OR connection's outbuf, keep adding until the + * outbuf is at least this long, or we run out of cells. */ +#define OR_CONN_HIGHWATER (32*1024) + +/** Add cells to an OR connection's outbuf whenever the outbuf's data length + * drops below this size. */ +#define OR_CONN_LOWWATER (16*1024) + +typedef struct connection_t connection_t; +typedef struct control_connection_t control_connection_t; +typedef struct dir_connection_t dir_connection_t; +typedef struct edge_connection_t edge_connection_t; +typedef struct entry_connection_t entry_connection_t; +typedef struct listener_connection_t listener_connection_t; +typedef struct or_connection_t or_connection_t; + +/** Cast a connection_t subtype pointer to a connection_t **/ +#define TO_CONN(c) (&(((c)->base_))) + +/** Cast a entry_connection_t subtype pointer to a connection_t **/ +#define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c))) + +typedef struct addr_policy_t addr_policy_t; + +typedef struct cached_dir_t cached_dir_t; + +/** Enum used to remember where a signed_descriptor_t is stored and how to + * manage the memory for signed_descriptor_body. */ +typedef enum { + /** The descriptor isn't stored on disk at all: the copy in memory is + * canonical; the saved_offset field is meaningless. */ + SAVED_NOWHERE=0, + /** The descriptor is stored in the cached_routers file: the + * signed_descriptor_body is meaningless; the signed_descriptor_len and + * saved_offset are used to index into the mmaped cache file. */ + SAVED_IN_CACHE, + /** The descriptor is stored in the cached_routers.new file: the + * signed_descriptor_body and saved_offset fields are both set. */ + /* FFFF (We could also mmap the file and grow the mmap as needed, or + * lazy-load the descriptor text by using seek and read. We don't, for + * now.) + */ + SAVED_IN_JOURNAL +} saved_location_t; +#define saved_location_bitfield_t ENUM_BF(saved_location_t) + +/** Enumeration: what directory object is being downloaded? + * This determines which schedule is selected to perform the download. */ +typedef enum { + DL_SCHED_GENERIC = 0, + DL_SCHED_CONSENSUS = 1, + DL_SCHED_BRIDGE = 2, +} download_schedule_t; +#define download_schedule_bitfield_t ENUM_BF(download_schedule_t) + +/** Enumeration: is the download schedule for downloading from an authority, + * or from any available directory mirror? + * During bootstrap, "any" means a fallback (or an authority, if there + * are no fallbacks). + * When we have a valid consensus, "any" means any directory server. */ +typedef enum { + DL_WANT_ANY_DIRSERVER = 0, + DL_WANT_AUTHORITY = 1, +} download_want_authority_t; +#define download_want_authority_bitfield_t \ + ENUM_BF(download_want_authority_t) + +/** Enumeration: do we want to increment the schedule position each time a + * connection is attempted (these attempts can be concurrent), or do we want + * to increment the schedule position after a connection fails? */ +typedef enum { + DL_SCHED_INCREMENT_FAILURE = 0, + DL_SCHED_INCREMENT_ATTEMPT = 1, +} download_schedule_increment_t; +#define download_schedule_increment_bitfield_t \ + ENUM_BF(download_schedule_increment_t) + +typedef struct download_status_t download_status_t; + +/** If n_download_failures is this high, the download can never happen. */ +#define IMPOSSIBLE_TO_DOWNLOAD 255 + +/** The max size we expect router descriptor annotations we create to + * be. We'll accept larger ones if we see them on disk, but we won't + * create any that are larger than this. */ +#define ROUTER_ANNOTATION_BUF_LEN 256 + +typedef struct signed_descriptor_t signed_descriptor_t; + +/** A signed integer representing a country code. */ +typedef int16_t country_t; + +/** Flags used to summarize the declared protocol versions of a relay, + * so we don't need to parse them again and again. */ +typedef struct protover_summary_flags_t { + /** True iff we have a proto line for this router, or a versions line + * from which we could infer the protocols. */ + unsigned int protocols_known:1; + + /** True iff this router has a version or protocol list that allows it to + * accept EXTEND2 cells. This requires Relay=2. */ + unsigned int supports_extend2_cells:1; + + /** True iff this router has a protocol list that allows it to negotiate + * ed25519 identity keys on a link handshake with us. This + * requires LinkAuth=3. */ + unsigned int supports_ed25519_link_handshake_compat:1; + + /** True iff this router has a protocol list that allows it to negotiate + * ed25519 identity keys on a link handshake, at all. This requires some + * LinkAuth=X for X >= 3. */ + unsigned int supports_ed25519_link_handshake_any:1; + + /** True iff this router has a protocol list that allows it to be an + * introduction point supporting ed25519 authentication key which is part of + * the v3 protocol detailed in proposal 224. This requires HSIntro=4. */ + unsigned int supports_ed25519_hs_intro : 1; + + /** True iff this router has a protocol list that allows it to be an hidden + * service directory supporting version 3 as seen in proposal 224. This + * requires HSDir=2. */ + unsigned int supports_v3_hsdir : 1; + + /** True iff this router has a protocol list that allows it to be an hidden + * service rendezvous point supporting version 3 as seen in proposal 224. + * This requires HSRend=2. */ + unsigned int supports_v3_rendezvous_point: 1; +} protover_summary_flags_t; + +typedef struct routerinfo_t routerinfo_t; +typedef struct extrainfo_t extrainfo_t; +typedef struct routerstatus_t routerstatus_t; + +typedef struct microdesc_t microdesc_t; +typedef struct node_t node_t; +typedef struct vote_microdesc_hash_t vote_microdesc_hash_t; +typedef struct vote_routerstatus_t vote_routerstatus_t; +typedef struct document_signature_t document_signature_t; +typedef struct networkstatus_voter_info_t networkstatus_voter_info_t; +typedef struct networkstatus_sr_info_t networkstatus_sr_info_t; + +/** Enumerates recognized flavors of a consensus networkstatus document. All + * flavors of a consensus are generated from the same set of votes, but they + * present different types information to different versions of Tor. */ +typedef enum { + FLAV_NS = 0, + FLAV_MICRODESC = 1, +} consensus_flavor_t; + +/** How many different consensus flavors are there? */ +#define N_CONSENSUS_FLAVORS ((int)(FLAV_MICRODESC)+1) + +typedef struct networkstatus_t networkstatus_t; +typedef struct ns_detached_signatures_t ns_detached_signatures_t; +typedef struct desc_store_t desc_store_t; +typedef struct routerlist_t routerlist_t; +typedef struct extend_info_t extend_info_t; +typedef struct authority_cert_t authority_cert_t; + +/** Bitfield enum type listing types of information that directory authorities + * can be authoritative about, and that directory caches may or may not cache. + * + * Note that the granularity here is based on authority granularity and on + * cache capabilities. Thus, one particular bit may correspond in practice to + * a few types of directory info, so long as every authority that pronounces + * officially about one of the types prounounces officially about all of them, + * and so long as every cache that caches one of them caches all of them. + */ +typedef enum { + NO_DIRINFO = 0, + /** Serves/signs v3 directory information: votes, consensuses, certs */ + V3_DIRINFO = 1 << 2, + /** Serves bridge descriptors. */ + BRIDGE_DIRINFO = 1 << 4, + /** Serves extrainfo documents. */ + EXTRAINFO_DIRINFO=1 << 5, + /** Serves microdescriptors. */ + MICRODESC_DIRINFO=1 << 6, +} dirinfo_type_t; + +#define ALL_DIRINFO ((dirinfo_type_t)((1<<7)-1)) + +#define ONION_HANDSHAKE_TYPE_TAP 0x0000 +#define ONION_HANDSHAKE_TYPE_FAST 0x0001 +#define ONION_HANDSHAKE_TYPE_NTOR 0x0002 +#define MAX_ONION_HANDSHAKE_TYPE 0x0002 + +typedef struct onion_handshake_state_t onion_handshake_state_t; +typedef struct relay_crypto_t relay_crypto_t; +typedef struct crypt_path_t crypt_path_t; +typedef struct crypt_path_reference_t crypt_path_reference_t; + +#define CPATH_KEY_MATERIAL_LEN (20*2+16*2) + +typedef struct cpath_build_state_t cpath_build_state_t; + +struct create_cell_t; + +/** Entry in the cell stats list of a circuit; used only if CELL_STATS + * events are enabled. */ +typedef struct testing_cell_stats_entry_t { + uint8_t command; /**< cell command number. */ + /** Waiting time in centiseconds if this event is for a removed cell, + * or 0 if this event is for adding a cell to the queue. 22 bits can + * store more than 11 hours, enough to assume that a circuit with this + * delay would long have been closed. */ + unsigned int waiting_time:22; + unsigned int removed:1; /**< 0 for added to, 1 for removed from queue. */ + unsigned int exitward:1; /**< 0 for app-ward, 1 for exit-ward. */ +} testing_cell_stats_entry_t; + +typedef struct circuit_t circuit_t; +typedef struct origin_circuit_t origin_circuit_t; +typedef struct or_circuit_t or_circuit_t; + +/** Largest number of relay_early cells that we can send on a given + * circuit. */ +#define MAX_RELAY_EARLY_CELLS_PER_CIRCUIT 8 + +typedef enum path_state_t path_state_t; +#define path_state_bitfield_t ENUM_BF(path_state_t) + +#if REND_COOKIE_LEN != DIGEST_LEN +#error "The REND_TOKEN_LEN macro assumes REND_COOKIE_LEN == DIGEST_LEN" +#endif +#define REND_TOKEN_LEN DIGEST_LEN + +/** Convert a circuit subtype to a circuit_t. */ +#define TO_CIRCUIT(x) (&((x)->base_)) + +/** @name Isolation flags + + Ways to isolate client streams + + @{ +*/ +/** Isolate based on destination port */ +#define ISO_DESTPORT (1u<<0) +/** Isolate based on destination address */ +#define ISO_DESTADDR (1u<<1) +/** Isolate based on SOCKS authentication */ +#define ISO_SOCKSAUTH (1u<<2) +/** Isolate based on client protocol choice */ +#define ISO_CLIENTPROTO (1u<<3) +/** Isolate based on client address */ +#define ISO_CLIENTADDR (1u<<4) +/** Isolate based on session group (always on). */ +#define ISO_SESSIONGRP (1u<<5) +/** Isolate based on newnym epoch (always on). */ +#define ISO_NYM_EPOCH (1u<<6) +/** Isolate all streams (Internal only). */ +#define ISO_STREAM (1u<<7) +/**@}*/ + +/** Default isolation level for ports. */ +#define ISO_DEFAULT (ISO_CLIENTADDR|ISO_SOCKSAUTH|ISO_SESSIONGRP|ISO_NYM_EPOCH) + +/** Indicates that we haven't yet set a session group on a port_cfg_t. */ +#define SESSION_GROUP_UNSET -1 +/** Session group reserved for directory connections */ +#define SESSION_GROUP_DIRCONN -2 +/** Session group reserved for resolve requests launched by a controller */ +#define SESSION_GROUP_CONTROL_RESOLVE -3 +/** First automatically allocated session group number */ +#define SESSION_GROUP_FIRST_AUTO -4 + +typedef struct port_cfg_t port_cfg_t; +typedef struct routerset_t routerset_t; + +/** A magic value for the (Socks|OR|...)Port options below, telling Tor + * to pick its own port. */ +#define CFG_AUTO_PORT 0xc4005e + +typedef struct or_options_t or_options_t; + +#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level()) + +typedef struct or_state_t or_state_t; + +#define MAX_SOCKS_ADDR_LEN 256 + +/********************************* circuitbuild.c **********************/ + +/** How many hops does a general-purpose circuit have by default? */ +#define DEFAULT_ROUTE_LEN 3 + +/* Circuit Build Timeout "public" structures. */ + +/** Precision multiplier for the Bw weights */ +#define BW_WEIGHT_SCALE 10000 +#define BW_MIN_WEIGHT_SCALE 1 +#define BW_MAX_WEIGHT_SCALE INT32_MAX + +typedef struct circuit_build_times_s circuit_build_times_t; + +/********************************* config.c ***************************/ + +/********************************* connection_edge.c *************************/ + +/** Enumerates possible origins of a client-side address mapping. */ +typedef enum { + /** We're remapping this address because the controller told us to. */ + ADDRMAPSRC_CONTROLLER, + /** We're remapping this address because of an AutomapHostsOnResolve + * configuration. */ + ADDRMAPSRC_AUTOMAP, + /** We're remapping this address because our configuration (via torrc, the + * command line, or a SETCONF command) told us to. */ + ADDRMAPSRC_TORRC, + /** We're remapping this address because we have TrackHostExit configured, + * and we want to remember to use the same exit next time. */ + ADDRMAPSRC_TRACKEXIT, + /** We're remapping this address because we got a DNS resolution from a + * Tor server that told us what its value was. */ + ADDRMAPSRC_DNS, + + /** No remapping has occurred. This isn't a possible value for an + * addrmap_entry_t; it's used as a null value when we need to answer "Why + * did this remapping happen." */ + ADDRMAPSRC_NONE +} addressmap_entry_source_t; +#define addressmap_entry_source_bitfield_t ENUM_BF(addressmap_entry_source_t) + +#define WRITE_STATS_INTERVAL (24*60*60) + +/********************************* dirvote.c ************************/ + +typedef struct vote_timing_t vote_timing_t; + +/********************************* microdesc.c *************************/ + +typedef struct microdesc_cache_t microdesc_cache_t; + +/********************************* rendcommon.c ***************************/ + +typedef struct rend_authorized_client_t rend_authorized_client_t; +typedef struct rend_encoded_v2_service_descriptor_t + rend_encoded_v2_service_descriptor_t; + +/** The maximum number of non-circuit-build-timeout failures a hidden + * service client will tolerate while trying to build a circuit to an + * introduction point. See also rend_intro_point_t.unreachable_count. */ +#define MAX_INTRO_POINT_REACHABILITY_FAILURES 5 + +/** The minimum and maximum number of distinct INTRODUCE2 cells which a + * hidden service's introduction point will receive before it begins to + * expire. */ +#define INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS 16384 +/* Double the minimum value so the interval is [min, min * 2]. */ +#define INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS \ + (INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS * 2) + +/** The minimum number of seconds that an introduction point will last + * before expiring due to old age. (If it receives + * INTRO_POINT_LIFETIME_INTRODUCTIONS INTRODUCE2 cells, it may expire + * sooner.) + * + * XXX Should this be configurable? */ +#define INTRO_POINT_LIFETIME_MIN_SECONDS (18*60*60) +/** The maximum number of seconds that an introduction point will last + * before expiring due to old age. + * + * XXX Should this be configurable? */ +#define INTRO_POINT_LIFETIME_MAX_SECONDS (24*60*60) + +/** The maximum number of circuit creation retry we do to an intro point + * before giving up. We try to reuse intro point that fails during their + * lifetime so this is a hard limit on the amount of time we do that. */ +#define MAX_INTRO_POINT_CIRCUIT_RETRIES 3 + +typedef struct rend_intro_point_t rend_intro_point_t; +typedef struct rend_service_descriptor_t rend_service_descriptor_t; + +/********************************* routerlist.c ***************************/ + +typedef struct dir_server_t dir_server_t; + +#define RELAY_REQUIRED_MIN_BANDWIDTH (75*1024) +#define BRIDGE_REQUIRED_MIN_BANDWIDTH (50*1024) + +#define ROUTER_MAX_DECLARED_BANDWIDTH INT32_MAX + +typedef struct tor_version_t tor_version_t; + +#endif /* !defined(TOR_OR_H) */ diff --git a/src/core/or/or_circuit_st.h b/src/core/or/or_circuit_st.h new file mode 100644 index 0000000000..b5e21d9867 --- /dev/null +++ b/src/core/or/or_circuit_st.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_CIRCUIT_ST_H +#define OR_CIRCUIT_ST_H + +#include "core/or/or.h" + +#include "core/or/circuit_st.h" +#include "core/or/crypt_path_st.h" + +struct onion_queue_t; + +/** An or_circuit_t holds information needed to implement a circuit at an + * OR. */ +struct or_circuit_t { + circuit_t base_; + + /** Pointer to an entry on the onion queue, if this circuit is waiting for a + * chance to give an onionskin to a cpuworker. Used only in onion.c */ + struct onion_queue_t *onionqueue_entry; + /** Pointer to a workqueue entry, if this circuit has given an onionskin to + * a cpuworker and is waiting for a response. Used to decide whether it is + * safe to free a circuit or if it is still in use by a cpuworker. */ + struct workqueue_entry_s *workqueue_entry; + + /** The circuit_id used in the previous (backward) hop of this circuit. */ + circid_t p_circ_id; + /** Queue of cells waiting to be transmitted on p_conn. */ + cell_queue_t p_chan_cells; + /** The channel that is previous in this circuit. */ + channel_t *p_chan; + /** + * Circuit mux associated with p_chan to which this circuit is attached; + * NULL if we have no p_chan. + */ + circuitmux_t *p_mux; + /** Linked list of Exit streams associated with this circuit. */ + edge_connection_t *n_streams; + /** Linked list of Exit streams associated with this circuit that are + * still being resolved. */ + edge_connection_t *resolving_streams; + + /** Cryptographic state used for encrypting and authenticating relay + * cells to and from this hop. */ + relay_crypto_t crypto; + + /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit + * is not marked for close. */ + struct or_circuit_t *rend_splice; + + /** Stores KH for the handshake. */ + char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ + + /** How many more relay_early cells can we send on this circuit, according + * to the specification? */ + unsigned int remaining_relay_early_cells : 4; + + /* We have already received an INTRODUCE1 cell on this circuit. */ + unsigned int already_received_introduce1 : 1; + + /** If set, this circuit carries HS traffic. Consider it in any HS + * statistics. */ + unsigned int circuit_carries_hs_traffic_stats : 1; + + /** Number of cells that were removed from circuit queue; reset every + * time when writing buffer stats to disk. */ + uint32_t processed_cells; + + /** Total time in milliseconds that cells spent in both app-ward and + * exit-ward queues of this circuit; reset every time when writing + * buffer stats to disk. */ + uint64_t total_cell_waiting_time; +}; + +#endif + diff --git a/src/core/or/or_connection_st.h b/src/core/or/or_connection_st.h new file mode 100644 index 0000000000..020a717c11 --- /dev/null +++ b/src/core/or/or_connection_st.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_CONNECTION_ST_H +#define OR_CONNECTION_ST_H + +#include "core/or/connection_st.h" +#include "lib/evloop/token_bucket.h" + +struct tor_tls_t; + +/** Subtype of connection_t for an "OR connection" -- that is, one that speaks + * cells over TLS. */ +struct or_connection_t { + connection_t base_; + + /** Hash of the public RSA key for the other side's identity key, or zeroes + * if the other side hasn't shown us a valid identity key. */ + char identity_digest[DIGEST_LEN]; + + /** Extended ORPort connection identifier. */ + char *ext_or_conn_id; + /** This is the ClientHash value we expect to receive from the + * client during the Extended ORPort authentication protocol. We + * compute it upon receiving the ClientNoce from the client, and we + * compare it with the acual ClientHash value sent by the + * client. */ + char *ext_or_auth_correct_client_hash; + /** String carrying the name of the pluggable transport + * (e.g. "obfs2") that is obfuscating this connection. If no + * pluggable transports are used, it's NULL. */ + char *ext_or_transport; + + char *nickname; /**< Nickname of OR on other side (if any). */ + + struct tor_tls_t *tls; /**< TLS connection state. */ + int tls_error; /**< Last tor_tls error code. */ + /** When we last used this conn for any client traffic. If not + * recent, we can rate limit it further. */ + + /* Channel using this connection */ + channel_tls_t *chan; + + tor_addr_t real_addr; /**< The actual address that this connection came from + * or went to. The <b>addr</b> field is prone to + * getting overridden by the address from the router + * descriptor matching <b>identity_digest</b>. */ + + /** Should this connection be used for extending circuits to the server + * matching the <b>identity_digest</b> field? Set to true if we're pretty + * sure we aren't getting MITMed, either because we're connected to an + * address listed in a server descriptor, or because an authenticated + * NETINFO cell listed the address we're connected to as recognized. */ + unsigned int is_canonical:1; + + /** True iff this is an outgoing connection. */ + unsigned int is_outgoing:1; + unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ + unsigned int wide_circ_ids:1; + /** True iff this connection has had its bootstrap failure logged with + * control_event_bootstrap_problem. */ + unsigned int have_noted_bootstrap_problem:1; + /** True iff this is a client connection and its address has been put in the + * geoip cache and handled by the DoS mitigation subsystem. We use this to + * insure we have a coherent count of concurrent connection. */ + unsigned int tracked_for_dos_mitigation : 1; + + uint16_t link_proto; /**< What protocol version are we using? 0 for + * "none negotiated yet." */ + uint16_t idle_timeout; /**< How long can this connection sit with no + * circuits on it before we close it? Based on + * IDLE_CIRCUIT_TIMEOUT_{NON,}CANONICAL and + * on is_canonical, randomized. */ + or_handshake_state_t *handshake_state; /**< If we are setting this connection + * up, state information to do so. */ + + time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/ + + token_bucket_rw_t bucket; /**< Used for rate limiting when the connection is + * in state CONN_OPEN. */ + + /* + * Count the number of bytes flushed out on this orconn, and the number of + * bytes TLS actually sent - used for overhead estimation for scheduling. + */ + uint64_t bytes_xmitted, bytes_xmitted_by_tls; +}; + +#endif diff --git a/src/core/or/or_handshake_certs_st.h b/src/core/or/or_handshake_certs_st.h new file mode 100644 index 0000000000..38e798b5e2 --- /dev/null +++ b/src/core/or/or_handshake_certs_st.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_HANDSHAKE_CERTS_ST +#define OR_HANDSHAKE_CERTS_ST + +struct tor_x509_cert_t; + +/** Structure to hold all the certificates we've received on an OR connection + */ +struct or_handshake_certs_t { + /** True iff we originated this connection. */ + int started_here; + /** The cert for the 'auth' RSA key that's supposed to sign the AUTHENTICATE + * cell. Signed with the RSA identity key. */ + struct tor_x509_cert_t *auth_cert; + /** The cert for the 'link' RSA key that was used to negotiate the TLS + * connection. Signed with the RSA identity key. */ + struct tor_x509_cert_t *link_cert; + /** A self-signed identity certificate: the RSA identity key signed + * with itself. */ + struct tor_x509_cert_t *id_cert; + /** The Ed25519 signing key, signed with the Ed25519 identity key. */ + struct tor_cert_st *ed_id_sign; + /** A digest of the X509 link certificate for the TLS connection, signed + * with the Ed25519 siging key. */ + struct tor_cert_st *ed_sign_link; + /** The Ed25519 authentication key (that's supposed to sign an AUTHENTICATE + * cell) , signed with the Ed25519 siging key. */ + struct tor_cert_st *ed_sign_auth; + /** The Ed25519 identity key, crosssigned with the RSA identity key. */ + uint8_t *ed_rsa_crosscert; + /** The length of <b>ed_rsa_crosscert</b> in bytes */ + size_t ed_rsa_crosscert_len; +}; + +#endif diff --git a/src/core/or/or_handshake_state_st.h b/src/core/or/or_handshake_state_st.h new file mode 100644 index 0000000000..4ee095d9af --- /dev/null +++ b/src/core/or/or_handshake_state_st.h @@ -0,0 +1,78 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef OR_HANDSHAKE_STATE_ST +#define OR_HANDSHAKE_STATE_ST + +/** Stores flags and information related to the portion of a v2/v3 Tor OR + * connection handshake that happens after the TLS handshake is finished. + */ +struct or_handshake_state_t { + /** When was the VERSIONS cell sent on this connection? Used to get + * an estimate of the skew in the returning NETINFO reply. */ + time_t sent_versions_at; + /** True iff we originated this connection */ + unsigned int started_here : 1; + /** True iff we have received and processed a VERSIONS cell. */ + unsigned int received_versions : 1; + /** True iff we have received and processed an AUTH_CHALLENGE cell */ + unsigned int received_auth_challenge : 1; + /** True iff we have received and processed a CERTS cell. */ + unsigned int received_certs_cell : 1; + /** True iff we have received and processed an AUTHENTICATE cell */ + unsigned int received_authenticate : 1; + + /* True iff we've received valid authentication to some identity. */ + unsigned int authenticated : 1; + unsigned int authenticated_rsa : 1; + unsigned int authenticated_ed25519 : 1; + + /* True iff we have sent a netinfo cell */ + unsigned int sent_netinfo : 1; + + /** The signing->ed25519 link certificate corresponding to the x509 + * certificate we used on the TLS connection (if this is a server-side + * connection). We make a copy of this here to prevent a race condition + * caused by TLS context rotation. */ + struct tor_cert_st *own_link_cert; + + /** True iff we should feed outgoing cells into digest_sent and + * digest_received respectively. + * + * From the server's side of the v3 handshake, we want to capture everything + * from the VERSIONS cell through and including the AUTH_CHALLENGE cell. + * From the client's, we want to capture everything from the VERSIONS cell + * through but *not* including the AUTHENTICATE cell. + * + * @{ */ + unsigned int digest_sent_data : 1; + unsigned int digest_received_data : 1; + /**@}*/ + + /** Identity RSA digest that we have received and authenticated for our peer + * on this connection. */ + uint8_t authenticated_rsa_peer_id[DIGEST_LEN]; + /** Identity Ed25519 public key that we have received and authenticated for + * our peer on this connection. */ + ed25519_public_key_t authenticated_ed25519_peer_id; + + /** Digests of the cells that we have sent or received as part of a V3 + * handshake. Used for making and checking AUTHENTICATE cells. + * + * @{ + */ + crypto_digest_t *digest_sent; + crypto_digest_t *digest_received; + /** @} */ + + /** Certificates that a connection initiator sent us in a CERTS cell; we're + * holding on to them until we get an AUTHENTICATE cell. + */ + or_handshake_certs_t *certs; +}; + +#endif + diff --git a/src/core/or/origin_circuit_st.h b/src/core/or/origin_circuit_st.h new file mode 100644 index 0000000000..e7b864e825 --- /dev/null +++ b/src/core/or/origin_circuit_st.h @@ -0,0 +1,290 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ORIGIN_CIRCUIT_ST_H +#define ORIGIN_CIRCUIT_ST_H + +#include "core/or/or.h" + +#include "core/or/circuit_st.h" + +struct onion_queue_t; + +/** + * Describes the circuit building process in simplified terms based + * on the path bias accounting state for a circuit. + * + * NOTE: These state values are enumerated in the order for which we + * expect circuits to transition through them. If you add states, + * you need to preserve this overall ordering. The various pathbias + * state transition and accounting functions (pathbias_mark_* and + * pathbias_count_*) contain ordinal comparisons to enforce proper + * state transitions for corrections. + * + * This state machine and the associated logic was created to prevent + * miscounting due to unknown cases of circuit reuse. See also tickets + * #6475 and #7802. + */ +enum path_state_t { + /** This circuit is "new". It has not yet completed a first hop + * or been counted by the path bias code. */ + PATH_STATE_NEW_CIRC = 0, + /** This circuit has completed one/two hops, and has been counted by + * the path bias logic. */ + PATH_STATE_BUILD_ATTEMPTED = 1, + /** This circuit has been completely built */ + PATH_STATE_BUILD_SUCCEEDED = 2, + /** Did we try to attach any SOCKS streams or hidserv introductions to + * this circuit? + * + * Note: If we ever implement end-to-end stream timing through test + * stream probes (#5707), we must *not* set this for those probes + * (or any other automatic streams) because the adversary could + * just tag at a later point. + */ + PATH_STATE_USE_ATTEMPTED = 3, + /** Did any SOCKS streams or hidserv introductions actually succeed on + * this circuit? + * + * If any streams detatch/fail from this circuit, the code transitions + * the circuit back to PATH_STATE_USE_ATTEMPTED to ensure we probe. See + * pathbias_mark_use_rollback() for that. + */ + PATH_STATE_USE_SUCCEEDED = 4, + + /** + * This is a special state to indicate that we got a corrupted + * relay cell on a circuit and we don't intend to probe it. + */ + PATH_STATE_USE_FAILED = 5, + + /** + * This is a special state to indicate that we already counted + * the circuit. Used to guard against potential state machine + * violations. + */ + PATH_STATE_ALREADY_COUNTED = 6, +}; + +/** An origin_circuit_t holds data necessary to build and use a circuit. + */ +struct origin_circuit_t { + circuit_t base_; + + /** Linked list of AP streams (or EXIT streams if hidden service) + * associated with this circuit. */ + edge_connection_t *p_streams; + + /** Bytes read on this circuit since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_read_circ_bw; + + /** Bytes written to on this circuit since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_written_circ_bw; + + /** Total known-valid relay cell bytes since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_delivered_read_circ_bw; + + /** Total written relay cell bytes since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_delivered_written_circ_bw; + + /** Total overhead data in all known-valid relay data cells since last + * call to control_event_circ_bandwidth_used(). Only used if we're + * configured to emit CIRC_BW events. */ + uint32_t n_overhead_read_circ_bw; + + /** Total written overhead data in all relay data cells since last call to + * control_event_circ_bandwidth_used(). Only used if we're configured + * to emit CIRC_BW events. */ + uint32_t n_overhead_written_circ_bw; + + /** Build state for this circuit. It includes the intended path + * length, the chosen exit router, rendezvous information, etc. + */ + cpath_build_state_t *build_state; + /** The doubly-linked list of crypt_path_t entries, one per hop, + * for this circuit. This includes ciphers for each hop, + * integrity-checking digests for each hop, and package/delivery + * windows for each hop. + */ + crypt_path_t *cpath; + + /** Holds all rendezvous data on either client or service side. */ + rend_data_t *rend_data; + + /** Holds hidden service identifier on either client or service side. This + * is for both introduction and rendezvous circuit. */ + struct hs_ident_circuit_t *hs_ident; + + /** Holds the data that the entry guard system uses to track the + * status of the guard this circuit is using, and thereby to determine + * whether this circuit can be used. */ + struct circuit_guard_state_t *guard_state; + + /** Index into global_origin_circuit_list for this circuit. -1 if not + * present. */ + int global_origin_circuit_list_idx; + + /** How many more relay_early cells can we send on this circuit, according + * to the specification? */ + unsigned int remaining_relay_early_cells : 4; + + /** Set if this circuit is insanely old and we already informed the user */ + unsigned int is_ancient : 1; + + /** Set if this circuit has already been opened. Used to detect + * cannibalized circuits. */ + unsigned int has_opened : 1; + + /** + * Path bias state machine. Used to ensure integrity of our + * circuit building and usage accounting. See path_state_t + * for more details. + */ + path_state_bitfield_t path_state : 3; + + /* If this flag is set, we should not consider attaching any more + * connections to this circuit. */ + unsigned int unusable_for_new_conns : 1; + + /** + * Tristate variable to guard against pathbias miscounting + * due to circuit purpose transitions changing the decision + * of pathbias_should_count(). This variable is informational + * only. The current results of pathbias_should_count() are + * the official decision for pathbias accounting. + */ + uint8_t pathbias_shouldcount; +#define PATHBIAS_SHOULDCOUNT_UNDECIDED 0 +#define PATHBIAS_SHOULDCOUNT_IGNORED 1 +#define PATHBIAS_SHOULDCOUNT_COUNTED 2 + + /** For path probing. Store the temporary probe stream ID + * for response comparison */ + streamid_t pathbias_probe_id; + + /** For path probing. Store the temporary probe address nonce + * (in host byte order) for response comparison. */ + uint32_t pathbias_probe_nonce; + + /** Set iff this is a hidden-service circuit which has timed out + * according to our current circuit-build timeout, but which has + * been kept around because it might still succeed in connecting to + * its destination, and which is not a fully-connected rendezvous + * circuit. + * + * (We clear this flag for client-side rendezvous circuits when they + * are 'joined' to the other side's rendezvous circuit, so that + * connection_ap_handshake_attach_circuit can put client streams on + * the circuit. We also clear this flag for service-side rendezvous + * circuits when they are 'joined' to a client's rend circ, but only + * for symmetry with the client case. Client-side introduction + * circuits are closed when we get a joined rend circ, and + * service-side introduction circuits never have this flag set.) */ + unsigned int hs_circ_has_timed_out : 1; + + /** Set iff this circuit has been given a relaxed timeout because + * no circuits have opened. Used to prevent spamming logs. */ + unsigned int relaxed_timeout : 1; + + /** Set iff this is a service-side rendezvous circuit for which a + * new connection attempt has been launched. We consider launching + * a new service-side rend circ to a client when the previous one + * fails; now that we don't necessarily close a service-side rend + * circ when we launch a new one to the same client, this flag keeps + * us from launching two retries for the same failed rend circ. */ + unsigned int hs_service_side_rend_circ_has_been_relaunched : 1; + + /** What commands were sent over this circuit that decremented the + * RELAY_EARLY counter? This is for debugging task 878. */ + uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT]; + + /** How many RELAY_EARLY cells have been sent over this circuit? This is + * for debugging task 878, too. */ + int relay_early_cells_sent; + + /** The next stream_id that will be tried when we're attempting to + * construct a new AP stream originating at this circuit. */ + streamid_t next_stream_id; + + /* The intro key replaces the hidden service's public key if purpose is + * S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous + * descriptor is used. */ + crypto_pk_t *intro_key; + + /** Quasi-global identifier for this circuit; used for control.c */ + /* XXXX NM This can get re-used after 2**32 circuits. */ + uint32_t global_identifier; + + /** True if we have associated one stream to this circuit, thereby setting + * the isolation parameters for this circuit. Note that this doesn't + * necessarily mean that we've <em>attached</em> any streams to the circuit: + * we may only have marked up this circuit during the launch process. + */ + unsigned int isolation_values_set : 1; + /** True iff any stream has <em>ever</em> been attached to this circuit. + * + * In a better world we could use timestamp_dirty for this, but + * timestamp_dirty is far too overloaded at the moment. + */ + unsigned int isolation_any_streams_attached : 1; + + /** A bitfield of ISO_* flags for every isolation field such that this + * circuit has had streams with more than one value for that field + * attached to it. */ + uint8_t isolation_flags_mixed; + + /** @name Isolation parameters + * + * If any streams have been associated with this circ (isolation_values_set + * == 1), and all streams associated with the circuit have had the same + * value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these + * elements hold the value for that field. + * + * Note again that "associated" is not the same as "attached": we + * preliminarily associate streams with a circuit while the circuit is being + * launched, so that we can tell whether we need to launch more circuits. + * + * @{ + */ + uint8_t client_proto_type; + uint8_t client_proto_socksver; + uint16_t dest_port; + tor_addr_t client_addr; + char *dest_address; + int session_group; + unsigned nym_epoch; + size_t socks_username_len; + uint8_t socks_password_len; + /* Note that the next two values are NOT NUL-terminated; see + socks_username_len and socks_password_len for their lengths. */ + char *socks_username; + char *socks_password; + /** Global identifier for the first stream attached here; used by + * ISO_STREAM. */ + uint64_t associated_isolated_stream_global_id; + /**@}*/ + /** A list of addr_policy_t for this circuit in particular. Used by + * adjust_exit_policy_from_exitpolicy_failure. + */ + smartlist_t *prepend_policy; + + /** How long do we wait before closing this circuit if it remains + * completely idle after it was built, in seconds? This value + * is randomized on a per-circuit basis from CircuitsAvailableTimoeut + * to 2*CircuitsAvailableTimoeut. */ + int circuit_idle_timeout; + +}; + +#endif diff --git a/src/or/policies.c b/src/core/or/policies.c index 1210ca687d..e01415f95e 100644 --- a/src/or/policies.c +++ b/src/core/or/policies.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,18 +17,27 @@ #define POLICIES_PRIVATE -#include "or.h" -#include "bridges.h" -#include "config.h" -#include "dirserv.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerparse.h" -#include "geoip.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "app/config/config.h" +#include "feature/dircache/dirserv.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerparse.h" +#include "feature/stats/geoip.h" #include "ht.h" +#include "lib/encoding/confline.h" + +#include "core/or/addr_policy_st.h" +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/port_cfg_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" /** Policy that addresses for incoming SOCKS connections must match. */ static smartlist_t *socks_policy = NULL; @@ -2401,7 +2410,7 @@ policy_summary_item_split(policy_summary_item_t* old, uint16_t new_starts) #define REJECT_CUTOFF_SCALE_IPV4 (0) /* Ports are rejected in an IPv4 summary if they are rejected in more than two * IPv4 /8 address blocks */ -#define REJECT_CUTOFF_COUNT_IPV4 (U64_LITERAL(1) << \ +#define REJECT_CUTOFF_COUNT_IPV4 (UINT64_C(1) << \ (IPV4_BITS - REJECT_CUTOFF_SCALE_IPV4 - 7)) #define IPV6_BITS (128) @@ -2413,7 +2422,7 @@ policy_summary_item_split(policy_summary_item_t* old, uint16_t new_starts) * some scattered smaller blocks) have been allocated to the RIRs. * Network providers are typically allocated one or more IPv6 /32s. */ -#define REJECT_CUTOFF_COUNT_IPV6 (U64_LITERAL(1) << \ +#define REJECT_CUTOFF_COUNT_IPV6 (UINT64_C(1) << \ (IPV6_BITS - REJECT_CUTOFF_SCALE_IPV6 - 16)) /** Split an exit policy summary so that prt_min and prt_max @@ -2508,7 +2517,7 @@ policy_summary_reject(smartlist_t *summary, * in the range. */ count = UINT64_MAX; } else { - count = (U64_LITERAL(1) << (addrbits - scale - maskbits)); + count = (UINT64_C(1) << (addrbits - scale - maskbits)); } tor_assert_nonfatal_once(count > 0); while (i < smartlist_len(summary) && @@ -3136,4 +3145,3 @@ policies_free_all(void) } HT_CLEAR(policy_map, &policy_root); } - diff --git a/src/or/policies.h b/src/core/or/policies.h index 4879acdd8d..7da3ba031f 100644 --- a/src/or/policies.h +++ b/src/core/or/policies.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -34,6 +34,39 @@ typedef enum firewall_connection_t { typedef int exit_policy_parser_cfg_t; +/** Outcome of applying an address policy to an address. */ +typedef enum { + /** The address was accepted */ + ADDR_POLICY_ACCEPTED=0, + /** The address was rejected */ + ADDR_POLICY_REJECTED=-1, + /** Part of the address was unknown, but as far as we can tell, it was + * accepted. */ + ADDR_POLICY_PROBABLY_ACCEPTED=1, + /** Part of the address was unknown, but as far as we can tell, it was + * rejected. */ + ADDR_POLICY_PROBABLY_REJECTED=2, +} addr_policy_result_t; + +/** A single entry in a parsed policy summary, describing a range of ports. */ +typedef struct short_policy_entry_t { + uint16_t min_port, max_port; +} short_policy_entry_t; + +/** A short_poliy_t is the parsed version of a policy summary. */ +typedef struct short_policy_t { + /** True if the members of 'entries' are port ranges to accept; false if + * they are port ranges to reject */ + unsigned int is_accept : 1; + /** The actual number of values in 'entries'. */ + unsigned int n_entries : 31; + /** An array of 0 or more short_policy_entry_t values, each describing a + * range of ports that this policy accepts or rejects (depending on the + * value of is_accept). + */ + short_policy_entry_t entries[FLEXIBLE_ARRAY_MEMBER]; +} short_policy_t; + int firewall_is_fascist_or(void); int firewall_is_fascist_dir(void); int fascist_firewall_use_ipv6(const or_options_t *options); @@ -88,7 +121,8 @@ int policies_parse_exit_policy_from_options( uint32_t local_address, const tor_addr_t *ipv6_local_address, smartlist_t **result); -int policies_parse_exit_policy(config_line_t *cfg, smartlist_t **dest, +struct config_line_t; +int policies_parse_exit_policy(struct config_line_t *cfg, smartlist_t **dest, exit_policy_parser_cfg_t options, const smartlist_t *configured_addresses); void policies_parse_exit_policy_reject_private( @@ -151,4 +185,3 @@ STATIC const tor_addr_port_t * fascist_firewall_choose_address( #endif /* defined(POLICIES_PRIVATE) */ #endif /* !defined(TOR_POLICIES_H) */ - diff --git a/src/core/or/port_cfg_st.h b/src/core/or/port_cfg_st.h new file mode 100644 index 0000000000..19410871ed --- /dev/null +++ b/src/core/or/port_cfg_st.h @@ -0,0 +1,35 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef PORT_CFG_ST_H +#define PORT_CFG_ST_H + +#include "core/or/entry_port_cfg_st.h" +#include "core/or/server_port_cfg_st.h" + +/** Configuration for a single port that we're listening on. */ +struct port_cfg_t { + tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */ + int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its + * own port. */ + uint8_t type; /**< One of CONN_TYPE_*_LISTENER */ + unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */ + + unsigned is_group_writable : 1; + unsigned is_world_writable : 1; + unsigned relax_dirmode_check : 1; + + entry_port_cfg_t entry_cfg; + + server_port_cfg_t server_cfg; + + /* Unix sockets only: */ + /** Path for an AF_UNIX address */ + char unix_addr[FLEXIBLE_ARRAY_MEMBER]; +}; + +#endif + diff --git a/src/or/protover.c b/src/core/or/protover.c index 0e8902196d..362a5becac 100644 --- a/src/or/protover.c +++ b/src/core/or/protover.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,9 +23,9 @@ #define PROTOVER_PRIVATE -#include "or.h" -#include "protover.h" -#include "routerparse.h" +#include "core/or/or.h" +#include "core/or/protover.h" +#include "feature/nodelist/routerparse.h" #ifndef HAVE_RUST diff --git a/src/or/protover.h b/src/core/or/protover.h index c46a13de66..7319d2f8c4 100644 --- a/src/or/protover.h +++ b/src/core/or/protover.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,10 @@ #ifndef TOR_PROTOVER_H #define TOR_PROTOVER_H -#include "container.h" +#include <stdbool.h> +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +struct smartlist_t; /** The first version of Tor that included "proto" entries in its * descriptors. Authorities should use this to decide whether to @@ -47,7 +50,7 @@ int protover_all_supported(const char *s, char **missing); int protover_is_supported_here(protocol_type_t pr, uint32_t ver); const char *protover_get_supported_protocols(void); -char *protover_compute_vote(const smartlist_t *list_of_proto_strings, +char *protover_compute_vote(const struct smartlist_t *list_of_proto_strings, int threshold); const char *protover_compute_for_old_tor(const char *version); int protocol_list_supports_protocol(const char *list, protocol_type_t tp, @@ -75,12 +78,12 @@ typedef struct proto_entry_t { */ char *name; /** Smartlist of proto_range_t */ - smartlist_t *ranges; + struct smartlist_t *ranges; } proto_entry_t; #if !defined(HAVE_RUST) && defined(TOR_UNIT_TESTS) -STATIC smartlist_t *parse_protocol_list(const char *s); -STATIC char *encode_protocol_list(const smartlist_t *sl); +STATIC struct smartlist_t *parse_protocol_list(const char *s); +STATIC char *encode_protocol_list(const struct smartlist_t *sl); STATIC const char *protocol_type_to_str(protocol_type_t pr); STATIC int str_to_protocol_type(const char *s, protocol_type_t *pr_out); STATIC void proto_entry_free_(proto_entry_t *entry); @@ -92,4 +95,3 @@ STATIC void proto_entry_free_(proto_entry_t *entry); #endif /* defined(PROTOVER_PRIVATE) */ #endif /* !defined(TOR_PROTOVER_H) */ - diff --git a/src/or/reasons.c b/src/core/or/reasons.c index ce1259b8f3..7a1e09e9f8 100644 --- a/src/or/reasons.c +++ b/src/core/or/reasons.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,9 +14,11 @@ * to another. **/ -#include "or.h" -#include "config.h" -#include "reasons.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/or/reasons.h" +#include "feature/nodelist/routerlist.h" +#include "lib/tls/tortls.h" /***************************** Edge (stream) reasons **********************/ @@ -493,4 +495,3 @@ end_reason_to_http_connect_response_line(int endreason) return "HTTP/1.0 500 Internal Server Error (weird end reason)\r\n\r\n"; } } - diff --git a/src/or/reasons.h b/src/core/or/reasons.h index 3d6ba8fc83..837b4a0f1a 100644 --- a/src/or/reasons.h +++ b/src/core/or/reasons.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,9 @@ #ifndef TOR_REASONS_H #define TOR_REASONS_H +#include "lib/net/socks5_status.h" +enum bandwidth_weight_rule_t; + const char *stream_end_reason_to_control_string(int reason); const char *stream_end_reason_to_string(int reason); socks5_reply_status_t stream_end_reason_to_socks5_response(int reason); @@ -29,4 +32,3 @@ const char *bandwidth_weight_rule_to_string(enum bandwidth_weight_rule_t rule); const char *end_reason_to_http_connect_response_line(int endreason); #endif /* !defined(TOR_REASONS_H) */ - diff --git a/src/or/relay.c b/src/core/or/relay.c index 3632678af6..32bb69d25f 100644 --- a/src/or/relay.c +++ b/src/core/or/relay.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -46,40 +46,55 @@ **/ #define RELAY_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "backtrace.h" -#include "buffers.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "compress.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "geoip.h" -#include "hs_cache.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "onion.h" -#include "policies.h" -#include "reasons.h" -#include "relay.h" -#include "relay_crypto.h" -#include "rendcache.h" -#include "rendcommon.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "scheduler.h" -#include "rephist.h" +#include "core/or/or.h" +#include "feature/client/addressmap.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "core/or/channel.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "lib/compress/compress.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/stats/geoip.h" +#include "feature/hs/hs_cache.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/crypto/onion.h" +#include "core/or/policies.h" +#include "core/or/reasons.h" +#include "core/or/relay.h" +#include "core/crypto/relay_crypto.h" +#include "feature/rend/rendcache.h" +#include "feature/rend/rendcommon.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "core/or/scheduler.h" +#include "feature/stats/rephist.h" + +#include "core/or/cell_st.h" +#include "core/or/cell_queue_st.h" +#include "core/or/cpath_build_state_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/destroy_cell_queue_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "core/or/socks_request_st.h" + +#include "lib/intmath/weakrng.h" static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, @@ -1783,15 +1798,15 @@ connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, return 0; } - /* Don't allow the other endpoint to request more than our maximim - * (ie initial) stream SENDME window worth of data. Well-behaved + /* Don't allow the other endpoint to request more than our maximum + * (i.e. initial) stream SENDME window worth of data. Well-behaved * stock clients will not request more than this max (as per the check * in the while loop of connection_edge_consider_sending_sendme()). */ if (conn->package_window + STREAMWINDOW_INCREMENT > STREAMWINDOW_START_MAX) { static struct ratelim_t stream_warn_ratelim = RATELIM_INIT(600); - log_fn_ratelim(&stream_warn_ratelim,LOG_PROTOCOL_WARN, LD_PROTOCOL, + log_fn_ratelim(&stream_warn_ratelim, LOG_PROTOCOL_WARN, LD_PROTOCOL, "Unexpected stream sendme cell. Closing circ (window %d).", conn->package_window); return -END_CIRC_REASON_TORPROTOCOL; @@ -3071,4 +3086,3 @@ circuit_queue_streams_are_blocked(circuit_t *circ) return circ->streams_blocked_on_p_chan; } } - diff --git a/src/or/relay.h b/src/core/or/relay.h index ce0969b46c..db7f17b96c 100644 --- a/src/or/relay.h +++ b/src/core/or/relay.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/core/or/relay_crypto_st.h b/src/core/or/relay_crypto_st.h new file mode 100644 index 0000000000..f186e182f0 --- /dev/null +++ b/src/core/or/relay_crypto_st.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef RELAY_CRYPTO_ST_H +#define RELAY_CRYPTO_ST_H + +#define crypto_cipher_t aes_cnt_cipher +struct crypto_cipher_t; +struct crypto_digest_t; + +struct relay_crypto_t { + /* crypto environments */ + /** Encryption key and counter for cells heading towards the OR at this + * step. */ + struct crypto_cipher_t *f_crypto; + /** Encryption key and counter for cells heading back from the OR at this + * step. */ + struct crypto_cipher_t *b_crypto; + + /** Digest state for cells heading towards the OR at this step. */ + struct crypto_digest_t *f_digest; /* for integrity checking */ + /** Digest state for cells heading away from the OR at this step. */ + struct crypto_digest_t *b_digest; + +}; +#undef crypto_cipher_t + +#endif diff --git a/src/or/scheduler.c b/src/core/or/scheduler.c index da894294bf..e19059f0c5 100644 --- a/src/or/scheduler.c +++ b/src/core/or/scheduler.c @@ -1,17 +1,20 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" +#include "core/or/or.h" +#include "app/config/config.h" -#include "compat_libevent.h" +#include "lib/evloop/compat_libevent.h" #define SCHEDULER_PRIVATE_ #define SCHEDULER_KIST_PRIVATE -#include "scheduler.h" -#include "main.h" -#include "buffers.h" +#include "core/or/scheduler.h" +#include "core/mainloop/main.h" +#include "lib/container/buffers.h" #define TOR_CHANNEL_INTERNAL_ -#include "channeltls.h" +#include "core/or/channeltls.h" +#include "lib/evloop/compat_libevent.h" + +#include "core/or/or_connection_st.h" /** * \file scheduler.c @@ -763,4 +766,3 @@ scheduler_touch_channel(channel_t *chan) } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/or/scheduler.h b/src/core/or/scheduler.h index 08b02e286f..05a888365b 100644 --- a/src/or/scheduler.h +++ b/src/core/or/scheduler.h @@ -1,4 +1,4 @@ -/* * Copyright (c) 2017, The Tor Project, Inc. */ +/* * Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,9 +9,9 @@ #ifndef TOR_SCHEDULER_H #define TOR_SCHEDULER_H -#include "or.h" -#include "channel.h" -#include "testsupport.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "lib/testsupport/testsupport.h" /** Scheduler type, we build an ordered list with those values from the * parsed strings in Schedulers. The reason to do such a thing is so we can diff --git a/src/or/scheduler_kist.c b/src/core/or/scheduler_kist.c index c6e9b72c48..449478df78 100644 --- a/src/or/scheduler_kist.c +++ b/src/core/or/scheduler_kist.c @@ -1,21 +1,28 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SCHEDULER_KIST_PRIVATE -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "connection.h" -#include "networkstatus.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/nodelist/networkstatus.h" #define TOR_CHANNEL_INTERNAL_ -#include "channel.h" -#include "channeltls.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" #define SCHEDULER_PRIVATE_ -#include "scheduler.h" +#include "core/or/scheduler.h" +#include "lib/math/fp.h" + +#include "core/or/or_connection_st.h" #define TLS_PER_CELL_OVERHEAD 29 +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + #ifdef HAVE_KIST_SUPPORT /* Kernel interface needed for KIST. */ #include <netinet/tcp.h> @@ -833,4 +840,3 @@ scheduler_can_use_kist(void) } #endif /* defined(HAVE_KIST_SUPPORT) */ - diff --git a/src/or/scheduler_vanilla.c b/src/core/or/scheduler_vanilla.c index b674d8256c..db8374eadb 100644 --- a/src/or/scheduler_vanilla.c +++ b/src/core/or/scheduler_vanilla.c @@ -1,12 +1,12 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" +#include "core/or/or.h" +#include "app/config/config.h" #define TOR_CHANNEL_INTERNAL_ -#include "channel.h" +#include "core/or/channel.h" #define SCHEDULER_PRIVATE_ -#include "scheduler.h" +#include "core/or/scheduler.h" /***************************************************************************** * Other internal data @@ -72,9 +72,9 @@ vanilla_scheduler_run(void) n_cells = channel_num_cells_writeable(chan); if (n_cells > 0) { log_debug(LD_SCHED, - "Scheduler saw pending channel " U64_FORMAT " at %p with " + "Scheduler saw pending channel %"PRIu64 " at %p with " "%d cells writeable", - U64_PRINTF_ARG(chan->global_identifier), chan, n_cells); + (chan->global_identifier), chan, n_cells); flushed = 0; while (flushed < n_cells) { @@ -97,9 +97,9 @@ vanilla_scheduler_run(void) if (!to_readd) to_readd = smartlist_new(); smartlist_add(to_readd, chan); log_debug(LD_SCHED, - "Channel " U64_FORMAT " at %p " + "Channel %"PRIu64 " at %p " "is still pending", - U64_PRINTF_ARG(chan->global_identifier), + (chan->global_identifier), chan); } else { /* It's waiting to be able to write more */ @@ -125,14 +125,14 @@ vanilla_scheduler_run(void) log_debug(LD_SCHED, "Scheduler flushed %d cells onto pending channel " - U64_FORMAT " at %p", - (int)flushed, U64_PRINTF_ARG(chan->global_identifier), + "%"PRIu64 " at %p", + (int)flushed, (chan->global_identifier), chan); } else { log_info(LD_SCHED, - "Scheduler saw pending channel " U64_FORMAT " at %p with " + "Scheduler saw pending channel %"PRIu64 " at %p with " "no cells writeable", - U64_PRINTF_ARG(chan->global_identifier), chan); + (chan->global_identifier), chan); /* Put it back to WAITING_TO_WRITE */ scheduler_set_channel_state(chan, SCHED_CHAN_WAITING_TO_WRITE); } diff --git a/src/core/or/server_port_cfg_st.h b/src/core/or/server_port_cfg_st.h new file mode 100644 index 0000000000..e1a9ca496a --- /dev/null +++ b/src/core/or/server_port_cfg_st.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef SERVER_PORT_CFG_ST_H +#define SERVER_PORT_CFG_ST_H + +struct server_port_cfg_t { + /* Server port types (or, dir) only: */ + unsigned int no_advertise : 1; + unsigned int no_listen : 1; + unsigned int all_addrs : 1; + unsigned int bind_ipv4_only : 1; + unsigned int bind_ipv6_only : 1; +}; + +#endif + diff --git a/src/core/or/socks_request_st.h b/src/core/or/socks_request_st.h new file mode 100644 index 0000000000..d7b979c3eb --- /dev/null +++ b/src/core/or/socks_request_st.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef SOCKS_REQUEST_ST_H +#define SOCKS_REQUEST_ST_H + +#define MAX_SOCKS_REPLY_LEN 1024 + +#define SOCKS_NO_AUTH 0x00 +#define SOCKS_USER_PASS 0x02 + +/** Please open a TCP connection to this addr:port. */ +#define SOCKS_COMMAND_CONNECT 0x01 +/** Please turn this FQDN into an IP address, privately. */ +#define SOCKS_COMMAND_RESOLVE 0xF0 +/** Please turn this IP address into an FQDN, privately. */ +#define SOCKS_COMMAND_RESOLVE_PTR 0xF1 + +/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */ +#define SOCKS_COMMAND_IS_CONNECT(c) (((c)==SOCKS_COMMAND_CONNECT) || 0) +#define SOCKS_COMMAND_IS_RESOLVE(c) ((c)==SOCKS_COMMAND_RESOLVE || \ + (c)==SOCKS_COMMAND_RESOLVE_PTR) + +/** State of a SOCKS request from a user to an OP. Also used to encode other + * information for non-socks user request (such as those on TransPort and + * DNSPort) */ +struct socks_request_t { + /** Which version of SOCKS did the client use? One of "0, 4, 5" -- where + * 0 means that no socks handshake ever took place, and this is just a + * stub connection (e.g. see connection_ap_make_link()). */ + uint8_t socks_version; + /** If using socks5 authentication, which authentication type did we + * negotiate? currently we support 0 (no authentication) and 2 + * (username/password). */ + uint8_t auth_type; + /** What is this stream's goal? One of the SOCKS_COMMAND_* values */ + uint8_t command; + /** Which kind of listener created this stream? */ + uint8_t listener_type; + size_t replylen; /**< Length of <b>reply</b>. */ + uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if + * we want to specify our own socks reply, + * rather than using the default socks4 or + * socks5 socks reply. We use this for the + * two-stage socks5 handshake. + */ + char address[MAX_SOCKS_ADDR_LEN]; /**< What address did the client ask to + connect to/resolve? */ + uint16_t port; /**< What port did the client ask to connect to? */ + unsigned int has_finished : 1; /**< Has the SOCKS handshake finished? Used to + * make sure we send back a socks reply for + * every connection. */ + unsigned int got_auth : 1; /**< Have we received any authentication data? */ + /** If this is set, we will choose "no authentication" instead of + * "username/password" authentication if both are offered. Used as input to + * parse_socks. */ + unsigned int socks_prefer_no_auth : 1; + + /** Number of bytes in username; 0 if username is NULL */ + size_t usernamelen; + /** Number of bytes in password; 0 if password is NULL */ + uint8_t passwordlen; + /** The negotiated username value if any (for socks5), or the entire + * authentication string (for socks4). This value is NOT nul-terminated; + * see usernamelen for its length. */ + char *username; + /** The negotiated password value if any (for socks5). This value is NOT + * nul-terminated; see passwordlen for its length. */ + char *password; +}; + +#endif diff --git a/src/or/status.c b/src/core/or/status.c index 4b8033d114..30a65b1d4c 100644 --- a/src/or/status.c +++ b/src/core/or/status.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,24 +14,28 @@ #define STATUS_PRIVATE -#include "or.h" -#include "circuituse.h" -#include "config.h" -#include "status.h" -#include "nodelist.h" -#include "relay.h" -#include "router.h" -#include "circuitlist.h" -#include "main.h" -#include "rephist.h" -#include "hibernate.h" -#include "statefile.h" -#include "hs_stats.h" -#include "hs_service.h" -#include "dos.h" +#include "core/or/or.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/or/status.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/relay.h" +#include "feature/relay/router.h" +#include "core/or/circuitlist.h" +#include "core/mainloop/main.h" +#include "feature/stats/rephist.h" +#include "feature/hibernate/hibernate.h" +#include "app/config/statefile.h" +#include "feature/hs/hs_stats.h" +#include "feature/hs/hs_service.h" +#include "core/or/dos.h" + +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "lib/tls/tortls.h" static void log_accounting(const time_t now, const or_options_t *options); -#include "geoip.h" +#include "feature/stats/geoip.h" /** Return the total number of circuits. */ STATIC int @@ -75,12 +79,12 @@ bytes_to_usage(uint64_t bytes) char *bw_string = NULL; if (bytes < (1<<20)) { /* Less than a megabyte. */ - tor_asprintf(&bw_string, U64_FORMAT" kB", U64_PRINTF_ARG(bytes>>10)); + tor_asprintf(&bw_string, "%"PRIu64" kB", (bytes>>10)); } else if (bytes < (1<<30)) { /* Megabytes. Let's add some precision. */ - double bw = U64_TO_DBL(bytes); + double bw = ((double)bytes); tor_asprintf(&bw_string, "%.2f MB", bw/(1<<20)); } else { /* Gigabytes. */ - double bw = U64_TO_DBL(bytes); + double bw = ((double)bytes); tor_asprintf(&bw_string, "%.2f GB", bw/(1<<30)); } @@ -148,8 +152,8 @@ log_heartbeat(time_t now) double fullness_pct = 100; if (stats_n_data_cells_packaged && !hibernating) { fullness_pct = - 100*(U64_TO_DBL(stats_n_data_bytes_packaged) / - U64_TO_DBL(stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)); + 100*(((double)stats_n_data_bytes_packaged) / + ((double)stats_n_data_cells_packaged*RELAY_PAYLOAD_SIZE)); } const double overhead_pct = ( r - 1.0 ) * 100.0; @@ -186,12 +190,12 @@ log_heartbeat(time_t now) const uint64_t main_loop_idle_count = get_main_loop_idle_count(); log_fn(LOG_NOTICE, LD_HEARTBEAT, "Main event loop statistics: " - U64_FORMAT " successful returns, " - U64_FORMAT " erroneous returns, and " - U64_FORMAT " idle returns.", - U64_PRINTF_ARG(main_loop_success_count), - U64_PRINTF_ARG(main_loop_error_count), - U64_PRINTF_ARG(main_loop_idle_count)); + "%"PRIu64 " successful returns, " + "%"PRIu64 " erroneous returns, and " + "%"PRIu64 " idle returns.", + (main_loop_success_count), + (main_loop_error_count), + (main_loop_idle_count)); } /** Now, if we are an HS service, log some stats about our usage */ @@ -245,4 +249,3 @@ log_accounting(const time_t now, const or_options_t *options) tor_free(acc_max); tor_free(remaining); } - diff --git a/src/or/status.h b/src/core/or/status.h index 49da6abc0f..7258ed5939 100644 --- a/src/or/status.h +++ b/src/core/or/status.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_STATUS_H #define TOR_STATUS_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" int log_heartbeat(time_t now); diff --git a/src/core/or/tor_version_st.h b/src/core/or/tor_version_st.h new file mode 100644 index 0000000000..5950c5d5c4 --- /dev/null +++ b/src/core/or/tor_version_st.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_VERSION_ST_H +#define TOR_VERSION_ST_H + +#define MAX_STATUS_TAG_LEN 32 +/** Structure to hold parsed Tor versions. This is a little messier + * than we would like it to be, because we changed version schemes with 0.1.0. + * + * See version-spec.txt for the whole business. + */ +struct tor_version_t { + int major; + int minor; + int micro; + /** Release status. For version in the post-0.1 format, this is always + * VER_RELEASE. */ + enum { VER_PRE=0, VER_RC=1, VER_RELEASE=2, } status; + int patchlevel; + char status_tag[MAX_STATUS_TAG_LEN]; + int svn_revision; + + int git_tag_len; + char git_tag[DIGEST_LEN]; +}; + +#endif + diff --git a/src/core/or/var_cell_st.h b/src/core/or/var_cell_st.h new file mode 100644 index 0000000000..514afc44b1 --- /dev/null +++ b/src/core/or/var_cell_st.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VAR_CELL_ST_H +#define VAR_CELL_ST_H + +/** Parsed variable-length onion routing cell. */ +struct var_cell_t { + /** Type of the cell: CELL_VERSIONS, etc. */ + uint8_t command; + /** Circuit thich received the cell */ + circid_t circ_id; + /** Number of bytes actually stored in <b>payload</b> */ + uint16_t payload_len; + /** Payload of this cell */ + uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; +}; + +#endif + diff --git a/src/or/proto_cell.c b/src/core/proto/proto_cell.c index 75eb2a7e7f..49b07663d7 100644 --- a/src/or/proto_cell.c +++ b/src/core/proto/proto_cell.c @@ -1,14 +1,16 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "proto_cell.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "core/proto/proto_cell.h" -#include "connection_or.h" +#include "core/or/connection_or.h" + +#include "core/or/var_cell_st.h" /** True iff the cell command <b>command</b> is one that implies a * variable-length cell in Tor link protocol <b>linkproto</b>. */ diff --git a/src/or/proto_cell.h b/src/core/proto/proto_cell.h index bbc14b9a02..b29645e41d 100644 --- a/src/or/proto_cell.h +++ b/src/core/proto/proto_cell.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_CELL_H diff --git a/src/or/proto_control0.c b/src/core/proto/proto_control0.c index c17ba34948..d26c69753a 100644 --- a/src/or/proto_control0.c +++ b/src/core/proto/proto_control0.c @@ -1,12 +1,12 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "proto_control0.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "core/proto/proto_control0.h" /** Return 1 iff buf looks more like it has an (obsolete) v0 controller * command on it than any valid v1 controller command. */ diff --git a/src/or/proto_control0.h b/src/core/proto/proto_control0.h index 0cc8eacad0..b80dc6c8f8 100644 --- a/src/or/proto_control0.h +++ b/src/core/proto/proto_control0.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_CONTROL0_H diff --git a/src/or/proto_ext_or.c b/src/core/proto/proto_ext_or.c index 057cf109ec..04bec4e6b9 100644 --- a/src/or/proto_ext_or.c +++ b/src/core/proto/proto_ext_or.c @@ -1,13 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "ext_orport.h" -#include "proto_ext_or.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "feature/relay/ext_orport.h" +#include "core/proto/proto_ext_or.h" /** The size of the header of an Extended ORPort message: 2 bytes for * COMMAND, 2 bytes for BODYLEN */ diff --git a/src/or/proto_ext_or.h b/src/core/proto/proto_ext_or.h index cc504d18e3..708a45974b 100644 --- a/src/or/proto_ext_or.h +++ b/src/core/proto/proto_ext_or.h @@ -1,17 +1,22 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_EXT_OR_H #define TOR_PROTO_EXT_OR_H struct buf_t; -struct ext_or_cmt_t; + +/** A parsed Extended ORPort message. */ +typedef struct ext_or_cmd_t { + uint16_t cmd; /** Command type */ + uint16_t len; /** Body length */ + char body[FLEXIBLE_ARRAY_MEMBER]; /** Message body */ +} ext_or_cmd_t; int fetch_ext_or_command_from_buf(struct buf_t *buf, struct ext_or_cmd_t **out); #endif /* !defined(TOR_PROTO_EXT_OR_H) */ - diff --git a/src/or/proto_http.c b/src/core/proto/proto_http.c index 3762429e1e..37298d1284 100644 --- a/src/or/proto_http.c +++ b/src/core/proto/proto_http.c @@ -1,13 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROTO_HTTP_PRIVATE -#include "or.h" -#include "buffers.h" -#include "proto_http.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "core/proto/proto_http.h" /** Return true if <b>cmd</b> looks like a HTTP (proxy) request. */ int diff --git a/src/or/proto_http.h b/src/core/proto/proto_http.h index 805686070f..587e435ede 100644 --- a/src/or/proto_http.h +++ b/src/core/proto/proto_http.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_HTTP_H diff --git a/src/or/proto_socks.c b/src/core/proto/proto_socks.c index 57a7d1cd64..6912441472 100644 --- a/src/or/proto_socks.c +++ b/src/core/proto/proto_socks.c @@ -1,18 +1,21 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "addressmap.h" -#include "buffers.h" -#include "control.h" -#include "config.h" -#include "crypto_util.h" -#include "ext_orport.h" -#include "proto_socks.h" -#include "reasons.h" +#include "core/or/or.h" +#include "feature/client/addressmap.h" +#include "lib/container/buffers.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/relay/ext_orport.h" +#include "core/proto/proto_socks.h" +#include "core/or/reasons.h" + +#include "core/or/socks_request_st.h" static void socks_request_set_socks5_error(socks_request_t *req, socks5_reply_status_t reason); @@ -708,4 +711,3 @@ parse_socks_client(const uint8_t *data, size_t datalen, return -1; /* LCOV_EXCL_STOP */ } - diff --git a/src/or/proto_socks.h b/src/core/proto/proto_socks.h index 02e0aca7e9..53de288f65 100644 --- a/src/or/proto_socks.h +++ b/src/core/proto/proto_socks.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_PROTO_SOCKS_H @@ -19,4 +19,3 @@ int fetch_from_buf_socks(struct buf_t *buf, socks_request_t *req, int fetch_from_buf_socks_client(buf_t *buf, int state, char **reason); #endif /* !defined(TOR_PROTO_SOCKS_H) */ - diff --git a/src/or/protover_rust.c b/src/core/proto/protover_rust.c index 99304f8b51..dbdd5c8237 100644 --- a/src/or/protover_rust.c +++ b/src/core/proto/protover_rust.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* @@ -7,8 +7,8 @@ * and safe translation/handling between the Rust/C boundary. */ -#include "or.h" -#include "protover.h" +#include "core/or/or.h" +#include "core/or/protover.h" #ifdef HAVE_RUST diff --git a/src/ext/OpenBSD_malloc_Linux.c b/src/ext/OpenBSD_malloc_Linux.c index 855c912310..9c30570c41 100644 --- a/src/ext/OpenBSD_malloc_Linux.c +++ b/src/ext/OpenBSD_malloc_Linux.c @@ -59,7 +59,7 @@ #include <errno.h> #include <err.h> /* For SIZE_MAX */ -#include "torint.h" +#include "lib/cc/torint.h" //#include "thread_private.h" diff --git a/src/ext/csiphash.c b/src/ext/csiphash.c index 0427c87950..a6a9846db4 100644 --- a/src/ext/csiphash.c +++ b/src/ext/csiphash.c @@ -29,12 +29,12 @@ Jean-Philippe Aumasson (https://131002.net/siphash/siphash24.c) */ -#include "torint.h" +#include "lib/cc/torint.h" +#include "lib/log/util_bug.h" + #include "siphash.h" -/* for tor_assert */ -#include "util.h" -/* for memcpy */ #include <string.h> +#include <stdlib.h> #include "byteorder.h" #define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) diff --git a/src/ext/curve25519_donna/curve25519-donna-c64.c b/src/ext/curve25519_donna/curve25519-donna-c64.c index b68ff3695a..45da7bf1e6 100644 --- a/src/ext/curve25519_donna/curve25519-donna-c64.c +++ b/src/ext/curve25519_donna/curve25519-donna-c64.c @@ -25,7 +25,7 @@ #include "orconfig.h" #include <string.h> -#include "torint.h" +#include "lib/cc/torint.h" typedef uint8_t u8; typedef uint64_t limb; diff --git a/src/ext/curve25519_donna/curve25519-donna.c b/src/ext/curve25519_donna/curve25519-donna.c index 1c5a27ab8a..d64b95c113 100644 --- a/src/ext/curve25519_donna/curve25519-donna.c +++ b/src/ext/curve25519_donna/curve25519-donna.c @@ -48,7 +48,7 @@ #include "orconfig.h" #include <string.h> -#include "torint.h" +#include "lib/cc/torint.h" typedef uint8_t u8; typedef int32_t s32; diff --git a/src/ext/ed25519/donna/ed25519-hash-custom.h b/src/ext/ed25519/donna/ed25519-hash-custom.h index cdeab3e45b..ff8bbde3da 100644 --- a/src/ext/ed25519/donna/ed25519-hash-custom.h +++ b/src/ext/ed25519/donna/ed25519-hash-custom.h @@ -9,7 +9,7 @@ void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen); */ -#include "crypto_digest.h" +#include "lib/crypt_ops/crypto_digest.h" typedef struct ed25519_hash_context { crypto_digest_t *ctx; diff --git a/src/ext/ed25519/donna/ed25519-randombytes-custom.h b/src/ext/ed25519/donna/ed25519-randombytes-custom.h index 27eade4f95..d92a51d1d3 100644 --- a/src/ext/ed25519/donna/ed25519-randombytes-custom.h +++ b/src/ext/ed25519/donna/ed25519-randombytes-custom.h @@ -8,7 +8,7 @@ */ /* Tor: Instead of calling OpenSSL's CSPRNG directly, call the wrapper. */ -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" static void ED25519_FN(ed25519_randombytes_unsafe) (void *p, size_t len) diff --git a/src/ext/ed25519/donna/ed25519_donna_tor.h b/src/ext/ed25519/donna/ed25519_donna_tor.h index 7d7b8c0625..20e9b5e99c 100644 --- a/src/ext/ed25519/donna/ed25519_donna_tor.h +++ b/src/ext/ed25519/donna/ed25519_donna_tor.h @@ -1,7 +1,7 @@ /* Added for Tor. */ #ifndef SRC_EXT_ED25519_DONNA_H_INCLUDED_ #define SRC_EXT_ED25519_DONNA_H_INCLUDED_ -#include <torint.h> +#include "lib/cc/torint.h" typedef unsigned char curved25519_key[32]; diff --git a/src/ext/ed25519/donna/ed25519_tor.c b/src/ext/ed25519/donna/ed25519_tor.c index 43de9faaea..7f5ab398d8 100644 --- a/src/ext/ed25519/donna/ed25519_tor.c +++ b/src/ext/ed25519/donna/ed25519_tor.c @@ -40,7 +40,7 @@ #include "ed25519-randombytes.h" #include "ed25519-hash.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" typedef unsigned char ed25519_signature[64]; typedef unsigned char ed25519_public_key[32]; diff --git a/src/ext/ed25519/ref10/blinding.c b/src/ext/ed25519/ref10/blinding.c index 88e84cac20..8485524e5d 100644 --- a/src/ext/ed25519/ref10/blinding.c +++ b/src/ext/ed25519/ref10/blinding.c @@ -7,7 +7,7 @@ #include "ed25519_ref10.h" #include <string.h> -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" static void ed25519_ref10_gettweak(unsigned char *out, const unsigned char *param) diff --git a/src/ext/ed25519/ref10/crypto_hash_sha512.h b/src/ext/ed25519/ref10/crypto_hash_sha512.h index 7faddb1597..25e6a90cec 100644 --- a/src/ext/ed25519/ref10/crypto_hash_sha512.h +++ b/src/ext/ed25519/ref10/crypto_hash_sha512.h @@ -1,5 +1,5 @@ /* Added for Tor. */ -#include "crypto_digest.h" +#include "lib/crypt_ops/crypto_digest.h" /* Set 'out' to the 512-bit SHA512 hash of the 'len'-byte string in 'inp' */ #define crypto_hash_sha512(out, inp, len) \ diff --git a/src/ext/ed25519/ref10/crypto_int32.h b/src/ext/ed25519/ref10/crypto_int32.h index dd13c91bd0..26271e917b 100644 --- a/src/ext/ed25519/ref10/crypto_int32.h +++ b/src/ext/ed25519/ref10/crypto_int32.h @@ -3,7 +3,7 @@ #ifndef CRYPTO_INT32_H #define CRYPTO_INT32_H -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_int32 int32_t #define crypto_uint32 uint32_t diff --git a/src/ext/ed25519/ref10/crypto_int64.h b/src/ext/ed25519/ref10/crypto_int64.h index 46e8852ed0..3b066a9c0c 100644 --- a/src/ext/ed25519/ref10/crypto_int64.h +++ b/src/ext/ed25519/ref10/crypto_int64.h @@ -3,7 +3,7 @@ #ifndef CRYPTO_INT64_H #define CRYPTO_INT64_H -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_int64 int64_t #define crypto_uint64 uint64_t diff --git a/src/ext/ed25519/ref10/crypto_uint32.h b/src/ext/ed25519/ref10/crypto_uint32.h index 62655a5b66..a7a77723bd 100644 --- a/src/ext/ed25519/ref10/crypto_uint32.h +++ b/src/ext/ed25519/ref10/crypto_uint32.h @@ -1,3 +1,3 @@ /* Added for Tor. */ -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_uint32 uint32_t diff --git a/src/ext/ed25519/ref10/crypto_uint64.h b/src/ext/ed25519/ref10/crypto_uint64.h index cbda882a6a..adaaa08042 100644 --- a/src/ext/ed25519/ref10/crypto_uint64.h +++ b/src/ext/ed25519/ref10/crypto_uint64.h @@ -1,3 +1,3 @@ /* Added for Tor. */ -#include "torint.h" +#include "lib/cc/torint.h" #define crypto_uint64 uint64_t diff --git a/src/ext/ed25519/ref10/crypto_verify_32.h b/src/ext/ed25519/ref10/crypto_verify_32.h index 0f63efc7a3..5299928754 100644 --- a/src/ext/ed25519/ref10/crypto_verify_32.h +++ b/src/ext/ed25519/ref10/crypto_verify_32.h @@ -1,5 +1,4 @@ /* Added for Tor. */ -#include "di_ops.h" +#include "lib/ctime/di_ops.h" #define crypto_verify_32(a,b) \ (! tor_memeq((a), (b), 32)) - diff --git a/src/ext/ed25519/ref10/ed25519_ref10.h b/src/ext/ed25519/ref10/ed25519_ref10.h index 5965694977..bb72af6c0b 100644 --- a/src/ext/ed25519/ref10/ed25519_ref10.h +++ b/src/ext/ed25519/ref10/ed25519_ref10.h @@ -1,7 +1,7 @@ /* Added for Tor */ #ifndef SRC_EXT_ED25519_REF10_H_INCLUDED_ #define SRC_EXT_ED25519_REF10_H_INCLUDED_ -#include <torint.h> +#include "lib/cc/torint.h" int ed25519_ref10_seckey(unsigned char *sk); int ed25519_ref10_seckey_expand(unsigned char *sk, const unsigned char *sk_seed); diff --git a/src/ext/ed25519/ref10/keypair.c b/src/ext/ed25519/ref10/keypair.c index c437f0a4f2..a6e2d4c781 100644 --- a/src/ext/ed25519/ref10/keypair.c +++ b/src/ext/ed25519/ref10/keypair.c @@ -6,8 +6,8 @@ #include "crypto_hash_sha512.h" #include "ge.h" -#include "crypto_rand.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" int crypto_sign_seckey(unsigned char *sk) @@ -52,4 +52,3 @@ int crypto_sign_keypair(unsigned char *pk,unsigned char *sk) return 0; } - diff --git a/src/ext/ed25519/ref10/randombytes.h b/src/ext/ed25519/ref10/randombytes.h index a21dde8540..c2cef10ceb 100644 --- a/src/ext/ed25519/ref10/randombytes.h +++ b/src/ext/ed25519/ref10/randombytes.h @@ -1,4 +1,4 @@ /* Added for Tor. */ -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #define randombytes(b, n) \ (crypto_strongest_rand((b), (n)), 0) diff --git a/src/ext/ht.h b/src/ext/ht.h index 99da773faf..df9f60ba1d 100644 --- a/src/ext/ht.h +++ b/src/ext/ht.h @@ -1,6 +1,6 @@ /* Copyright (c) 2002, Christopher Clark. * Copyright (c) 2005-2006, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See license at end. */ /* Based on ideas by Christopher Clark and interfaces from Niels Provos. */ diff --git a/src/ext/keccak-tiny/keccak-tiny-unrolled.c b/src/ext/keccak-tiny/keccak-tiny-unrolled.c index 07e8c95bcf..05cf0ec3f0 100644 --- a/src/ext/keccak-tiny/keccak-tiny-unrolled.c +++ b/src/ext/keccak-tiny/keccak-tiny-unrolled.c @@ -9,7 +9,7 @@ #include "keccak-tiny.h" #include <string.h> -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" #include "byteorder.h" /******** Endianness conversion helpers ********/ diff --git a/src/ext/keccak-tiny/keccak-tiny.h b/src/ext/keccak-tiny/keccak-tiny.h index 7efea2319e..a9c8ed6420 100644 --- a/src/ext/keccak-tiny/keccak-tiny.h +++ b/src/ext/keccak-tiny/keccak-tiny.h @@ -2,7 +2,7 @@ #define KECCAK_FIPS202_H #include <stddef.h> -#include "torint.h" +#include "lib/cc/torint.h" #define KECCAK_MAX_RATE 200 diff --git a/src/ext/mulodi/mulodi4.c b/src/ext/mulodi/mulodi4.c index 9891bbf1af..accce1ce01 100644 --- a/src/ext/mulodi/mulodi4.c +++ b/src/ext/mulodi/mulodi4.c @@ -18,7 +18,7 @@ #define COMPILER_RT_ABI #define di_int int64_t #define di_uint uint64_t -#include "torint.h" +#include "lib/cc/torint.h" di_int __mulodi4(di_int a, di_int b, int* overflow); #endif diff --git a/src/or/tor_api.c b/src/feature/api/tor_api.c index 4260cc88f4..2a4458bf69 100644 --- a/src/or/tor_api.c +++ b/src/feature/api/tor_api.c @@ -1,15 +1,15 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file tor_api.c **/ -#include "tor_api.h" -#include "tor_api_internal.h" +#include "feature/api/tor_api.h" +#include "feature/api/tor_api_internal.h" // Include this after the above headers, to insure that they don't // depend on anything else. diff --git a/src/or/tor_api.h b/src/feature/api/tor_api.h index 6d4a9518e0..ead9493c1f 100644 --- a/src/or/tor_api.h +++ b/src/feature/api/tor_api.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/tor_api_internal.h b/src/feature/api/tor_api_internal.h index 10b6278b7b..2c392a68de 100644 --- a/src/or/tor_api_internal.h +++ b/src/feature/api/tor_api_internal.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_API_INTERNAL_H diff --git a/src/or/addressmap.c b/src/feature/client/addressmap.c index 7f861e4d24..e62d82b7f3 100644 --- a/src/or/addressmap.c +++ b/src/feature/client/addressmap.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,16 +15,19 @@ #define ADDRESSMAP_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "circuituse.h" -#include "config.h" -#include "connection_edge.h" -#include "control.h" -#include "crypto_rand.h" -#include "dns.h" -#include "nodelist.h" -#include "routerset.h" +#include "lib/crypt_ops/crypto_rand.h" + +#include "core/or/or.h" +#include "feature/client/addressmap.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/or/connection_edge.h" +#include "feature/control/control.h" +#include "feature/relay/dns.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerset.h" + +#include "core/or/entry_connection_st.h" /** A client-side struct to remember requests to rewrite addresses * to new addresses. These structs are stored in the hash table @@ -640,7 +643,7 @@ client_dns_incr_failures(const char *address) ent->expires = time(NULL) + MAX_DNS_ENTRY_AGE; strmap_set(addressmap,address,ent); } - if (ent->num_resolve_failures < SHORT_MAX) + if (ent->num_resolve_failures < SHRT_MAX) ++ent->num_resolve_failures; /* don't overflow */ log_info(LD_APP, "Address %s now has %d resolve failures.", safe_str_client(address), @@ -1151,4 +1154,3 @@ addressmap_get_mappings(smartlist_t *sl, time_t min_expires, iter = strmap_iter_next(addressmap,iter); } } - diff --git a/src/or/addressmap.h b/src/feature/client/addressmap.h index 1544b76e10..b0db5c8b4e 100644 --- a/src/or/addressmap.h +++ b/src/feature/client/addressmap.h @@ -1,13 +1,13 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ADDRESSMAP_H #define TOR_ADDRESSMAP_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" void addressmap_init(void); void addressmap_clear_excluded_trackexithosts(const or_options_t *options); diff --git a/src/or/bridges.c b/src/feature/client/bridges.c index 699e030e6c..4bffe16036 100644 --- a/src/or/bridges.c +++ b/src/feature/client/bridges.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,19 +13,24 @@ #define TOR_BRIDGES_PRIVATE -#include "or.h" -#include "bridges.h" -#include "circuitbuild.h" -#include "config.h" -#include "connection.h" -#include "directory.h" -#include "entrynodes.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "transports.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "core/or/circuitbuild.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/dircache/directory.h" +#include "feature/client/entrynodes.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "feature/client/transports.h" + +#include "core/or/extend_info_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" /** Information about a configured bridge. Currently this just matches the * ones in the torrc file, but one day we may be able to learn about new diff --git a/src/or/bridges.h b/src/feature/client/bridges.h index 3108eb555d..70588c1b91 100644 --- a/src/or/bridges.h +++ b/src/feature/client/bridges.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,6 +13,7 @@ #define TOR_BRIDGES_H struct bridge_line_t; +struct ed25519_public_key_t; /* Opaque handle to a configured bridge */ typedef struct bridge_info_t bridge_info_t; @@ -38,7 +39,7 @@ int routerinfo_is_a_configured_bridge(const routerinfo_t *ri); int node_is_a_configured_bridge(const node_t *node); void learned_router_identity(const tor_addr_t *addr, uint16_t port, const char *digest, - const ed25519_public_key_t *ed_id); + const struct ed25519_public_key_t *ed_id); void bridge_add_from_config(struct bridge_line_t *bridge_line); void retry_bridge_descriptor_fetch_directly(const char *digest); @@ -77,4 +78,3 @@ STATIC void bridge_resolve_conflicts(const tor_addr_t *addr, #endif /* defined(TOR_BRIDGES_PRIVATE) */ #endif /* !defined(TOR_BRIDGES_H) */ - diff --git a/src/or/circpathbias.c b/src/feature/client/circpathbias.c index ff42bf91e4..1ee29c639d 100644 --- a/src/or/circpathbias.c +++ b/src/feature/client/circpathbias.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,19 +21,27 @@ * each guard, and stored persistently in the state file. */ -#include "or.h" -#include "channel.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitstats.h" -#include "connection_edge.h" -#include "config.h" -#include "crypto_rand.h" -#include "entrynodes.h" -#include "networkstatus.h" -#include "relay.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/circuitstats.h" +#include "core/or/connection_edge.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/client/entrynodes.h" +#include "feature/nodelist/networkstatus.h" +#include "core/or/relay.h" +#include "lib/math/fp.h" +#include "lib/math/laplace.h" + +#include "core/or/cell_st.h" +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" static void pathbias_count_successful_close(origin_circuit_t *circ); static void pathbias_count_collapse(origin_circuit_t *circ); @@ -1568,4 +1576,3 @@ pathbias_scale_use_rates(entry_guard_t *guard) entry_guards_changed(); } } - diff --git a/src/or/circpathbias.h b/src/feature/client/circpathbias.h index c9e572d2ae..c99d1277bb 100644 --- a/src/or/circpathbias.h +++ b/src/feature/client/circpathbias.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,7 +23,6 @@ int pathbias_check_probe_response(circuit_t *circ, const cell_t *cell); void pathbias_count_use_attempt(origin_circuit_t *circ); void pathbias_mark_use_success(origin_circuit_t *circ); void pathbias_mark_use_rollback(origin_circuit_t *circ); -const char *pathbias_state_to_string(path_state_t state); +const char *pathbias_state_to_string(enum path_state_t state); #endif /* !defined(TOR_CIRCPATHBIAS_H) */ - diff --git a/src/or/dnsserv.c b/src/feature/client/dnsserv.c index 7e344deeab..31cc3eff79 100644 --- a/src/or/dnsserv.c +++ b/src/feature/client/dnsserv.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,14 +21,21 @@ * DNS client. **/ -#include "or.h" -#include "dnsserv.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "main.h" -#include "policies.h" +#include "core/or/or.h" +#include "feature/client/dnsserv.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/control/control.h" +#include "core/mainloop/main.h" +#include "core/or/policies.h" + +#include "feature/control/control_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/listener_connection_st.h" +#include "core/or/socks_request_st.h" +#include "lib/evloop/compat_libevent.h" + #include <event2/dns.h> #include <event2/dns_compat.h> /* XXXX this implies we want an improved evdns */ @@ -406,4 +413,3 @@ dnsserv_close_listener(connection_t *conn) listener_conn->dns_server_port = NULL; } } - diff --git a/src/or/dnsserv.h b/src/feature/client/dnsserv.h index 2af366eee5..afdde3a342 100644 --- a/src/or/dnsserv.h +++ b/src/feature/client/dnsserv.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/entrynodes.c b/src/feature/client/entrynodes.c index 27d760f1a8..664be8ce11 100644 --- a/src/or/entrynodes.c +++ b/src/feature/client/entrynodes.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -112,32 +112,40 @@ #define ENTRYNODES_PRIVATE -#include "or.h" -#include "channel.h" -#include "bridges.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitstats.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "entrynodes.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "transports.h" -#include "statefile.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "feature/client/bridges.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/circuitstats.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircache/directory.h" +#include "feature/client/entrynodes.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "feature/client/transports.h" +#include "app/config/statefile.h" +#include "lib/math/fp.h" +#include "lib/encoding/confline.h" + +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" +#include "app/config/or_state_st.h" + +#include "lib/crypt_ops/digestset.h" /** A list of existing guard selection contexts. */ static smartlist_t *guard_contexts = NULL; @@ -1060,7 +1068,7 @@ get_eligible_guards(const or_options_t *options, continue; } ++n_guards; - if (digestset_contains(sampled_guard_ids, node->identity)) + if (digestset_probably_contains(sampled_guard_ids, node->identity)) continue; smartlist_add(eligible_guards, (node_t*)node); } SMARTLIST_FOREACH_END(node); @@ -3684,4 +3692,3 @@ entry_guards_free_all(void) } circuit_build_times_free_timeouts(get_circuit_build_times_mutable()); } - diff --git a/src/or/entrynodes.h b/src/feature/client/entrynodes.h index e8c91da41b..5f9b5bdcba 100644 --- a/src/or/entrynodes.h +++ b/src/feature/client/entrynodes.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_ENTRYNODES_H #define TOR_ENTRYNODES_H -#include "handles.h" +#include "lib/container/handles.h" /* Forward declare for guard_selection_t; entrynodes.c has the real struct */ typedef struct guard_selection_s guard_selection_t; @@ -64,6 +64,8 @@ typedef struct guard_pathbias_t { } guard_pathbias_t; #if defined(ENTRYNODES_PRIVATE) +#include "lib/crypt_ops/crypto_ed25519.h" + /** * @name values for entry_guard_t.is_reachable. * @@ -635,4 +637,3 @@ guard_get_guardfraction_bandwidth(guardfraction_bandwidth_t *guardfraction_bw, uint32_t guardfraction_percentage); #endif /* !defined(TOR_ENTRYNODES_H) */ - diff --git a/src/or/transports.c b/src/feature/client/transports.c index 614fc81da8..85d4d2e080 100644 --- a/src/or/transports.c +++ b/src/feature/client/transports.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -90,17 +90,20 @@ **/ #define PT_PRIVATE -#include "or.h" -#include "bridges.h" -#include "config.h" -#include "circuitbuild.h" -#include "transports.h" -#include "util.h" -#include "router.h" -#include "statefile.h" -#include "connection_or.h" -#include "ext_orport.h" -#include "control.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/circuitbuild.h" +#include "feature/client/transports.h" +#include "feature/relay/router.h" +#include "app/config/statefile.h" +#include "core/or/connection_or.h" +#include "feature/relay/ext_orport.h" +#include "feature/control/control.h" + +#include "lib/process/env.h" +#include "lib/process/subprocess.h" static process_environment_t * create_managed_proxy_environment(const managed_proxy_t *mp); @@ -1697,3 +1700,39 @@ pt_free_all(void) } } +/** Return a newly allocated string equal to <b>string</b>, except that every + * character in <b>chars_to_escape</b> is preceded by a backslash. */ +char * +tor_escape_str_for_pt_args(const char *string, const char *chars_to_escape) +{ + char *new_string = NULL; + char *new_cp = NULL; + size_t length, new_length; + + tor_assert(string); + + length = strlen(string); + + if (!length) /* If we were given the empty string, return the same. */ + return tor_strdup(""); + /* (new_length > SIZE_MAX) => ((length * 2) + 1 > SIZE_MAX) => + (length*2 > SIZE_MAX - 1) => (length > (SIZE_MAX - 1)/2) */ + if (length > (SIZE_MAX - 1)/2) /* check for overflow */ + return NULL; + + /* this should be enough even if all characters must be escaped */ + new_length = (length * 2) + 1; + + new_string = new_cp = tor_malloc(new_length); + + while (*string) { + if (strchr(chars_to_escape, *string)) + *new_cp++ = '\\'; + + *new_cp++ = *string++; + } + + *new_cp = '\0'; /* NUL-terminate the new string */ + + return new_string; +} diff --git a/src/or/transports.h b/src/feature/client/transports.h index 022b926a03..d304dcd485 100644 --- a/src/or/transports.h +++ b/src/feature/client/transports.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -66,6 +66,9 @@ char *pt_stringify_socks_args(const smartlist_t *socks_args); char *pt_get_socks_args_for_proxy_addrport(const tor_addr_t *addr, uint16_t port); +char *tor_escape_str_for_pt_args(const char *string, + const char *chars_to_escape); + #ifdef PT_PRIVATE /** State of the managed proxy configuration protocol. */ enum pt_proto_state { @@ -78,6 +81,8 @@ enum pt_proto_state { PT_PROTO_FAILED_LAUNCH /* failed while launching */ }; +struct process_handle_t; + /** Structure containing information of a managed proxy. */ typedef struct { enum pt_proto_state conf_state; /* the current configuration state */ @@ -90,7 +95,7 @@ typedef struct { int is_server; /* is it a server proxy? */ /* A pointer to the process handle of this managed proxy. */ - process_handle_t *process_handle; + struct process_handle_t *process_handle; int pid; /* The Process ID this managed proxy is using. */ @@ -140,4 +145,3 @@ STATIC void free_execve_args(char **arg); #endif /* defined(PT_PRIVATE) */ #endif /* !defined(TOR_TRANSPORTS_H) */ - diff --git a/src/or/control.c b/src/feature/control/control.c index 09cf833e37..12f10926b7 100644 --- a/src/or/control.c +++ b/src/feature/control/control.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,59 +35,86 @@ #define CONTROL_PRIVATE -#include "or.h" -#include "addressmap.h" -#include "bridges.h" -#include "buffers.h" -#include "channel.h" -#include "channeltls.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "command.h" -#include "compat_libevent.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "dnsserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hibernate.h" -#include "hs_cache.h" -#include "hs_common.h" -#include "hs_control.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "proto_control0.h" -#include "proto_http.h" -#include "reasons.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "shared_random_client.h" +#include "core/or/or.h" +#include "feature/client/addressmap.h" +#include "feature/client/bridges.h" +#include "lib/container/buffers.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "core/or/circuituse.h" +#include "core/or/command.h" +#include "lib/evloop/compat_libevent.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/dnsserv.h" +#include "feature/client/entrynodes.h" +#include "feature/stats/geoip.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_control.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/proto/proto_control0.h" +#include "core/proto/proto_http.h" +#include "core/or/reasons.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/hs_common/shared_random_client.h" +#include "lib/encoding/confline.h" + +#include "feature/dircache/cached_dir_st.h" +#include "feature/control/control_connection_st.h" +#include "core/or/cpath_build_state_st.h" +#include "core/or/entry_connection_st.h" +#include "feature/nodelist/extrainfo_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/or_connection_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/rend/rend_authorized_client_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/rend/rend_service_descriptor_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "core/or/socks_request_st.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif #ifndef _WIN32 #include <pwd.h> #include <sys/resource.h> #endif -#include "crypto_s2k.h" -#include "procmon.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/evloop/procmon.h" +#include "lib/evloop/compat_libevent.h" /** Yield true iff <b>s</b> is the state of a control_connection_t that has * finished authentication and is accepting commands. */ @@ -226,6 +253,15 @@ static void flush_queued_events_cb(mainloop_event_t *event, void *arg); static char * download_status_to_string(const download_status_t *dl); static void control_get_bytes_rw_last_sec(uint64_t *r, uint64_t *w); +/** Convert a connection_t* to an control_connection_t*; assert if the cast is + * invalid. */ +control_connection_t * +TO_CONTROL_CONN(connection_t *c) +{ + tor_assert(c->magic == CONTROL_CONNECTION_MAGIC); + return DOWNCAST(control_connection_t, c); +} + /** Given a control event code for a message event, return the corresponding * log severity. */ static inline int @@ -1857,9 +1893,9 @@ getinfo_helper_misc(control_connection_t *conn, const char *question, } *answer = tor_dup_ip(addr); } else if (!strcmp(question, "traffic/read")) { - tor_asprintf(answer, U64_FORMAT, U64_PRINTF_ARG(get_bytes_read())); + tor_asprintf(answer, "%"PRIu64, (get_bytes_read())); } else if (!strcmp(question, "traffic/written")) { - tor_asprintf(answer, U64_FORMAT, U64_PRINTF_ARG(get_bytes_written())); + tor_asprintf(answer, "%"PRIu64, (get_bytes_written())); } else if (!strcmp(question, "process/pid")) { int myPid = -1; @@ -1894,8 +1930,8 @@ getinfo_helper_misc(control_connection_t *conn, const char *question, int max_fds = get_max_sockets(); tor_asprintf(answer, "%d", max_fds); } else if (!strcmp(question, "limits/max-mem-in-queues")) { - tor_asprintf(answer, U64_FORMAT, - U64_PRINTF_ARG(get_options()->MaxMemInQueues)); + tor_asprintf(answer, "%"PRIu64, + (get_options()->MaxMemInQueues)); } else if (!strcmp(question, "fingerprint")) { crypto_pk_t *server_key; if (!server_mode(get_options())) { @@ -2207,6 +2243,27 @@ getinfo_helper_dir(control_connection_t *control_conn, return -1; } } + } else if (!strcmp(question, "md/all")) { + const smartlist_t *nodes = nodelist_get_list(); + tor_assert(nodes); + + if (smartlist_len(nodes) == 0) { + *answer = tor_strdup(""); + return 0; + } + + smartlist_t *microdescs = smartlist_new(); + + SMARTLIST_FOREACH_BEGIN(nodes, node_t *, n) { + if (n->md && n->md->body) { + char *copy = tor_strndup(n->md->body, n->md->bodylen); + smartlist_add(microdescs, copy); + } + } SMARTLIST_FOREACH_END(n); + + *answer = smartlist_join_strings(microdescs, "", 0, NULL); + SMARTLIST_FOREACH(microdescs, char *, md, tor_free(md)); + smartlist_free(microdescs); } else if (!strcmpstart(question, "md/id/")) { const node_t *node = node_get_by_hex_id(question+strlen("md/id/"), 0); const microdesc_t *md = NULL; @@ -3241,6 +3298,7 @@ static const getinfo_item_t getinfo_items[] = { ITEM("desc/download-enabled", dir, "Do we try to download router descriptors?"), ITEM("desc/all-recent-extrainfo-hack", dir, NULL), /* Hack. */ + ITEM("md/all", dir, "All known microdescriptors."), PREFIX("md/id/", dir, "Microdescriptors by ID"), PREFIX("md/name/", dir, "Microdescriptors by name"), ITEM("md/download-enabled", dir, @@ -3400,6 +3458,7 @@ handle_control_getinfo(control_connection_t *conn, uint32_t len, SPLIT_SKIP_SPACE|SPLIT_IGNORE_BLANK, 0); SMARTLIST_FOREACH_BEGIN(questions, const char *, q) { const char *errmsg = NULL; + if (handle_getinfo_helper(conn, q, &ans, &errmsg) < 0) { if (!errmsg) errmsg = "Internal error"; @@ -4629,7 +4688,7 @@ handle_control_add_onion(control_connection_t *conn, static const char *max_s_prefix = "MaxStreams="; static const char *auth_prefix = "ClientAuth="; - const char *arg = smartlist_get(args, i); + const char *arg = smartlist_get(args, (int)i); if (!strcasecmpstart(arg, port_prefix)) { /* "Port=VIRTPORT[,TARGET]". */ const char *port_str = arg + strlen(port_prefix); @@ -5832,8 +5891,8 @@ control_event_stream_status(entry_connection_t *conn, stream_status_event_t tp, if (circ && CIRCUIT_IS_ORIGIN(circ)) origin_circ = TO_ORIGIN_CIRCUIT(circ); send_control_event(EVENT_STREAM_STATUS, - "650 STREAM "U64_FORMAT" %s %lu %s%s%s%s\r\n", - U64_PRINTF_ARG(ENTRY_TO_CONN(conn)->global_identifier), + "650 STREAM %"PRIu64" %s %lu %s%s%s%s\r\n", + (ENTRY_TO_CONN(conn)->global_identifier), status, origin_circ? (unsigned long)origin_circ->global_identifier : 0ul, @@ -5904,12 +5963,12 @@ control_event_or_conn_status(or_connection_t *conn, or_conn_status_event_t tp, orconn_target_get_name(name, sizeof(name), conn); send_control_event(EVENT_OR_CONN_STATUS, - "650 ORCONN %s %s%s%s%s ID="U64_FORMAT"\r\n", + "650 ORCONN %s %s%s%s%s ID=%"PRIu64"\r\n", name, status, reason ? " REASON=" : "", orconn_end_reason_to_control_string(reason), ncircs_buf, - U64_PRINTF_ARG(conn->base_.global_identifier)); + (conn->base_.global_identifier)); return 0; } @@ -5929,8 +5988,8 @@ control_event_stream_bandwidth(edge_connection_t *edge_conn) tor_gettimeofday(&now); format_iso_time_nospace_usec(tbuf, &now); send_control_event(EVENT_STREAM_BANDWIDTH_USED, - "650 STREAM_BW "U64_FORMAT" %lu %lu %s\r\n", - U64_PRINTF_ARG(edge_conn->base_.global_identifier), + "650 STREAM_BW %"PRIu64" %lu %lu %s\r\n", + (edge_conn->base_.global_identifier), (unsigned long)edge_conn->n_read, (unsigned long)edge_conn->n_written, tbuf); @@ -5963,8 +6022,8 @@ control_event_stream_bandwidth_used(void) tor_gettimeofday(&now); format_iso_time_nospace_usec(tbuf, &now); send_control_event(EVENT_STREAM_BANDWIDTH_USED, - "650 STREAM_BW "U64_FORMAT" %lu %lu %s\r\n", - U64_PRINTF_ARG(edge_conn->base_.global_identifier), + "650 STREAM_BW %"PRIu64" %lu %lu %s\r\n", + (edge_conn->base_.global_identifier), (unsigned long)edge_conn->n_read, (unsigned long)edge_conn->n_written, tbuf); @@ -6042,9 +6101,9 @@ control_event_conn_bandwidth(connection_t *conn) return 0; } send_control_event(EVENT_CONN_BW, - "650 CONN_BW ID="U64_FORMAT" TYPE=%s " + "650 CONN_BW ID=%"PRIu64" TYPE=%s " "READ=%lu WRITTEN=%lu\r\n", - U64_PRINTF_ARG(conn->global_identifier), + (conn->global_identifier), conn_type_str, (unsigned long)conn->n_read_conn_bw, (unsigned long)conn->n_written_conn_bw); @@ -6109,9 +6168,9 @@ append_cell_stats_by_command(smartlist_t *event_parts, const char *key, int i; for (i = 0; i <= CELL_COMMAND_MAX_; i++) { if (include_if_non_zero[i] > 0) { - smartlist_add_asprintf(key_value_strings, "%s:"U64_FORMAT, + smartlist_add_asprintf(key_value_strings, "%s:%"PRIu64, cell_command_to_string(i), - U64_PRINTF_ARG(number_to_include[i])); + (number_to_include[i])); } } if (smartlist_len(key_value_strings) > 0) { @@ -6138,8 +6197,8 @@ format_cell_stats(char **event_string, circuit_t *circ, or_circuit_t *or_circ = TO_OR_CIRCUIT(circ); smartlist_add_asprintf(event_parts, "InboundQueue=%lu", (unsigned long)or_circ->p_circ_id); - smartlist_add_asprintf(event_parts, "InboundConn="U64_FORMAT, - U64_PRINTF_ARG(or_circ->p_chan->global_identifier)); + smartlist_add_asprintf(event_parts, "InboundConn=%"PRIu64, + (or_circ->p_chan->global_identifier)); append_cell_stats_by_command(event_parts, "InboundAdded", cell_stats->added_cells_appward, cell_stats->added_cells_appward); @@ -6153,8 +6212,8 @@ format_cell_stats(char **event_string, circuit_t *circ, if (circ->n_chan) { smartlist_add_asprintf(event_parts, "OutboundQueue=%lu", (unsigned long)circ->n_circ_id); - smartlist_add_asprintf(event_parts, "OutboundConn="U64_FORMAT, - U64_PRINTF_ARG(circ->n_chan->global_identifier)); + smartlist_add_asprintf(event_parts, "OutboundConn=%"PRIu64, + (circ->n_chan->global_identifier)); append_cell_stats_by_command(event_parts, "OutboundAdded", cell_stats->added_cells_exitward, cell_stats->added_cells_exitward); @@ -7741,4 +7800,3 @@ control_testing_set_global_event_mask(uint64_t mask) global_event_mask = mask; } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/or/control.h b/src/feature/control/control.h index 92cbf866dd..5c5fe8a917 100644 --- a/src/or/control.h +++ b/src/feature/control/control.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,93 @@ #ifndef TOR_CONTROL_H #define TOR_CONTROL_H +/** Used to indicate the type of a circuit event passed to the controller. + * The various types are defined in control-spec.txt */ +typedef enum circuit_status_event_t { + CIRC_EVENT_LAUNCHED = 0, + CIRC_EVENT_BUILT = 1, + CIRC_EVENT_EXTENDED = 2, + CIRC_EVENT_FAILED = 3, + CIRC_EVENT_CLOSED = 4, +} circuit_status_event_t; + +/** Used to indicate the type of a CIRC_MINOR event passed to the controller. + * The various types are defined in control-spec.txt . */ +typedef enum circuit_status_minor_event_t { + CIRC_MINOR_EVENT_PURPOSE_CHANGED, + CIRC_MINOR_EVENT_CANNIBALIZED, +} circuit_status_minor_event_t; + +/** Used to indicate the type of a stream event passed to the controller. + * The various types are defined in control-spec.txt */ +typedef enum stream_status_event_t { + STREAM_EVENT_SENT_CONNECT = 0, + STREAM_EVENT_SENT_RESOLVE = 1, + STREAM_EVENT_SUCCEEDED = 2, + STREAM_EVENT_FAILED = 3, + STREAM_EVENT_CLOSED = 4, + STREAM_EVENT_NEW = 5, + STREAM_EVENT_NEW_RESOLVE = 6, + STREAM_EVENT_FAILED_RETRIABLE = 7, + STREAM_EVENT_REMAP = 8 +} stream_status_event_t; + +/** Used to indicate the type of an OR connection event passed to the + * controller. The various types are defined in control-spec.txt */ +typedef enum or_conn_status_event_t { + OR_CONN_EVENT_LAUNCHED = 0, + OR_CONN_EVENT_CONNECTED = 1, + OR_CONN_EVENT_FAILED = 2, + OR_CONN_EVENT_CLOSED = 3, + OR_CONN_EVENT_NEW = 4, +} or_conn_status_event_t; + +/** Used to indicate the type of a buildtime event */ +typedef enum buildtimeout_set_event_t { + BUILDTIMEOUT_SET_EVENT_COMPUTED = 0, + BUILDTIMEOUT_SET_EVENT_RESET = 1, + BUILDTIMEOUT_SET_EVENT_SUSPENDED = 2, + BUILDTIMEOUT_SET_EVENT_DISCARD = 3, + BUILDTIMEOUT_SET_EVENT_RESUME = 4 +} buildtimeout_set_event_t; + +/** Enum describing various stages of bootstrapping, for use with controller + * bootstrap status events. The values range from 0 to 100. */ +typedef enum { + BOOTSTRAP_STATUS_UNDEF=-1, + BOOTSTRAP_STATUS_STARTING=0, + BOOTSTRAP_STATUS_CONN_DIR=5, + BOOTSTRAP_STATUS_HANDSHAKE=-2, + BOOTSTRAP_STATUS_HANDSHAKE_DIR=10, + BOOTSTRAP_STATUS_ONEHOP_CREATE=15, + BOOTSTRAP_STATUS_REQUESTING_STATUS=20, + BOOTSTRAP_STATUS_LOADING_STATUS=25, + BOOTSTRAP_STATUS_LOADING_KEYS=40, + BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS=45, + BOOTSTRAP_STATUS_LOADING_DESCRIPTORS=50, + BOOTSTRAP_STATUS_CONN_OR=80, + BOOTSTRAP_STATUS_HANDSHAKE_OR=85, + BOOTSTRAP_STATUS_CIRCUIT_CREATE=90, + BOOTSTRAP_STATUS_DONE=100 +} bootstrap_status_t; + +control_connection_t *TO_CONTROL_CONN(connection_t *); + +#define CONTROL_CONN_STATE_MIN_ 1 +/** State for a control connection: Authenticated and accepting v1 commands. */ +#define CONTROL_CONN_STATE_OPEN 1 +/** State for a control connection: Waiting for authentication; speaking + * protocol v1. */ +#define CONTROL_CONN_STATE_NEEDAUTH 2 +#define CONTROL_CONN_STATE_MAX_ 2 + +/** Reason for remapping an AP connection's address: we have a cached + * answer. */ +#define REMAP_STREAM_SOURCE_CACHE 1 +/** Reason for remapping an AP connection's address: the exit node told us an + * answer. */ +#define REMAP_STREAM_SOURCE_EXIT 2 + void control_initialize_event_queue(void); void control_update_global_event_mask(void); @@ -97,7 +184,8 @@ int control_event_signal(uintptr_t signal); int init_control_cookie_authentication(int enabled); char *get_controller_cookie_file_name(void); -smartlist_t *decode_hashed_passwords(config_line_t *passwords); +struct config_line_t; +smartlist_t *decode_hashed_passwords(struct config_line_t *passwords); void disable_control_logging(void); void enable_control_logging(void); @@ -160,6 +248,8 @@ void control_event_hs_descriptor_content(const char *onion_address, void control_free_all(void); #ifdef CONTROL_PRIVATE +#include "lib/crypt_ops/crypto_ed25519.h" + /* Recognized asynchronous event types. It's okay to expand this list * because it is used both as a list of v0 event types, and as indices * into the bitfield to determine which controllers want which events. @@ -323,4 +413,3 @@ STATIC int getinfo_helper_current_time( #endif /* defined(CONTROL_PRIVATE) */ #endif /* !defined(TOR_CONTROL_H) */ - diff --git a/src/feature/control/control_connection_st.h b/src/feature/control/control_connection_st.h new file mode 100644 index 0000000000..ff6264a9a5 --- /dev/null +++ b/src/feature/control/control_connection_st.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CONTROL_CONNECTION_ST_H +#define CONTROL_CONNECTION_ST_H + +#include "core/or/or.h" +#include "core/or/connection_st.h" + +/** Subtype of connection_t for an connection to a controller. */ +struct control_connection_t { + connection_t base_; + + uint64_t event_mask; /**< Bitfield: which events does this controller + * care about? + * EVENT_MAX_ is >31, so we need a 64 bit mask */ + + /** True if we have sent a protocolinfo reply on this connection. */ + unsigned int have_sent_protocolinfo:1; + /** True if we have received a takeownership command on this + * connection. */ + unsigned int is_owning_control_connection:1; + + /** List of ephemeral onion services belonging to this connection. */ + smartlist_t *ephemeral_onion_services; + + /** If we have sent an AUTHCHALLENGE reply on this connection and + * have not received a successful AUTHENTICATE command, points to + * the value which the client must send to authenticate itself; + * otherwise, NULL. */ + char *safecookie_client_hash; + + /** Amount of space allocated in incoming_cmd. */ + uint32_t incoming_cmd_len; + /** Number of bytes currently stored in incoming_cmd. */ + uint32_t incoming_cmd_cur_len; + /** A control command that we're reading from the inbuf, but which has not + * yet arrived completely. */ + char *incoming_cmd; +}; + +#endif + diff --git a/src/or/dirauth/dircollate.c b/src/feature/dirauth/dircollate.c index dec6f75154..ca8e5b7873 100644 --- a/src/or/dirauth/dircollate.c +++ b/src/feature/dirauth/dircollate.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,8 +22,11 @@ */ #define DIRCOLLATE_PRIVATE -#include "dircollate.h" -#include "dirvote.h" +#include "feature/dirauth/dircollate.h" +#include "feature/dirauth/dirvote.h" + +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" static void dircollator_collate_by_ed25519(dircollator_t *dc); diff --git a/src/or/dirauth/dircollate.h b/src/feature/dirauth/dircollate.h index 0584b2fe06..0e84c66e6f 100644 --- a/src/or/dirauth/dircollate.h +++ b/src/feature/dirauth/dircollate.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,8 @@ #ifndef TOR_DIRCOLLATE_H #define TOR_DIRCOLLATE_H -#include "testsupport.h" -#include "or.h" +#include "lib/testsupport/testsupport.h" +#include "core/or/or.h" typedef struct dircollator_s dircollator_t; diff --git a/src/or/dirauth/dirvote.c b/src/feature/dirauth/dirvote.c index b097b10cf9..ce67c1bb9a 100644 --- a/src/or/dirauth/dirvote.c +++ b/src/feature/dirauth/dirvote.c @@ -1,32 +1,51 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRVOTE_PRIVATE -#include "or.h" -#include "config.h" -#include "dircollate.h" -#include "directory.h" -#include "dirserv.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "parsecommon.h" -#include "policies.h" -#include "protover.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "entrynodes.h" /* needed for guardfraction methods */ -#include "torcert.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random_state.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/dirauth/dircollate.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/parsecommon.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/client/entrynodes.h" /* needed for guardfraction methods */ +#include "feature/nodelist/torcert.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/mode.h" +#include "feature/dirauth/shared_random_state.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "feature/dircache/cached_dir_st.h" +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/document_signature_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/networkstatus_voter_info_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/dirauth/ns_detached_signatures_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "feature/dirauth/vote_microdesc_hash_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" +#include "feature/dircommon/vote_timing_st.h" + +#include "lib/container/order.h" +#include "lib/encoding/confline.h" +#include "lib/crypt_ops/crypto_format.h" /** * \file dirvote.c @@ -982,13 +1001,13 @@ networkstatus_check_weights(int64_t Wgg, int64_t Wgd, int64_t Wmg, out: if (berr) { log_info(LD_DIR, - "Bw weight mismatch %d. G="I64_FORMAT" M="I64_FORMAT - " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + "Bw weight mismatch %d. G=%"PRId64" M=%"PRId64 + " E=%"PRId64" D=%"PRId64" T=%"PRId64 " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" " Wgd=%d Wgg=%d Wme=%d Wmg=%d", berr, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg); } @@ -1014,10 +1033,10 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, if (G <= 0 || M <= 0 || E <= 0 || D <= 0) { log_warn(LD_DIR, "Consensus with empty bandwidth: " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT - " D="I64_FORMAT" T="I64_FORMAT, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + "G=%"PRId64" M=%"PRId64" E=%"PRId64 + " D=%"PRId64" T=%"PRId64, + (G), (M), (E), + (D), (T)); return 0; } @@ -1048,13 +1067,13 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, if (berr) { log_warn(LD_DIR, - "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT - " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + "Bw Weights error %d for %s v10. G=%"PRId64" M=%"PRId64 + " E=%"PRId64" D=%"PRId64" T=%"PRId64 " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", berr, casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); return 0; @@ -1119,13 +1138,13 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, if (berr != BW_WEIGHTS_NO_ERROR && berr != BW_WEIGHTS_BALANCE_MID_ERROR) { log_warn(LD_DIR, - "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT - " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + "Bw Weights error %d for %s v10. G=%"PRId64" M=%"PRId64 + " E=%"PRId64" D=%"PRId64" T=%"PRId64 " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", berr, casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); return 0; @@ -1136,10 +1155,10 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, // Case 3: Exactly one of Guard or Exit is scarce if (!(3*E < T || 3*G < T) || !(3*G >= T || 3*E >= T)) { log_warn(LD_BUG, - "Bw-Weights Case 3 v10 but with G="I64_FORMAT" M=" - I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + "Bw-Weights Case 3 v10 but with G=%"PRId64" M=" + "%"PRId64" E=%"PRId64" D=%"PRId64" T=%"PRId64, + (G), (M), (E), + (D), (T)); } if (3*(S+D) < T) { // Subcase a: S+D < T/3 @@ -1191,13 +1210,13 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, } if (berr) { log_warn(LD_DIR, - "Bw Weights error %d for %s v10. G="I64_FORMAT" M="I64_FORMAT - " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT + "Bw Weights error %d for %s v10. G=%"PRId64" M=%"PRId64 + " E=%"PRId64" D=%"PRId64" T=%"PRId64 " Wmd=%d Wme=%d Wmg=%d Wed=%d Wee=%d" " Wgd=%d Wgg=%d Wme=%d Wmg=%d weight_scale=%d", berr, casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), (int)Wmd, (int)Wme, (int)Wmg, (int)Wed, (int)Wee, (int)Wgd, (int)Wgg, (int)Wme, (int)Wmg, (int)weight_scale); return 0; @@ -1231,11 +1250,11 @@ networkstatus_compute_bw_weights_v10(smartlist_t *chunks, int64_t G, (int)weight_scale, (int)Wmd, (int)Wme, (int)Wmg, (int)weight_scale); log_notice(LD_CIRC, "Computed bandwidth weights for %s with v10: " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT, + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64, casename, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T)); + (G), (M), (E), + (D), (T)); return 1; } @@ -1739,9 +1758,9 @@ networkstatus_compute_consensus(smartlist_t *votes, /* Build the flag indexes. Note that no vote can have more than 64 members * for known_flags, so no value will be greater than 63, so it's safe to - * do U64_LITERAL(1) << index on these values. But note also that + * do UINT64_C(1) << index on these values. But note also that * named_flag and unnamed_flag are initialized to -1, so we need to check - * that they're actually set before doing U64_LITERAL(1) << index with + * that they're actually set before doing UINT64_C(1) << index with * them.*/ SMARTLIST_FOREACH_BEGIN(votes, networkstatus_t *, v) { flag_map[v_sl_idx] = tor_calloc(smartlist_len(v->known_flags), @@ -1770,7 +1789,7 @@ networkstatus_compute_consensus(smartlist_t *votes, uint64_t nf; if (named_flag[v_sl_idx]<0) continue; - nf = U64_LITERAL(1) << named_flag[v_sl_idx]; + nf = UINT64_C(1) << named_flag[v_sl_idx]; SMARTLIST_FOREACH_BEGIN(v->routerstatus_list, vote_routerstatus_t *, rs) { @@ -1795,7 +1814,7 @@ networkstatus_compute_consensus(smartlist_t *votes, uint64_t uf; if (unnamed_flag[v_sl_idx]<0) continue; - uf = U64_LITERAL(1) << unnamed_flag[v_sl_idx]; + uf = UINT64_C(1) << unnamed_flag[v_sl_idx]; SMARTLIST_FOREACH_BEGIN(v->routerstatus_list, vote_routerstatus_t *, rs) { if ((rs->flags & uf) != 0) { @@ -1885,11 +1904,11 @@ networkstatus_compute_consensus(smartlist_t *votes, /* Tally up all the flags. */ for (int flag = 0; flag < n_voter_flags[voter_idx]; ++flag) { - if (rs->flags & (U64_LITERAL(1) << flag)) + if (rs->flags & (UINT64_C(1) << flag)) ++flag_counts[flag_map[voter_idx][flag]]; } if (named_flag[voter_idx] >= 0 && - (rs->flags & (U64_LITERAL(1) << named_flag[voter_idx]))) { + (rs->flags & (UINT64_C(1) << named_flag[voter_idx]))) { if (chosen_name && strcmp(chosen_name, rs->status.nickname)) { log_notice(LD_DIR, "Conflict on naming for router: %s vs %s", chosen_name, rs->status.nickname); @@ -4220,7 +4239,7 @@ routers_make_ed_keys_unique(smartlist_t *routers) if (ri2_pub < ri_pub || (ri2_pub == ri_pub && fast_memcmp(ri->cache_info.signed_descriptor_digest, - ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) { + ri2->cache_info.signed_descriptor_digest,DIGEST_LEN)<0)) { digest256map_set(by_ed_key, pk, ri); ri2->omit_from_vote = 1; } else { @@ -4393,10 +4412,10 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, vrs->protocols = tor_strdup(ri->protocol_list); } else { vrs->protocols = tor_strdup( - protover_compute_for_old_tor(vrs->version)); + protover_compute_for_old_tor(vrs->version)); } vrs->microdesc = dirvote_format_all_microdesc_vote_lines(ri, now, - microdescriptors); + microdescriptors); smartlist_add(routerstatuses, vrs); } @@ -4489,9 +4508,9 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, /* We should not recommend anything we don't have. */ tor_assert_nonfatal(protover_all_supported( - v3_out->recommended_relay_protocols, NULL)); + v3_out->recommended_relay_protocols, NULL)); tor_assert_nonfatal(protover_all_supported( - v3_out->recommended_client_protocols, NULL)); + v3_out->recommended_client_protocols, NULL)); v3_out->package_lines = smartlist_new(); { @@ -4547,4 +4566,3 @@ dirserv_generate_networkstatus_vote_obj(crypto_pk_t *private_key, return v3_out; } - diff --git a/src/or/dirauth/dirvote.h b/src/feature/dirauth/dirvote.h index b69bbbf5d9..7ce8e4a699 100644 --- a/src/or/dirauth/dirvote.h +++ b/src/feature/dirauth/dirvote.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -164,7 +164,8 @@ dirvote_add_vote(const char *vote_body, const char **msg_out, int *status_out) } static inline int -dirvote_add_signatures(const char *detached_signatures_body, const char *source, +dirvote_add_signatures(const char *detached_signatures_body, + const char *source, const char **msg_out) { (void) detached_signatures_body; @@ -244,4 +245,3 @@ STATIC microdesc_t *dirvote_create_microdescriptor(const routerinfo_t *ri, #endif /* defined(DIRVOTE_PRIVATE) */ #endif /* !defined(TOR_DIRVOTE_H) */ - diff --git a/src/or/keypin.c b/src/feature/dirauth/keypin.c index 97e16c1f78..44e19985fa 100644 --- a/src/or/keypin.c +++ b/src/feature/dirauth/keypin.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,17 +11,28 @@ #define KEYPIN_PRIVATE #include "orconfig.h" -#include "compat.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "di_ops.h" + +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/ctime/di_ops.h" +#include "lib/ctime/di_ops.h" +#include "lib/encoding/binascii.h" +#include "lib/encoding/time_fmt.h" +#include "lib/fdio/fdio.h" +#include "lib/fs/files.h" +#include "lib/fs/mmap.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/printf.h" +#include "lib/wallclock/approx_time.h" + #include "ht.h" -#include "keypin.h" +#include "feature/dirauth/keypin.h" + #include "siphash.h" -#include "torint.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -34,6 +45,10 @@ #include <io.h> #endif +#include <errno.h> +#include <string.h> +#include <stdlib.h> + /** * @file keypin.c * @brief Key-pinning for RSA and Ed25519 identity keys at directory @@ -308,7 +323,7 @@ keypin_open_journal(const char *fname) char tbuf[ISO_TIME_LEN+1]; format_iso_time(tbuf, approx_time()); tor_snprintf(buf, sizeof(buf), "@opened-at %s\n", tbuf); - if (write_all(fd, buf, strlen(buf), 0) < 0) + if (write_all_to_fd(fd, buf, strlen(buf)) < 0) goto err; keypin_journal_fd = fd; @@ -347,7 +362,7 @@ keypin_journal_append_entry(const uint8_t *rsa_id_digest, (const char*)ed25519_id_key); line[BASE64_DIGEST_LEN+1+BASE64_DIGEST256_LEN] = '\n'; - if (write_all(keypin_journal_fd, line, JOURNAL_LINE_LEN, 0)<0) { + if (write_all_to_fd(keypin_journal_fd, line, JOURNAL_LINE_LEN)<0) { log_warn(LD_DIRSERV, "Error while adding a line to the key-pinning " "journal: %s", strerror(errno)); keypin_close_journal(); @@ -498,4 +513,3 @@ keypin_clear(void) bad_entries); } } - diff --git a/src/or/keypin.h b/src/feature/dirauth/keypin.h index fbb77e5c35..73a76be563 100644 --- a/src/or/keypin.h +++ b/src/feature/dirauth/keypin.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_KEYPIN_H #define TOR_KEYPIN_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" int keypin_check_and_add(const uint8_t *rsa_id_digest, const uint8_t *ed25519_id_key, diff --git a/src/or/dirauth/mode.h b/src/feature/dirauth/mode.h index 8a0d3142f1..8bb961dffb 100644 --- a/src/or/dirauth/mode.h +++ b/src/feature/dirauth/mode.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,7 @@ #ifdef HAVE_MODULE_DIRAUTH -#include "router.h" +#include "feature/relay/router.h" /* Return true iff we believe ourselves to be a v3 authoritative directory * server. */ diff --git a/src/feature/dirauth/ns_detached_signatures_st.h b/src/feature/dirauth/ns_detached_signatures_st.h new file mode 100644 index 0000000000..26ceec84b9 --- /dev/null +++ b/src/feature/dirauth/ns_detached_signatures_st.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NS_DETACHED_SIGNATURES_ST_H +#define NS_DETACHED_SIGNATURES_ST_H + +/** A set of signatures for a networkstatus consensus. Unless otherwise + * noted, all fields are as for networkstatus_t. */ +struct ns_detached_signatures_t { + time_t valid_after; + time_t fresh_until; + time_t valid_until; + strmap_t *digests; /**< Map from flavor name to digestset_t */ + strmap_t *signatures; /**< Map from flavor name to list of + * document_signature_t */ +}; + +#endif + diff --git a/src/or/dirauth/shared_random.c b/src/feature/dirauth/shared_random.c index 6dd1f330e0..8ae2679779 100644 --- a/src/or/dirauth/shared_random.c +++ b/src/feature/dirauth/shared_random.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -87,23 +87,25 @@ #define SHARED_RANDOM_PRIVATE -#include "or.h" -#include "shared_random.h" -#include "config.h" -#include "confparse.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "networkstatus.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "shared_random_client.h" -#include "shared_random_state.h" -#include "util.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" +#include "core/or/or.h" +#include "feature/dirauth/shared_random.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/hs_common/shared_random_client.h" +#include "feature/dirauth/shared_random_state.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/mode.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "feature/nodelist/networkstatus_st.h" /* String prefix of shared random values in votes/consensuses. */ static const char previous_srv_str[] = "shared-rand-previous-value"; diff --git a/src/or/dirauth/shared_random.h b/src/feature/dirauth/shared_random.h index 1778ce8f09..68ece9aec0 100644 --- a/src/or/dirauth/shared_random.h +++ b/src/feature/dirauth/shared_random.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SHARED_RANDOM_H @@ -10,7 +10,7 @@ * with "sr_" which stands for shared random. */ -#include "or.h" +#include "core/or/or.h" /* Protocol version */ #define SR_PROTO_VERSION 1 diff --git a/src/or/dirauth/shared_random_state.c b/src/feature/dirauth/shared_random_state.c index fc0e4e5630..55936a7367 100644 --- a/src/or/dirauth/shared_random_state.c +++ b/src/feature/dirauth/shared_random_state.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,17 +10,20 @@ #define SHARED_RANDOM_STATE_PRIVATE -#include "or.h" -#include "config.h" -#include "confparse.h" -#include "crypto_util.h" -#include "dirauth/dirvote.h" -#include "networkstatus.h" -#include "router.h" -#include "shared_random.h" -#include "shared_random_client.h" -#include "shared_random_state.h" -#include "voting_schedule.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dirauth/dirvote.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/relay/router.h" +#include "feature/dirauth/shared_random.h" +#include "feature/hs_common/shared_random_client.h" +#include "feature/dirauth/shared_random_state.h" +#include "feature/dircommon/voting_schedule.h" +#include "lib/encoding/confline.h" + +#include "app/config/or_state_st.h" /* Default filename of the shared random state on disk. */ static const char default_fname[] = "sr-state"; @@ -1321,4 +1324,3 @@ get_sr_state(void) } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/or/dirauth/shared_random_state.h b/src/feature/dirauth/shared_random_state.h index 60a326f86c..83edfaf103 100644 --- a/src/or/dirauth/shared_random_state.h +++ b/src/feature/dirauth/shared_random_state.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_SHARED_RANDOM_STATE_H #define TOR_SHARED_RANDOM_STATE_H -#include "shared_random.h" +#include "feature/dirauth/shared_random.h" /* Action that can be performed on the state for any objects. */ typedef enum { @@ -85,11 +85,11 @@ typedef struct sr_disk_state_t { /* State valid until? */ time_t ValidUntil; /* All commits seen that are valid. */ - config_line_t *Commit; + struct config_line_t *Commit; /* Previous and current shared random value. */ - config_line_t *SharedRandValues; + struct config_line_t *SharedRandValues; /* Extra Lines for configuration we might not know. */ - config_line_t *ExtraLines; + struct config_line_t *ExtraLines; } sr_disk_state_t; /* API */ @@ -144,4 +144,3 @@ STATIC sr_state_t *get_sr_state(void); #endif /* defined(TOR_UNIT_TESTS) */ #endif /* !defined(TOR_SHARED_RANDOM_STATE_H) */ - diff --git a/src/feature/dirauth/vote_microdesc_hash_st.h b/src/feature/dirauth/vote_microdesc_hash_st.h new file mode 100644 index 0000000000..31fc98040e --- /dev/null +++ b/src/feature/dirauth/vote_microdesc_hash_st.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VOTE_MICRODESC_HASH_ST_H +#define VOTE_MICRODESC_HASH_ST_H + +/** Linked list of microdesc hash lines for a single router in a directory + * vote. + */ +struct vote_microdesc_hash_t { + /** Next element in the list, or NULL. */ + struct vote_microdesc_hash_t *next; + /** The raw contents of the microdesc hash line, from the "m" through the + * newline. */ + char *microdesc_hash_line; +}; + +#endif + diff --git a/src/feature/dircache/cached_dir_st.h b/src/feature/dircache/cached_dir_st.h new file mode 100644 index 0000000000..38ae86d975 --- /dev/null +++ b/src/feature/dircache/cached_dir_st.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef CACHED_DIR_ST_H +#define CACHED_DIR_ST_H + +/** A cached_dir_t represents a cacheable directory object, along with its + * compressed form. */ +struct cached_dir_t { + char *dir; /**< Contents of this object, NUL-terminated. */ + char *dir_compressed; /**< Compressed contents of this object. */ + size_t dir_len; /**< Length of <b>dir</b> (not counting its NUL). */ + size_t dir_compressed_len; /**< Length of <b>dir_compressed</b>. */ + time_t published; /**< When was this object published. */ + common_digests_t digests; /**< Digests of this object (networkstatus only) */ + /** Sha3 digest (also ns only) */ + uint8_t digest_sha3_as_signed[DIGEST256_LEN]; + int refcnt; /**< Reference count for this cached_dir_t. */ +}; + +#endif + diff --git a/src/or/conscache.c b/src/feature/dircache/conscache.c index 51dc9d621f..e9bf58a180 100644 --- a/src/or/conscache.c +++ b/src/feature/dircache/conscache.c @@ -1,12 +1,13 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "core/or/or.h" -#include "config.h" -#include "conscache.h" -#include "crypto_util.h" -#include "storagedir.h" +#include "app/config/config.h" +#include "feature/dircache/conscache.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/fs/storagedir.h" +#include "lib/encoding/confline.h" #define CCE_MAGIC 0x17162253 @@ -624,4 +625,3 @@ consensus_cache_entry_is_mapped(consensus_cache_entry_t *ent) } } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/or/conscache.h b/src/feature/dircache/conscache.h index 08a5c5a37b..c274a60393 100644 --- a/src/or/conscache.h +++ b/src/feature/dircache/conscache.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONSCACHE_H #define TOR_CONSCACHE_H -#include "handles.h" +#include "lib/container/handles.h" typedef struct consensus_cache_entry_t consensus_cache_entry_t; typedef struct consensus_cache_t consensus_cache_t; @@ -27,9 +27,9 @@ void consensus_cache_delete_pending(consensus_cache_t *cache, int force); int consensus_cache_get_n_filenames_available(consensus_cache_t *cache); consensus_cache_entry_t *consensus_cache_add(consensus_cache_t *cache, - const config_line_t *labels, - const uint8_t *data, - size_t datalen); + const struct config_line_t *labels, + const uint8_t *data, + size_t datalen); consensus_cache_entry_t *consensus_cache_find_first( consensus_cache_t *cache, @@ -46,7 +46,7 @@ void consensus_cache_filter_list(smartlist_t *lst, const char *consensus_cache_entry_get_value(const consensus_cache_entry_t *ent, const char *key); -const config_line_t *consensus_cache_entry_get_labels( +const struct config_line_t *consensus_cache_entry_get_labels( const consensus_cache_entry_t *ent); void consensus_cache_entry_incref(consensus_cache_entry_t *ent); @@ -64,4 +64,3 @@ int consensus_cache_entry_is_mapped(consensus_cache_entry_t *ent); #endif #endif /* !defined(TOR_CONSCACHE_H) */ - diff --git a/src/or/consdiffmgr.c b/src/feature/dircache/consdiffmgr.c index 323f4f9ca0..304b64f3b6 100644 --- a/src/or/consdiffmgr.c +++ b/src/feature/dircache/consdiffmgr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,15 +13,21 @@ #define CONSDIFFMGR_PRIVATE -#include "or.h" -#include "config.h" -#include "conscache.h" -#include "consdiff.h" -#include "consdiffmgr.h" -#include "cpuworker.h" -#include "networkstatus.h" -#include "routerparse.h" -#include "workqueue.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/dircache/conscache.h" +#include "feature/dircommon/consdiff.h" +#include "feature/dircache/consdiffmgr.h" +#include "core/mainloop/cpuworker.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/routerparse.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/evloop/workqueue.h" +#include "lib/compress/compress.h" +#include "lib/encoding/confline.h" + +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/networkstatus_voter_info_st.h" /** * Labels to apply to items in the conscache object. @@ -1937,4 +1943,3 @@ consensus_cache_entry_get_valid_after(const consensus_cache_entry_t *ent, else return 0; } - diff --git a/src/or/consdiffmgr.h b/src/feature/dircache/consdiffmgr.h index df569c8e23..66c3d65002 100644 --- a/src/or/consdiffmgr.h +++ b/src/feature/dircache/consdiffmgr.h @@ -1,9 +1,11 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONSDIFFMGR_H #define TOR_CONSDIFFMGR_H +enum compress_method_t; + /** * Possible outcomes from trying to look up a given consensus diff. */ @@ -25,7 +27,7 @@ int consdiffmgr_add_consensus(const char *consensus, consdiff_status_t consdiffmgr_find_consensus( struct consensus_cache_entry_t **entry_out, consensus_flavor_t flavor, - compress_method_t method); + enum compress_method_t method); consdiff_status_t consdiffmgr_find_diff_from( struct consensus_cache_entry_t **entry_out, @@ -33,7 +35,7 @@ consdiff_status_t consdiffmgr_find_diff_from( int digest_type, const uint8_t *digest, size_t digestlen, - compress_method_t method); + enum compress_method_t method); int consensus_cache_entry_get_voter_id_digests( const struct consensus_cache_entry_t *ent, @@ -71,4 +73,3 @@ STATIC int uncompress_or_copy(char **out, size_t *outlen, #endif /* defined(CONSDIFFMGR_PRIVATE) */ #endif /* !defined(TOR_CONSDIFFMGR_H) */ - diff --git a/src/or/directory.c b/src/feature/dircache/directory.c index e763de268f..a723176185 100644 --- a/src/or/directory.c +++ b/src/feature/dircache/directory.c @@ -1,47 +1,50 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRECTORY_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "bridges.h" -#include "buffers.h" -#include "circuitbuild.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "conscache.h" -#include "consdiff.h" -#include "consdiffmgr.h" -#include "control.h" -#include "compat.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hs_cache.h" -#include "hs_common.h" -#include "hs_control.h" -#include "hs_client.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" +#include "core/or/or.h" +#include "lib/err/backtrace.h" +#include "feature/client/bridges.h" +#include "lib/container/buffers.h" +#include "core/or/circuitbuild.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/dircache/conscache.h" +#include "feature/dircommon/consdiff.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/control/control.h" +#include "lib/compress/compress.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/entrynodes.h" +#include "feature/dircommon/fp_pair.h" +#include "feature/stats/geoip.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_control.h" +#include "feature/hs/hs_client.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/or/relay.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "lib/encoding/confline.h" +#include "lib/crypt_ops/crypto_format.h" #if defined(EXPORTMALLINFO) && defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) #if !defined(OpenBSD) @@ -49,9 +52,19 @@ #endif #endif -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random.h" +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/mode.h" +#include "feature/dirauth/shared_random.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "feature/dircache/cached_dir_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/dirclient/dir_server_st.h" +#include "core/or/entry_connection_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/rend/rend_service_descriptor_st.h" +#include "feature/nodelist/routerinfo_st.h" /** * \file directory.c @@ -131,6 +144,15 @@ static void connection_dir_close_consensus_fetches( /********* START VARIABLES **********/ +/** Maximum size, in bytes, for resized buffers. */ +#define MAX_BUF_SIZE ((1<<24)-1) /* 16MB-1 */ +/** Maximum size, in bytes, for any directory object that we've downloaded. */ +#define MAX_DIR_DL_SIZE MAX_BUF_SIZE + +/** Maximum size, in bytes, for any directory object that we're accepting + * as an upload. */ +#define MAX_DIR_UL_SIZE MAX_BUF_SIZE + /** How far in the future do we allow a directory server to tell us it is * before deciding that one of us has the wrong time? */ #define ALLOW_DIRECTORY_TIME_SKEW (30*60) @@ -151,6 +173,15 @@ static void connection_dir_close_consensus_fetches( /********* END VARIABLES ************/ +/** Convert a connection_t* to a dir_connection_t*; assert if the cast is + * invalid. */ +dir_connection_t * +TO_DIR_CONN(connection_t *c) +{ + tor_assert(c->magic == DIR_CONNECTION_MAGIC); + return DOWNCAST(dir_connection_t, c); +} + /** Return false if the directory purpose <b>dir_purpose</b> * does not require an anonymous (three-hop) connection. * @@ -1910,12 +1941,12 @@ directory_send_command(dir_connection_t *conn, log_debug(LD_DIR, "Sent request to directory server '%s:%d': " - "(purpose: %d, request size: " U64_FORMAT ", " - "payload size: " U64_FORMAT ")", + "(purpose: %d, request size: %"TOR_PRIuSZ", " + "payload size: %"TOR_PRIuSZ")", conn->base_.address, conn->base_.port, conn->base_.purpose, - U64_PRINTF_ARG(total_request_len), - U64_PRINTF_ARG(payload ? payload_len : 0)); + (total_request_len), + (payload ? payload_len : 0)); } /** Parse an HTTP request string <b>headers</b> of the form @@ -2401,14 +2432,14 @@ connection_dir_client_reached_eof(dir_connection_t *conn) tor_log(LOG_DEBUG, LD_DIR, "Received response from directory server '%s:%d': %d %s " - "(purpose: %d, response size: " U64_FORMAT + "(purpose: %d, response size: %"TOR_PRIuSZ #ifdef MEASUREMENTS_21206 ", data cells received: %d, data cells sent: %d" #endif ", compression: %d)", conn->base_.address, conn->base_.port, status_code, escaped(reason), conn->base_.purpose, - U64_PRINTF_ARG(received_bytes), + (received_bytes), #ifdef MEASUREMENTS_21206 conn->data_cells_received, conn->data_cells_sent, #endif @@ -5614,6 +5645,27 @@ download_status_reset(download_status_t *dls) /* Don't reset dls->want_authority or dls->increment_on */ } +/** Return true iff, as of <b>now</b>, the resource tracked by <b>dls</b> is + * ready to get its download reattempted. */ +int +download_status_is_ready(download_status_t *dls, time_t now) +{ + /* dls wasn't reset before it was used */ + if (dls->next_attempt_at == 0) { + download_status_reset(dls); + } + + return download_status_get_next_attempt_at(dls) <= now; +} + +/** Mark <b>dl</b> as never downloadable. */ +void +download_status_mark_impossible(download_status_t *dl) +{ + dl->n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; + dl->n_download_attempts = IMPOSSIBLE_TO_DOWNLOAD; +} + /** Return the number of failures on <b>dls</b> since the last success (if * any). */ int @@ -5912,4 +5964,3 @@ dir_split_resource_into_spoolable(const char *resource, smartlist_free(fingerprints); return r; } - diff --git a/src/or/directory.h b/src/feature/dircache/directory.h index 5f5ff7eca6..54ea0c584d 100644 --- a/src/or/directory.h +++ b/src/feature/dircache/directory.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,82 @@ #ifndef TOR_DIRECTORY_H #define TOR_DIRECTORY_H -#include "hs_ident.h" +#include "feature/hs/hs_ident.h" +enum compress_method_t; + +dir_connection_t *TO_DIR_CONN(connection_t *c); + +#define DIR_CONN_STATE_MIN_ 1 +/** State for connection to directory server: waiting for connect(). */ +#define DIR_CONN_STATE_CONNECTING 1 +/** State for connection to directory server: sending HTTP request. */ +#define DIR_CONN_STATE_CLIENT_SENDING 2 +/** State for connection to directory server: reading HTTP response. */ +#define DIR_CONN_STATE_CLIENT_READING 3 +/** State for connection to directory server: happy and finished. */ +#define DIR_CONN_STATE_CLIENT_FINISHED 4 +/** State for connection at directory server: waiting for HTTP request. */ +#define DIR_CONN_STATE_SERVER_COMMAND_WAIT 5 +/** State for connection at directory server: sending HTTP response. */ +#define DIR_CONN_STATE_SERVER_WRITING 6 +#define DIR_CONN_STATE_MAX_ 6 + +#define DIR_PURPOSE_MIN_ 4 +/** A connection to a directory server: set after a v2 rendezvous + * descriptor is downloaded. */ +#define DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 4 +/** A connection to a directory server: download one or more server + * descriptors. */ +#define DIR_PURPOSE_FETCH_SERVERDESC 6 +/** A connection to a directory server: download one or more extra-info + * documents. */ +#define DIR_PURPOSE_FETCH_EXTRAINFO 7 +/** A connection to a directory server: upload a server descriptor. */ +#define DIR_PURPOSE_UPLOAD_DIR 8 +/** A connection to a directory server: upload a v3 networkstatus vote. */ +#define DIR_PURPOSE_UPLOAD_VOTE 10 +/** A connection to a directory server: upload a v3 consensus signature */ +#define DIR_PURPOSE_UPLOAD_SIGNATURES 11 +/** A connection to a directory server: download one or more v3 networkstatus + * votes. */ +#define DIR_PURPOSE_FETCH_STATUS_VOTE 12 +/** A connection to a directory server: download a v3 detached signatures + * object for a consensus. */ +#define DIR_PURPOSE_FETCH_DETACHED_SIGNATURES 13 +/** A connection to a directory server: download a v3 networkstatus + * consensus. */ +#define DIR_PURPOSE_FETCH_CONSENSUS 14 +/** A connection to a directory server: download one or more directory + * authority certificates. */ +#define DIR_PURPOSE_FETCH_CERTIFICATE 15 + +/** Purpose for connection at a directory server. */ +#define DIR_PURPOSE_SERVER 16 +/** A connection to a hidden service directory server: upload a v2 rendezvous + * descriptor. */ +#define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17 +/** A connection to a hidden service directory server: download a v2 rendezvous + * descriptor. */ +#define DIR_PURPOSE_FETCH_RENDDESC_V2 18 +/** A connection to a directory server: download a microdescriptor. */ +#define DIR_PURPOSE_FETCH_MICRODESC 19 +/** A connection to a hidden service directory: upload a v3 descriptor. */ +#define DIR_PURPOSE_UPLOAD_HSDESC 20 +/** A connection to a hidden service directory: fetch a v3 descriptor. */ +#define DIR_PURPOSE_FETCH_HSDESC 21 +/** A connection to a directory server: set after a hidden service descriptor + * is downloaded. */ +#define DIR_PURPOSE_HAS_FETCHED_HSDESC 22 +#define DIR_PURPOSE_MAX_ 22 + +/** True iff <b>p</b> is a purpose corresponding to uploading + * data to a directory server. */ +#define DIR_PURPOSE_IS_UPLOAD(p) \ + ((p)==DIR_PURPOSE_UPLOAD_DIR || \ + (p)==DIR_PURPOSE_UPLOAD_VOTE || \ + (p)==DIR_PURPOSE_UPLOAD_SIGNATURES || \ + (p)==DIR_PURPOSE_UPLOAD_RENDDESC_V2 || \ + (p)==DIR_PURPOSE_UPLOAD_HSDESC) int directories_have_accepted_server_descriptor(void); void directory_post_to_dirservers(uint8_t dir_purpose, uint8_t router_purpose, @@ -60,6 +135,7 @@ void directory_request_set_dir_addr_port(directory_request_t *req, const tor_addr_port_t *p); void directory_request_set_directory_id_digest(directory_request_t *req, const char *digest); +struct circuit_guard_state_t; void directory_request_set_guard_state(directory_request_t *req, struct circuit_guard_state_t *state); void directory_request_set_router_purpose(directory_request_t *req, @@ -88,7 +164,7 @@ void directory_request_add_header(directory_request_t *req, MOCK_DECL(void, directory_initiate_request, (directory_request_t *request)); int parse_http_response(const char *headers, int *code, time_t *date, - compress_method_t *compression, char **response); + enum compress_method_t *compression, char **response); int parse_http_command(const char *headers, char **command_out, char **url_out); char *http_get_header(const char *headers, const char *which); @@ -132,30 +208,9 @@ time_t download_status_increment_attempt(download_status_t *dls, time(NULL)) void download_status_reset(download_status_t *dls); -static int download_status_is_ready(download_status_t *dls, time_t now); +int download_status_is_ready(download_status_t *dls, time_t now); time_t download_status_get_next_attempt_at(const download_status_t *dls); - -/** Return true iff, as of <b>now</b>, the resource tracked by <b>dls</b> is - * ready to get its download reattempted. */ -static inline int -download_status_is_ready(download_status_t *dls, time_t now) -{ - /* dls wasn't reset before it was used */ - if (dls->next_attempt_at == 0) { - download_status_reset(dls); - } - - return download_status_get_next_attempt_at(dls) <= now; -} - -static void download_status_mark_impossible(download_status_t *dl); -/** Mark <b>dl</b> as never downloadable. */ -static inline void -download_status_mark_impossible(download_status_t *dl) -{ - dl->n_download_failures = IMPOSSIBLE_TO_DOWNLOAD; - dl->n_download_attempts = IMPOSSIBLE_TO_DOWNLOAD; -} +void download_status_mark_impossible(download_status_t *dl); int download_status_get_n_failures(const download_status_t *dls); int download_status_get_n_attempts(const download_status_t *dls); @@ -208,7 +263,7 @@ struct directory_request_t { /** Hidden-service-specific information v2. */ const rend_data_t *rend_query; /** Extra headers to append to the request */ - config_line_t *additional_headers; + struct config_line_t *additional_headers; /** Hidden-service-specific information for v3+. */ const hs_ident_dir_conn_t *hs_ident; /** Used internally to directory.c: gets informed when the attempt to @@ -222,8 +277,10 @@ STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn, const struct get_handler_args_t *args); STATIC int directory_handle_command(dir_connection_t *conn); STATIC char *accept_encoding_header(void); -STATIC int allowed_anonymous_connection_compression_method(compress_method_t); -STATIC void warn_disallowed_anonymous_compression_method(compress_method_t); +STATIC int allowed_anonymous_connection_compression_method( + enum compress_method_t); +STATIC void warn_disallowed_anonymous_compression_method( + enum compress_method_t); STATIC int handle_response_fetch_hsdesc_v3(dir_connection_t *conn, const response_handler_args_t *args); @@ -258,7 +315,8 @@ STATIC int handle_post_hs_descriptor(const char *url, const char *body); STATIC char* authdir_type_to_string(dirinfo_type_t auth); STATIC const char * dir_conn_purpose_to_string(int purpose); STATIC int should_use_directory_guards(const or_options_t *options); -STATIC compression_level_t choose_compression_level(ssize_t n_bytes); +enum compression_level_t; +STATIC enum compression_level_t choose_compression_level(ssize_t n_bytes); STATIC int find_dl_min_delay(const download_status_t *dls, const or_options_t *options); @@ -287,4 +345,3 @@ STATIC unsigned parse_accept_encoding_header(const char *h); #endif /* defined(TOR_UNIT_TESTS) || defined(DIRECTORY_PRIVATE) */ #endif /* !defined(TOR_DIRECTORY_H) */ - diff --git a/src/or/dirserv.c b/src/feature/dircache/dirserv.c index 2362089d32..c5286b0cbf 100644 --- a/src/or/dirserv.c +++ b/src/feature/dircache/dirserv.c @@ -1,45 +1,60 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRSERV_PRIVATE -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "confparse.h" -#include "channel.h" -#include "channeltls.h" -#include "command.h" -#include "connection.h" -#include "connection_or.h" -#include "conscache.h" -#include "consdiffmgr.h" -#include "control.h" -#include "directory.h" -#include "dirserv.h" -#include "hibernate.h" -#include "keypin.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "protover.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "torcert.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/command.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "feature/dircache/conscache.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/control/control.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/hibernate/hibernate.h" +#include "feature/dirauth/keypin.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "feature/nodelist/torcert.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/dirauth/dirvote.h" + +#include "feature/dircache/cached_dir_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/nodelist/extrainfo_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "core/or/tor_version_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" + +#include "lib/compress/compress.h" +#include "lib/container/order.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/encoding/confline.h" /** * \file dirserv.c * \brief Directory server core implementation. Manages directory - * contents and generates directories. + * contents and generates directory documents. * * This module implements most of directory cache functionality, and some of * the directory authority functionality. The directory.c module delegates @@ -3581,4 +3596,3 @@ dirserv_free_all(void) dirserv_clear_measured_bw_cache(); } - diff --git a/src/or/dirserv.h b/src/feature/dircache/dirserv.h index 9026f332bc..3b4a646094 100644 --- a/src/or/dirserv.h +++ b/src/feature/dircache/dirserv.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,24 @@ #ifndef TOR_DIRSERV_H #define TOR_DIRSERV_H -#include "testsupport.h" +struct ed25519_public_key_t; + +#include "lib/testsupport/testsupport.h" + +/** An enum to describe what format we're generating a routerstatus line in. + */ +typedef enum { + /** For use in a v2 opinion */ + NS_V2, + /** For use in a consensus networkstatus document (ns flavor) */ + NS_V3_CONSENSUS, + /** For use in a vote networkstatus document */ + NS_V3_VOTE, + /** For passing to the controlport in response to a GETINFO request */ + NS_CONTROL_PORT, + /** For use in a consensus networkstatus document (microdesc flavor) */ + NS_V3_CONSENSUS_MICRODESC +} routerstatus_format_type_t; /** What fraction (1 over this number) of the relay ID space do we * (as a directory authority) launch connections to at each reachability @@ -87,6 +104,14 @@ typedef struct spooled_resource_t { off_t cached_dir_offset; } spooled_resource_t; +#ifdef DIRSERV_PRIVATE +typedef struct measured_bw_line_t { + char node_id[DIGEST_LEN]; + char node_hex[MAX_HEX_NICKNAME_LEN+1]; + long int bw_kb; +} measured_bw_line_t; +#endif /* defined(DIRSERV_PRIVATE) */ + int connection_dirserv_flushed_some(dir_connection_t *conn); int dirserv_add_own_fingerprint(crypto_pk_t *pk); @@ -130,7 +155,7 @@ int dirserv_get_routerdescs(smartlist_t *descs_out, const char *key, void dirserv_orconn_tls_done(const tor_addr_t *addr, uint16_t or_port, const char *digest_rcvd, - const ed25519_public_key_t *ed_id_rcvd); + const struct ed25519_public_key_t *ed_id_rcvd); int dirserv_should_launch_reachability_test(const routerinfo_t *ri, const routerinfo_t *ri_old); void dirserv_single_reachability_test(time_t now, routerinfo_t *router); @@ -212,4 +237,3 @@ void dirserv_spool_sort(dir_connection_t *conn); void dir_conn_clear_spool(dir_connection_t *conn); #endif /* !defined(TOR_DIRSERV_H) */ - diff --git a/src/feature/dirclient/dir_server_st.h b/src/feature/dirclient/dir_server_st.h new file mode 100644 index 0000000000..0a6d8155ae --- /dev/null +++ b/src/feature/dirclient/dir_server_st.h @@ -0,0 +1,54 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DIR_SERVER_ST_H +#define DIR_SERVER_ST_H + +#include "lib/cc/torint.h" +#include "core/or/or.h" +#include "feature/nodelist/routerstatus_st.h" + +/** Represents information about a single trusted or fallback directory + * server. */ +struct dir_server_t { + char *description; + char *nickname; + char *address; /**< Hostname. */ + /* XX/teor - why do we duplicate the address and port fields here and in + * fake_status? Surely we could just use fake_status (#17867). */ + tor_addr_t ipv6_addr; /**< IPv6 address if present; AF_UNSPEC if not */ + uint32_t addr; /**< IPv4 address. */ + uint16_t dir_port; /**< Directory port. */ + uint16_t or_port; /**< OR port: Used for tunneling connections. */ + uint16_t ipv6_orport; /**< OR port corresponding to ipv6_addr. */ + double weight; /** Weight used when selecting this node at random */ + char digest[DIGEST_LEN]; /**< Digest of identity key. */ + char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only, + * high-security) identity key. */ + + unsigned int is_running:1; /**< True iff we think this server is running. */ + unsigned int is_authority:1; /**< True iff this is a directory authority + * of some kind. */ + + /** True iff this server has accepted the most recent server descriptor + * we tried to upload to it. */ + unsigned int has_accepted_serverdesc:1; + + /** What kind of authority is this? (Bitfield.) */ + dirinfo_type_t type; + + time_t addr_current_at; /**< When was the document that we derived the + * address information from published? */ + + routerstatus_t fake_status; /**< Used when we need to pass this trusted + * dir_server_t to + * directory_request_set_routerstatus. + * as a routerstatus_t. Not updated by the + * router-status management code! + **/ +}; + +#endif diff --git a/src/feature/dirclient/download_status_st.h b/src/feature/dirclient/download_status_st.h new file mode 100644 index 0000000000..3f18f754a1 --- /dev/null +++ b/src/feature/dirclient/download_status_st.h @@ -0,0 +1,65 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DOWNLOAD_STATUS_ST_H +#define DOWNLOAD_STATUS_ST_H + +/** Information about our plans for retrying downloads for a downloadable + * directory object. + * Each type of downloadable directory object has a corresponding retry + * <b>schedule</b>, which can be different depending on whether the object is + * being downloaded from an authority or a mirror (<b>want_authority</b>). + * <b>next_attempt_at</b> contains the next time we will attempt to download + * the object. + * For schedules that <b>increment_on</b> failure, <b>n_download_failures</b> + * is used to determine the position in the schedule. (Each schedule is a + * smartlist of integer delays, parsed from a CSV option.) Every time a + * connection attempt fails, <b>n_download_failures</b> is incremented, + * the new delay value is looked up from the schedule, and + * <b>next_attempt_at</b> is set delay seconds from the time the previous + * connection failed. Therefore, at most one failure-based connection can be + * in progress for each download_status_t. + * For schedules that <b>increment_on</b> attempt, <b>n_download_attempts</b> + * is used to determine the position in the schedule. Every time a + * connection attempt is made, <b>n_download_attempts</b> is incremented, + * the new delay value is looked up from the schedule, and + * <b>next_attempt_at</b> is set delay seconds from the time the previous + * connection was attempted. Therefore, multiple concurrent attempted-based + * connections can be in progress for each download_status_t. + * After an object is successfully downloaded, any other concurrent connections + * are terminated. A new schedule which starts at position 0 is used for + * subsequent downloads of the same object. + */ +struct download_status_t { + time_t next_attempt_at; /**< When should we try downloading this object + * again? */ + uint8_t n_download_failures; /**< Number of failed downloads of the most + * recent object, since the last success. */ + uint8_t n_download_attempts; /**< Number of (potentially concurrent) attempts + * to download the most recent object, since + * the last success. */ + download_schedule_bitfield_t schedule : 8; /**< What kind of object is being + * downloaded? This determines the + * schedule used for the download. + */ + download_want_authority_bitfield_t want_authority : 1; /**< Is the download + * happening from an authority + * or a mirror? This determines + * the schedule used for the + * download. */ + download_schedule_increment_bitfield_t increment_on : 1; /**< does this + * schedule increment on each attempt, + * or after each failure? */ + uint8_t last_backoff_position; /**< number of attempts/failures, depending + * on increment_on, when we last recalculated + * the delay. Only updated if backoff + * == 1. */ + int last_delay_used; /**< last delay used for random exponential backoff; + * only updated if backoff == 1 */ +}; + +#endif + diff --git a/src/or/consdiff.c b/src/feature/dircommon/consdiff.c index deaf465fe7..1823dc07fb 100644 --- a/src/or/consdiff.c +++ b/src/feature/dircommon/consdiff.c @@ -1,5 +1,5 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014, The Tor Project, Inc. */ + * Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -38,10 +38,10 @@ #define CONSDIFF_PRIVATE -#include "or.h" -#include "consdiff.h" -#include "memarea.h" -#include "routerparse.h" +#include "core/or/or.h" +#include "feature/dircommon/consdiff.h" +#include "lib/memarea/memarea.h" +#include "feature/nodelist/routerparse.h" static const char* ns_diff_version = "network-status-diff-version 1"; static const char* hash_token = "hash"; @@ -1412,4 +1412,3 @@ looks_like_a_consensus_diff(const char *document, size_t len) return (len >= strlen(ns_diff_version) && fast_memeq(document, ns_diff_version, strlen(ns_diff_version))); } - diff --git a/src/or/consdiff.h b/src/feature/dircommon/consdiff.h index eb772c0b2b..a5e4ba5cbf 100644 --- a/src/or/consdiff.h +++ b/src/feature/dircommon/consdiff.h @@ -1,11 +1,11 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014, The Tor Project, Inc. */ + * Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CONSDIFF_H #define TOR_CONSDIFF_H -#include "or.h" +#include "core/or/or.h" char *consensus_diff_generate(const char *cons1, const char *cons2); @@ -15,6 +15,8 @@ char *consensus_diff_apply(const char *consensus, int looks_like_a_consensus_diff(const char *document, size_t len); #ifdef CONSDIFF_PRIVATE +#include "lib/container/bitarray.h" + struct memarea_t; /** Line type used for constructing consensus diffs. Each of these lines @@ -95,4 +97,3 @@ MOCK_DECL(STATIC int, #endif /* defined(CONSDIFF_PRIVATE) */ #endif /* !defined(TOR_CONSDIFF_H) */ - diff --git a/src/feature/dircommon/dir_connection_st.h b/src/feature/dircommon/dir_connection_st.h new file mode 100644 index 0000000000..768f6ba81e --- /dev/null +++ b/src/feature/dircommon/dir_connection_st.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DIR_CONNECTION_ST_H +#define DIR_CONNECTION_ST_H + +#include "core/or/connection_st.h" + +struct tor_compress_state_t; + +/** Subtype of connection_t for an "directory connection" -- that is, an HTTP + * connection to retrieve or serve directory material. */ +struct dir_connection_t { + connection_t base_; + + /** Which 'resource' did we ask the directory for? This is typically the part + * of the URL string that defines, relative to the directory conn purpose, + * what thing we want. For example, in router descriptor downloads by + * descriptor digest, it contains "d/", then one or more +-separated + * fingerprints. + **/ + char *requested_resource; + unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ + + /** If we're fetching descriptors, what router purpose shall we assign + * to them? */ + uint8_t router_purpose; + + /** List of spooled_resource_t for objects that we're spooling. We use + * it from back to front. */ + smartlist_t *spool; + /** The compression object doing on-the-fly compression for spooled data. */ + struct tor_compress_state_t *compress_state; + + /** What rendezvous service are we querying for? */ + rend_data_t *rend_data; + + /* Hidden service connection identifier for dir connections: Used by HS + client-side code to fetch HS descriptors, and by the service-side code to + upload descriptors. */ + struct hs_ident_dir_conn_t *hs_ident; + + /** If this is a one-hop connection, tracks the state of the directory guard + * for this connection (if any). */ + struct circuit_guard_state_t *guard_state; + + char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for + * the directory server's signing key. */ + + /** Unique ID for directory requests; this used to be in connection_t, but + * that's going away and being used on channels instead. The dirserver still + * needs this for the incoming side, so it's moved here. */ + uint64_t dirreq_id; + +#ifdef MEASUREMENTS_21206 + /** Number of RELAY_DATA cells received. */ + uint32_t data_cells_received; + + /** Number of RELAY_DATA cells sent. */ + uint32_t data_cells_sent; +#endif /* defined(MEASUREMENTS_21206) */ +}; + +#endif diff --git a/src/or/fp_pair.c b/src/feature/dircommon/fp_pair.c index c938e76678..0544145284 100644 --- a/src/or/fp_pair.c +++ b/src/feature/dircommon/fp_pair.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,8 +17,8 @@ * certificate for any (ID key, signing key) pair. **/ -#include "or.h" -#include "fp_pair.h" +#include "core/or/or.h" +#include "feature/dircommon/fp_pair.h" /* Define fp_pair_map_t structures */ diff --git a/src/or/fp_pair.h b/src/feature/dircommon/fp_pair.h index 4498a16101..500c7c9928 100644 --- a/src/or/fp_pair.h +++ b/src/feature/dircommon/fp_pair.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,6 +9,12 @@ #ifndef _TOR_FP_PAIR_H #define _TOR_FP_PAIR_H +/** A pair of digests created by dir_split_resource_info_fingerprint_pairs() */ +typedef struct { + char first[DIGEST_LEN]; + char second[DIGEST_LEN]; +} fp_pair_t; + /* * Declare fp_pair_map_t functions and structs */ diff --git a/src/feature/dircommon/vote_timing_st.h b/src/feature/dircommon/vote_timing_st.h new file mode 100644 index 0000000000..14c13eed28 --- /dev/null +++ b/src/feature/dircommon/vote_timing_st.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VOTE_TIMING_ST_H +#define VOTE_TIMING_ST_H + +/** Describes the schedule by which votes should be generated. */ +struct vote_timing_t { + /** Length in seconds between one consensus becoming valid and the next + * becoming valid. */ + int vote_interval; + /** For how many intervals is a consensus valid? */ + int n_intervals_valid; + /** Time in seconds allowed to propagate votes */ + int vote_delay; + /** Time in seconds allowed to propagate signatures */ + int dist_delay; +}; + +#endif + diff --git a/src/or/voting_schedule.c b/src/feature/dircommon/voting_schedule.c index d230a6dbcd..84c016c2b9 100644 --- a/src/or/voting_schedule.c +++ b/src/feature/dircommon/voting_schedule.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,11 +9,13 @@ **/ #define VOTING_SCHEDULE_PRIVATE -#include "voting_schedule.h" +#include "feature/dircommon/voting_schedule.h" -#include "or.h" -#include "config.h" -#include "networkstatus.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/nodelist/networkstatus.h" + +#include "feature/nodelist/networkstatus_st.h" /* ===== * Vote scheduling diff --git a/src/or/voting_schedule.h b/src/feature/dircommon/voting_schedule.h index 087701408e..0e0b0cc988 100644 --- a/src/or/voting_schedule.h +++ b/src/feature/dircommon/voting_schedule.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ #ifndef TOR_VOTING_SCHEDULE_H #define TOR_VOTING_SCHEDULE_H -#include "or.h" +#include "core/or/or.h" /** Scheduling information for a voting interval. */ typedef struct { diff --git a/src/or/hibernate.c b/src/feature/hibernate/hibernate.c index d7d259470f..d37ba5b8b1 100644 --- a/src/or/hibernate.c +++ b/src/feature/hibernate/hibernate.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,19 +28,27 @@ hibernating, phase 2: */ #define HIBERNATE_PRIVATE -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "control.h" -#include "crypto_rand.h" -#include "hibernate.h" -#include "main.h" -#include "router.h" -#include "statefile.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/hibernate/hibernate.h" +#include "core/mainloop/main.h" +#include "feature/relay/router.h" +#include "app/config/statefile.h" +#include "lib/evloop/compat_libevent.h" + +#include "core/or/or_connection_st.h" +#include "app/config/or_state_st.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /** Are we currently awake, asleep, running out of bandwidth, or shutting * down? */ @@ -759,13 +767,13 @@ read_bandwidth_usage(void) "Successfully read bandwidth accounting info from state written at %s " "for interval starting at %s. We have been active for %lu seconds in " "this interval. At the start of the interval, we expected to use " - "about %lu KB per second. ("U64_FORMAT" bytes read so far, " - U64_FORMAT" bytes written so far)", + "about %lu KB per second. (%"PRIu64" bytes read so far, " + "%"PRIu64" bytes written so far)", tbuf1, tbuf2, (unsigned long)n_seconds_active_in_interval, (unsigned long)(expected_bandwidth_usage*1024/60), - U64_PRINTF_ARG(n_bytes_read_in_interval), - U64_PRINTF_ARG(n_bytes_written_in_interval)); + (n_bytes_read_in_interval), + (n_bytes_written_in_interval)); } return 0; @@ -797,7 +805,7 @@ hibernate_soft_limit_reached(void) * - We have used up 95% of our bytes. * - We have less than 500MB of bytes left. */ - uint64_t soft_limit = DBL_TO_U64(U64_TO_DBL(acct_max) * SOFT_LIM_PCT); + uint64_t soft_limit = (uint64_t) (acct_max * SOFT_LIM_PCT); if (acct_max > SOFT_LIM_BYTES && acct_max - SOFT_LIM_BYTES > soft_limit) { soft_limit = acct_max - SOFT_LIM_BYTES; } @@ -1132,9 +1140,9 @@ getinfo_helper_accounting(control_connection_t *conn, *answer = tor_strdup(hibernate_state_to_string(hibernate_state)); tor_strlower(*answer); } else if (!strcmp(question, "accounting/bytes")) { - tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, - U64_PRINTF_ARG(n_bytes_read_in_interval), - U64_PRINTF_ARG(n_bytes_written_in_interval)); + tor_asprintf(answer, "%"PRIu64" %"PRIu64, + (n_bytes_read_in_interval), + (n_bytes_written_in_interval)); } else if (!strcmp(question, "accounting/bytes-left")) { uint64_t limit = get_options()->AccountingMax; if (get_options()->AccountingRule == ACCT_SUM) { @@ -1142,28 +1150,28 @@ getinfo_helper_accounting(control_connection_t *conn, uint64_t total_bytes = get_accounting_bytes(); if (total_bytes < limit) total_left = limit - total_bytes; - tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, - U64_PRINTF_ARG(total_left), U64_PRINTF_ARG(total_left)); + tor_asprintf(answer, "%"PRIu64" %"PRIu64, + (total_left), (total_left)); } else if (get_options()->AccountingRule == ACCT_IN) { uint64_t read_left = 0; if (n_bytes_read_in_interval < limit) read_left = limit - n_bytes_read_in_interval; - tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, - U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(limit)); + tor_asprintf(answer, "%"PRIu64" %"PRIu64, + (read_left), (limit)); } else if (get_options()->AccountingRule == ACCT_OUT) { uint64_t write_left = 0; if (n_bytes_written_in_interval < limit) write_left = limit - n_bytes_written_in_interval; - tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, - U64_PRINTF_ARG(limit), U64_PRINTF_ARG(write_left)); + tor_asprintf(answer, "%"PRIu64" %"PRIu64, + (limit), (write_left)); } else { uint64_t read_left = 0, write_left = 0; if (n_bytes_read_in_interval < limit) read_left = limit - n_bytes_read_in_interval; if (n_bytes_written_in_interval < limit) write_left = limit - n_bytes_written_in_interval; - tor_asprintf(answer, U64_FORMAT" "U64_FORMAT, - U64_PRINTF_ARG(read_left), U64_PRINTF_ARG(write_left)); + tor_asprintf(answer, "%"PRIu64" %"PRIu64, + (read_left), (write_left)); } } else if (!strcmp(question, "accounting/interval-start")) { *answer = tor_malloc(ISO_TIME_LEN+1); @@ -1225,4 +1233,3 @@ hibernate_set_state_for_testing_(hibernate_state_t newstate) hibernate_state = newstate; } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/or/hibernate.h b/src/feature/hibernate/hibernate.h index 453969d052..bfd8571cd6 100644 --- a/src/or/hibernate.h +++ b/src/feature/hibernate/hibernate.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_HIBERNATE_H #define TOR_HIBERNATE_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" int accounting_parse_options(const or_options_t *options, int validate_only); MOCK_DECL(int, accounting_is_enabled, (const or_options_t *options)); diff --git a/src/or/hs_cache.c b/src/feature/hs/hs_cache.c index ecc845d17f..58bb10b194 100644 --- a/src/or/hs_cache.c +++ b/src/feature/hs/hs_cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,17 +9,20 @@ /* For unit tests.*/ #define HS_CACHE_PRIVATE -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "hs_ident.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_descriptor.h" -#include "networkstatus.h" -#include "rendcache.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/hs/hs_ident.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/rend/rendcache.h" -#include "hs_cache.h" +#include "feature/hs/hs_cache.h" + +#include "feature/nodelist/networkstatus_st.h" static int cached_client_descriptor_has_expired(time_t now, const hs_cache_client_descriptor_t *cached_desc); @@ -974,4 +977,3 @@ hs_cache_free_all(void) cache_client_intro_state_free_void); hs_cache_client_intro_state = NULL; } - diff --git a/src/or/hs_cache.h b/src/feature/hs/hs_cache.h index 0d0085ffdc..7cd4995d2c 100644 --- a/src/or/hs_cache.h +++ b/src/feature/hs/hs_cache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,11 +11,12 @@ #include <stdint.h> -#include "crypto_ed25519.h" -#include "hs_common.h" -#include "hs_descriptor.h" -#include "rendcommon.h" -#include "torcert.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/rend/rendcommon.h" +#include "feature/nodelist/torcert.h" + +struct ed25519_public_key_t; /* This is the maximum time an introduction point state object can stay in the * client cache in seconds (2 mins or 120 seconds). */ @@ -79,30 +80,32 @@ int hs_cache_lookup_as_dir(uint32_t version, const char *query, const char **desc_out); const hs_descriptor_t * -hs_cache_lookup_as_client(const ed25519_public_key_t *key); +hs_cache_lookup_as_client(const struct ed25519_public_key_t *key); const char * -hs_cache_lookup_encoded_as_client(const ed25519_public_key_t *key); +hs_cache_lookup_encoded_as_client(const struct ed25519_public_key_t *key); int hs_cache_store_as_client(const char *desc_str, - const ed25519_public_key_t *identity_pk); + const struct ed25519_public_key_t *identity_pk); void hs_cache_clean_as_client(time_t now); void hs_cache_purge_as_client(void); /* Client failure cache. */ -void hs_cache_client_intro_state_note(const ed25519_public_key_t *service_pk, - const ed25519_public_key_t *auth_key, - rend_intro_point_failure_t failure); +void hs_cache_client_intro_state_note( + const struct ed25519_public_key_t *service_pk, + const struct ed25519_public_key_t *auth_key, + rend_intro_point_failure_t failure); const hs_cache_intro_state_t *hs_cache_client_intro_state_find( - const ed25519_public_key_t *service_pk, - const ed25519_public_key_t *auth_key); + const struct ed25519_public_key_t *service_pk, + const struct ed25519_public_key_t *auth_key); void hs_cache_client_intro_state_clean(time_t now); void hs_cache_client_intro_state_purge(void); #ifdef HS_CACHE_PRIVATE +#include "lib/crypt_ops/crypto_ed25519.h" /** Represents a locally cached HS descriptor on a hidden service client. */ typedef struct hs_cache_client_descriptor_t { /* This object is indexed using the service identity public key */ - ed25519_public_key_t key; + struct ed25519_public_key_t key; /* When will this entry expire? We expire cached client descriptors in the * start of the next time period, since that's when clients need to start @@ -125,4 +128,3 @@ lookup_v3_desc_as_client(const uint8_t *key); #endif /* defined(HS_CACHE_PRIVATE) */ #endif /* !defined(TOR_HS_CACHE_H) */ - diff --git a/src/or/hs_cell.c b/src/feature/hs/hs_cell.c index 03273a44f9..c6ca6746bc 100644 --- a/src/or/hs_cell.c +++ b/src/feature/hs/hs_cell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,22 +6,23 @@ * \brief Hidden service API for cell creation and handling. **/ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "rendservice.h" -#include "replaycache.h" -#include "util.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/rend/rendservice.h" +#include "feature/hs_common/replaycache.h" -#include "hs_cell.h" -#include "hs_ntor.h" +#include "feature/hs/hs_cell.h" +#include "core/crypto/hs_ntor.h" + +#include "core/or/origin_circuit_st.h" /* Trunnel. */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" -#include "hs/cell_rendezvous.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" +#include "trunnel/hs/cell_rendezvous.h" /* Compute the MAC of an INTRODUCE cell in mac_out. The encoded_cell param is * the cell content up to the ENCRYPTED section of length encoded_cell_len. diff --git a/src/or/hs_cell.h b/src/feature/hs/hs_cell.h index 958dde4ffc..7b9d7e5792 100644 --- a/src/or/hs_cell.h +++ b/src/feature/hs/hs_cell.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_HS_CELL_H #define TOR_HS_CELL_H -#include "or.h" -#include "hs_service.h" +#include "core/or/or.h" +#include "feature/hs/hs_service.h" /* An INTRODUCE1 cell requires at least this amount of bytes (see section * 3.2.2 of the specification). Below this value, the cell must be padded. */ diff --git a/src/or/hs_circuit.c b/src/feature/hs/hs_circuit.c index a35d2af8ba..cd312e98be 100644 --- a/src/or/hs_circuit.c +++ b/src/feature/hs/hs_circuit.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,31 +7,38 @@ #define HS_CIRCUIT_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "nodelist.h" -#include "policies.h" -#include "relay.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" - -#include "hs_cell.h" -#include "hs_ident.h" -#include "hs_ntor.h" -#include "hs_service.h" -#include "hs_circuit.h" +#include "core/or/or.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/or/relay.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" + +#include "feature/hs/hs_cell.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_ident.h" +#include "core/crypto/hs_ntor.h" +#include "feature/hs/hs_service.h" +#include "feature/hs/hs_circuit.h" /* Trunnel. */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" /* A circuit is about to become an e2e rendezvous circuit. Check * <b>circ_purpose</b> and ensure that it's properly set. Return true iff @@ -97,7 +104,8 @@ create_rend_cpath(const uint8_t *ntor_key_seed, size_t seed_len, /* We are a v2 legacy HS client: Create and return a crypt path for the hidden * service on the other side of the rendezvous circuit <b>circ</b>. Initialize * the crypt path crypto using the body of the RENDEZVOUS1 cell at - * <b>rend_cell_body</b> (which must be at least DH_KEY_LEN+DIGEST_LEN bytes). + * <b>rend_cell_body</b> (which must be at least DH1024_KEY_LEN+DIGEST_LEN + * bytes). */ static crypt_path_t * create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body) @@ -105,7 +113,7 @@ create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body) crypt_path_t *hop = NULL; char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; - /* first DH_KEY_LEN bytes are g^y from the service. Finish the dh + /* first DH1024_KEY_LEN bytes are g^y from the service. Finish the dh * handshake...*/ tor_assert(circ->build_state); tor_assert(circ->build_state->pending_final_cpath); @@ -113,7 +121,7 @@ create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body) tor_assert(hop->rend_dh_handshake_state); if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, hop->rend_dh_handshake_state, - (char*)rend_cell_body, DH_KEY_LEN, + (char*)rend_cell_body, DH1024_KEY_LEN, keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) { log_warn(LD_GENERAL, "Couldn't complete DH handshake."); goto err; @@ -125,7 +133,7 @@ create_rend_cpath_legacy(origin_circuit_t *circ, const uint8_t *rend_cell_body) goto err; /* Check whether the digest is right... */ - if (tor_memneq(keys, rend_cell_body+DH_KEY_LEN, DIGEST_LEN)) { + if (tor_memneq(keys, rend_cell_body+DH1024_KEY_LEN, DIGEST_LEN)) { log_warn(LD_PROTOCOL, "Incorrect digest of key material."); goto err; } @@ -1239,4 +1247,3 @@ hs_circ_cleanup(circuit_t *circ) hs_circuitmap_remove_circuit(circ); } } - diff --git a/src/or/hs_circuit.h b/src/feature/hs/hs_circuit.h index f69137e1d5..54f28a39ab 100644 --- a/src/or/hs_circuit.h +++ b/src/feature/hs/hs_circuit.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,10 @@ #ifndef TOR_HS_CIRCUIT_H #define TOR_HS_CIRCUIT_H -#include "or.h" -#include "crypto_ed25519.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_ed25519.h" -#include "hs_service.h" +#include "feature/hs/hs_service.h" /* Cleanup function when the circuit is closed or/and freed. */ void hs_circ_cleanup(circuit_t *circ); diff --git a/src/or/hs_circuitmap.c b/src/feature/hs/hs_circuitmap.c index 112c8bdced..962a421a00 100644 --- a/src/or/hs_circuitmap.c +++ b/src/feature/hs/hs_circuitmap.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,13 @@ #define HS_CIRCUITMAP_PRIVATE -#include "or.h" -#include "config.h" -#include "circuitlist.h" -#include "hs_circuitmap.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/or/circuitlist.h" +#include "feature/hs/hs_circuitmap.h" + +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" /************************** HS circuitmap code *******************************/ @@ -580,4 +583,3 @@ hs_circuitmap_free_all(void) tor_free(the_hs_circuitmap); } } - diff --git a/src/or/hs_circuitmap.h b/src/feature/hs/hs_circuitmap.h index 9e653480b5..c39a37c052 100644 --- a/src/or/hs_circuitmap.h +++ b/src/feature/hs/hs_circuitmap.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,7 @@ typedef HT_HEAD(hs_circuitmap_ht, circuit_t) hs_circuitmap_ht; -typedef struct hs_token_s hs_token_t; +typedef struct hs_token_t hs_token_t; struct or_circuit_t; struct origin_circuit_t; @@ -90,7 +90,7 @@ typedef enum { /** Represents a token used in the HS protocol. Each such token maps to a * specific introduction or rendezvous circuit. */ -struct hs_token_s { +struct hs_token_t { /* Type of HS token. */ hs_token_type_t type; @@ -110,4 +110,3 @@ hs_circuitmap_ht *get_hs_circuitmap(void); #endif /* TOR_UNIT_TESTS */ #endif /* !defined(TOR_HS_CIRCUITMAP_H) */ - diff --git a/src/or/hs_client.c b/src/feature/hs/hs_client.c index b39bb2cad0..1f9218e15a 100644 --- a/src/or/hs_client.c +++ b/src/feature/hs/hs_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,32 +8,39 @@ #define HS_CLIENT_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "container.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "hs_cache.h" -#include "hs_cell.h" -#include "hs_circuit.h" -#include "hs_client.h" -#include "hs_control.h" -#include "hs_descriptor.h" -#include "hs_ident.h" -#include "hs_ntor.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "reasons.h" -#include "rendclient.h" -#include "router.h" -#include "routerset.h" +#include "core/or/or.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_cell.h" +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_control.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_ident.h" +#include "core/crypto/hs_ntor.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/reasons.h" +#include "feature/rend/rendclient.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerset.h" + +#include "core/or/cpath_build_state_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" /* Return a human-readable string for the client fetch status code. */ static const char * @@ -1614,4 +1621,3 @@ hs_client_dir_info_changed(void) * AP_CONN_STATE_RENDDESC_WAIT state in order to fetch the descriptor. */ retry_all_socks_conn_waiting_for_desc(); } - diff --git a/src/or/hs_client.h b/src/feature/hs/hs_client.h index 2523568ad1..6ee9f40c00 100644 --- a/src/or/hs_client.h +++ b/src/feature/hs/hs_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,9 +9,9 @@ #ifndef TOR_HS_CLIENT_H #define TOR_HS_CLIENT_H -#include "crypto_ed25519.h" -#include "hs_descriptor.h" -#include "hs_ident.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_ident.h" /* Status code of a descriptor fetch request. */ typedef enum { diff --git a/src/or/hs_common.c b/src/feature/hs/hs_common.c index 5354055bb0..723cfa6ea8 100644 --- a/src/or/hs_common.c +++ b/src/feature/hs/hs_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,30 +11,36 @@ #define HS_COMMON_PRIVATE -#include "or.h" - -#include "config.h" -#include "circuitbuild.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "hs_cache.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_ident.h" -#include "hs_service.h" -#include "hs_circuitmap.h" -#include "policies.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "routerset.h" -#include "router.h" -#include "shared_random_client.h" -#include "dirauth/shared_random_state.h" +#include "core/or/or.h" + +#include "app/config/config.h" +#include "core/or/circuitbuild.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_ident.h" +#include "feature/hs/hs_service.h" +#include "feature/hs/hs_circuitmap.h" +#include "core/or/policies.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/nodelist/routerset.h" +#include "feature/relay/router.h" +#include "feature/hs_common/shared_random_client.h" +#include "feature/dirauth/shared_random_state.h" + +#include "core/or/edge_connection_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/nodelist/routerstatus_st.h" /* Trunnel */ -#include "ed25519_cert.h" +#include "trunnel/ed25519_cert.h" /* Ed25519 Basepoint value. Taken from section 5 of * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03 */ @@ -1817,4 +1823,3 @@ hs_inc_rdv_stream_counter(origin_circuit_t *circ) tor_assert_nonfatal_unreached(); } } - diff --git a/src/or/hs_common.h b/src/feature/hs/hs_common.h index ef7d5dca2b..888eb0a4ec 100644 --- a/src/or/hs_common.h +++ b/src/feature/hs/hs_common.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,15 @@ #ifndef TOR_HS_COMMON_H #define TOR_HS_COMMON_H -#include "or.h" +#include "core/or/or.h" +#include "lib/defs/x25519_sizes.h" + +struct curve25519_public_key_t; +struct ed25519_public_key_t; +struct ed25519_keypair_t; /* Trunnel */ -#include "ed25519_cert.h" +#include "trunnel/ed25519_cert.h" /* Protocol version 2. Use this instead of hardcoding "2" in the code base, * this adds a clearer semantic to the value when used. */ @@ -122,7 +127,7 @@ * bigger than the 84 bytes needed for version 3 so we need to pad up to that * length so it is indistinguishable between versions. */ #define HS_LEGACY_RENDEZVOUS_CELL_SIZE \ - (REND_COOKIE_LEN + DH_KEY_LEN + DIGEST_LEN) + (REND_COOKIE_LEN + DH1024_KEY_LEN + DIGEST_LEN) /* Type of authentication key used by an introduction point. */ typedef enum { @@ -167,20 +172,20 @@ int hs_check_service_private_dir(const char *username, const char *path, int hs_get_service_max_rend_failures(void); char *hs_path_from_filename(const char *directory, const char *filename); -void hs_build_address(const ed25519_public_key_t *key, uint8_t version, +void hs_build_address(const struct ed25519_public_key_t *key, uint8_t version, char *addr_out); int hs_address_is_valid(const char *address); -int hs_parse_address(const char *address, ed25519_public_key_t *key_out, +int hs_parse_address(const char *address, struct ed25519_public_key_t *key_out, uint8_t *checksum_out, uint8_t *version_out); -void hs_build_blinded_pubkey(const ed25519_public_key_t *pubkey, +void hs_build_blinded_pubkey(const struct ed25519_public_key_t *pubkey, const uint8_t *secret, size_t secret_len, uint64_t time_period_num, - ed25519_public_key_t *pubkey_out); -void hs_build_blinded_keypair(const ed25519_keypair_t *kp, + struct ed25519_public_key_t *pubkey_out); +void hs_build_blinded_keypair(const struct ed25519_keypair_t *kp, const uint8_t *secret, size_t secret_len, uint64_t time_period_num, - ed25519_keypair_t *kp_out); + struct ed25519_keypair_t *kp_out); int hs_service_requires_uptime_circ(const smartlist_t *ports); void rend_data_free_(rend_data_t *data); @@ -203,8 +208,8 @@ const uint8_t *rend_data_get_pk_digest(const rend_data_t *rend_data, routerstatus_t *pick_hsdir(const char *desc_id, const char *desc_id_base32); -void hs_get_subcredential(const ed25519_public_key_t *identity_pk, - const ed25519_public_key_t *blinded_pk, +void hs_get_subcredential(const struct ed25519_public_key_t *identity_pk, + const struct ed25519_public_key_t *blinded_pk, uint8_t *subcred_out); uint64_t hs_get_previous_time_period_num(time_t now); @@ -222,18 +227,18 @@ uint8_t *hs_get_current_srv(uint64_t time_period_num, uint8_t *hs_get_previous_srv(uint64_t time_period_num, const networkstatus_t *ns); -void hs_build_hsdir_index(const ed25519_public_key_t *identity_pk, +void hs_build_hsdir_index(const struct ed25519_public_key_t *identity_pk, const uint8_t *srv, uint64_t period_num, uint8_t *hsdir_index_out); void hs_build_hs_index(uint64_t replica, - const ed25519_public_key_t *blinded_pk, + const struct ed25519_public_key_t *blinded_pk, uint64_t period_num, uint8_t *hs_index_out); int32_t hs_get_hsdir_n_replicas(void); int32_t hs_get_hsdir_spread_fetch(void); int32_t hs_get_hsdir_spread_store(void); -void hs_get_responsible_hsdirs(const ed25519_public_key_t *blinded_pk, +void hs_get_responsible_hsdirs(const struct ed25519_public_key_t *blinded_pk, uint64_t time_period_num, int use_second_hsdir_index, int for_fetching, smartlist_t *responsible_dirs); @@ -254,8 +259,8 @@ void hs_inc_rdv_stream_counter(origin_circuit_t *circ); void hs_dec_rdv_stream_counter(origin_circuit_t *circ); extend_info_t *hs_get_extend_info_from_lspecs(const smartlist_t *lspecs, - const curve25519_public_key_t *onion_key, - int direct_conn); + const struct curve25519_public_key_t *onion_key, + int direct_conn); #ifdef HS_COMMON_PRIVATE @@ -281,4 +286,3 @@ STATIC uint8_t *get_second_cached_disaster_srv(void); #endif /* defined(HS_COMMON_PRIVATE) */ #endif /* !defined(TOR_HS_COMMON_H) */ - diff --git a/src/or/hs_config.c b/src/feature/hs/hs_config.c index be223503a0..2c25a168a2 100644 --- a/src/or/hs_config.c +++ b/src/feature/hs/hs_config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,10 +25,12 @@ #define HS_CONFIG_PRIVATE -#include "hs_common.h" -#include "hs_config.h" -#include "hs_service.h" -#include "rendservice.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_config.h" +#include "feature/hs/hs_service.h" +#include "feature/rend/rendservice.h" +#include "lib/encoding/confline.h" +#include "app/config/or_options_st.h" /* Using the given list of services, stage them into our global state. Every * service version are handled. This function can remove entries in the given @@ -587,4 +589,3 @@ hs_config_service_all(const or_options_t *options, int validate_only) /* Tor main should call the free all function on error. */ return ret; } - diff --git a/src/or/hs_config.h b/src/feature/hs/hs_config.h index 6cd7aed460..96eb19ee70 100644 --- a/src/or/hs_config.h +++ b/src/feature/hs/hs_config.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ #ifndef TOR_HS_CONFIG_H #define TOR_HS_CONFIG_H -#include "or.h" +#include "core/or/or.h" /* Max value for HiddenServiceMaxStreams */ #define HS_CONFIG_MAX_STREAMS_PER_RDV_CIRCUIT 65535 diff --git a/src/or/hs_control.c b/src/feature/hs/hs_control.c index 6b9b95c6d8..a21788ecd7 100644 --- a/src/or/hs_control.c +++ b/src/feature/hs/hs_control.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,14 +6,18 @@ * \brief Contains control port event related code. **/ -#include "or.h" -#include "control.h" -#include "crypto_util.h" -#include "hs_common.h" -#include "hs_control.h" -#include "hs_descriptor.h" -#include "hs_service.h" -#include "nodelist.h" +#include "core/or/or.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_control.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_service.h" +#include "feature/nodelist/nodelist.h" + +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerstatus_st.h" /* Send on the control port the "HS_DESC REQUESTED [...]" event. * @@ -255,4 +259,3 @@ hs_control_hspost_command(const char *body, const char *onion_address, smartlist_free(hsdirs); return ret; } - diff --git a/src/or/hs_control.h b/src/feature/hs/hs_control.h index 95c46e655e..63e3fe13d6 100644 --- a/src/or/hs_control.h +++ b/src/feature/hs/hs_control.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,7 @@ #ifndef TOR_HS_CONTROL_H #define TOR_HS_CONTROL_H -#include "hs_ident.h" +#include "feature/hs/hs_ident.h" /* Event "HS_DESC REQUESTED [...]" */ void hs_control_desc_event_requested(const ed25519_public_key_t *onion_pk, diff --git a/src/or/hs_descriptor.c b/src/feature/hs/hs_descriptor.c index 7ffa885ca8..3928000164 100644 --- a/src/or/hs_descriptor.c +++ b/src/feature/hs/hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,17 +55,21 @@ /* For unit tests.*/ #define HS_DESCRIPTOR_PRIVATE -#include "or.h" -#include "ed25519_cert.h" /* Trunnel interface. */ -#include "hs_descriptor.h" -#include "circuitbuild.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "parsecommon.h" -#include "rendcache.h" -#include "hs_cache.h" -#include "hs_config.h" -#include "torcert.h" /* tor_cert_encode_ed22519() */ +#include "core/or/or.h" +#include "trunnel/ed25519_cert.h" /* Trunnel interface. */ +#include "feature/hs/hs_descriptor.h" +#include "core/or/circuitbuild.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/nodelist/parsecommon.h" +#include "feature/rend/rendcache.h" +#include "feature/hs/hs_cache.h" +#include "feature/hs/hs_config.h" +#include "feature/nodelist/torcert.h" /* tor_cert_encode_ed22519() */ +#include "lib/memarea/memarea.h" +#include "lib/crypt_ops/crypto_format.h" + +#include "core/or/extend_info_st.h" /* Constant string value used for the descriptor format. */ #define str_hs_desc "hs-descriptor" @@ -2605,4 +2609,3 @@ hs_desc_lspec_to_trunnel(const hs_desc_link_specifier_t *spec) return ls; } - diff --git a/src/or/hs_descriptor.h b/src/feature/hs/hs_descriptor.h index 8195c6efbc..bfdf7559c6 100644 --- a/src/or/hs_descriptor.h +++ b/src/feature/hs/hs_descriptor.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,13 +11,9 @@ #include <stdint.h> -#include "or.h" -#include "address.h" -#include "container.h" -#include "crypto.h" -#include "crypto_ed25519.h" -#include "ed25519_cert.h" /* needed for trunnel */ -#include "torcert.h" +#include "core/or/or.h" +#include "trunnel/ed25519_cert.h" /* needed for trunnel */ +#include "feature/nodelist/torcert.h" /* Trunnel */ struct link_specifier_t; @@ -282,4 +278,3 @@ MOCK_DECL(STATIC size_t, decrypt_desc_layer,(const hs_descriptor_t *desc, #endif /* defined(HS_DESCRIPTOR_PRIVATE) */ #endif /* !defined(TOR_HS_DESCRIPTOR_H) */ - diff --git a/src/or/hs_ident.c b/src/feature/hs/hs_ident.c index 3603e329d4..c6ef8c2ce3 100644 --- a/src/or/hs_ident.c +++ b/src/feature/hs/hs_ident.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,8 +7,8 @@ * subsytem. **/ -#include "crypto_util.h" -#include "hs_ident.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/hs/hs_ident.h" /* Return a newly allocated circuit identifier. The given public key is copied * identity_pk into the identifier. */ diff --git a/src/or/hs_ident.h b/src/feature/hs/hs_ident.h index 8f9da30c35..92d15b0523 100644 --- a/src/or/hs_ident.h +++ b/src/feature/hs/hs_ident.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,9 +21,9 @@ #ifndef TOR_HS_IDENT_H #define TOR_HS_IDENT_H -#include "crypto_ed25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" -#include "hs_common.h" +#include "feature/hs/hs_common.h" /* Length of the rendezvous cookie that is used to connect circuits at the * rendezvous point. */ diff --git a/src/or/hs_intropoint.c b/src/feature/hs/hs_intropoint.c index 3274e8e9c0..42092e22b1 100644 --- a/src/or/hs_intropoint.c +++ b/src/feature/hs/hs_intropoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,24 +8,27 @@ #define HS_INTROPOINT_PRIVATE -#include "or.h" -#include "config.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "relay.h" -#include "rendmid.h" -#include "rephist.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/relay.h" +#include "feature/rend/rendmid.h" +#include "feature/stats/rephist.h" +#include "lib/crypt_ops/crypto_format.h" /* Trunnel */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" -#include "hs_circuitmap.h" -#include "hs_descriptor.h" -#include "hs_intropoint.h" -#include "hs_common.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_intropoint.h" +#include "feature/hs/hs_common.h" + +#include "core/or/or_circuit_st.h" /** Extract the authentication key from an ESTABLISH_INTRO or INTRODUCE1 using * the given <b>cell_type</b> from <b>cell</b> and place it in @@ -609,4 +612,3 @@ hs_intropoint_clear(hs_intropoint_t *ip) smartlist_free(ip->link_specifiers); memset(ip, 0, sizeof(hs_intropoint_t)); } - diff --git a/src/or/hs_intropoint.h b/src/feature/hs/hs_intropoint.h index 749d1530e1..562836fb07 100644 --- a/src/or/hs_intropoint.h +++ b/src/feature/hs/hs_intropoint.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_HS_INTRO_H #define TOR_HS_INTRO_H -#include "crypto_curve25519.h" -#include "torcert.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "feature/nodelist/torcert.h" /* Authentication key type in an ESTABLISH_INTRO cell. */ typedef enum { @@ -55,8 +55,8 @@ void hs_intropoint_clear(hs_intropoint_t *ip); #ifdef HS_INTROPOINT_PRIVATE -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" STATIC int verify_establish_intro_cell(const trn_cell_establish_intro_t *out, diff --git a/src/or/hs_service.c b/src/feature/hs/hs_service.c index f1f26954ae..8b4de21387 100644 --- a/src/or/hs_service.c +++ b/src/feature/hs/hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,41 +8,60 @@ #define HS_SERVICE_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "rendservice.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "shared_random_client.h" -#include "statefile.h" - -#include "hs_circuit.h" -#include "hs_common.h" -#include "hs_config.h" -#include "hs_control.h" -#include "hs_descriptor.h" -#include "hs_ident.h" -#include "hs_intropoint.h" -#include "hs_service.h" -#include "hs_stats.h" +#include "core/or/or.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/relay.h" +#include "feature/rend/rendservice.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/hs_common/shared_random_client.h" +#include "app/config/statefile.h" + +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_config.h" +#include "feature/hs/hs_control.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_ident.h" +#include "feature/hs/hs_intropoint.h" +#include "feature/hs/hs_service.h" +#include "feature/hs/hs_stats.h" + +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/edge_connection_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "lib/encoding/confline.h" +#include "lib/crypt_ops/crypto_format.h" /* Trunnel */ -#include "ed25519_cert.h" -#include "hs/cell_common.h" -#include "hs/cell_establish_intro.h" +#include "trunnel/ed25519_cert.h" +#include "trunnel/hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* Helper macro. Iterate over every service in the global map. The var is the * name of the service pointer. */ @@ -3623,4 +3642,3 @@ get_first_service(void) } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/or/hs_service.h b/src/feature/hs/hs_service.h index 5494b6f5fa..22bfcacc26 100644 --- a/src/or/hs_service.h +++ b/src/feature/hs/hs_service.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,17 +9,17 @@ #ifndef TOR_HS_SERVICE_H #define TOR_HS_SERVICE_H -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" -#include "replaycache.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/hs_common/replaycache.h" -#include "hs_common.h" -#include "hs_descriptor.h" -#include "hs_ident.h" -#include "hs_intropoint.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/hs/hs_ident.h" +#include "feature/hs/hs_intropoint.h" /* Trunnel */ -#include "hs/cell_establish_intro.h" +#include "trunnel/hs/cell_establish_intro.h" /* When loading and configuring a service, this is the default version it will * be configured for as it is possible that no HiddenServiceVersion is diff --git a/src/or/hs_stats.c b/src/feature/hs/hs_stats.c index 1e2a96945b..b109a37cc1 100644 --- a/src/or/hs_stats.c +++ b/src/feature/hs/hs_stats.c @@ -6,9 +6,9 @@ * \brief Keeps stats about the activity of our onion service(s). **/ -#include "or.h" -#include "hs_stats.h" -#include "hs_service.h" +#include "core/or/or.h" +#include "feature/hs/hs_stats.h" +#include "feature/hs/hs_service.h" /** Number of v3 INTRODUCE2 cells received */ static uint32_t n_introduce2_v3 = 0; diff --git a/src/or/hs_stats.h b/src/feature/hs/hs_stats.h index a946ad75e5..a946ad75e5 100644 --- a/src/or/hs_stats.h +++ b/src/feature/hs/hs_stats.h diff --git a/src/feature/hs/hsdir_index_st.h b/src/feature/hs/hsdir_index_st.h new file mode 100644 index 0000000000..de5cc9bd16 --- /dev/null +++ b/src/feature/hs/hsdir_index_st.h @@ -0,0 +1,24 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef HSDIR_INDEX_ST_H +#define HSDIR_INDEX_ST_H + +/* Hidden service directory index used in a node_t which is set once we set + * the consensus. */ +struct hsdir_index_t { + /* HSDir index to use when fetching a descriptor. */ + uint8_t fetch[DIGEST256_LEN]; + + /* HSDir index used by services to store their first and second + * descriptor. The first descriptor is chronologically older than the second + * one and uses older TP and SRV values. */ + uint8_t store_first[DIGEST256_LEN]; + uint8_t store_second[DIGEST256_LEN]; +}; + +#endif + diff --git a/src/or/replaycache.c b/src/feature/hs_common/replaycache.c index a9a6709937..1d3f20e819 100644 --- a/src/or/replaycache.c +++ b/src/feature/hs_common/replaycache.c @@ -1,4 +1,4 @@ - /* Copyright (c) 2012-2017, The Tor Project, Inc. */ + /* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,8 +21,8 @@ #define REPLAYCACHE_PRIVATE -#include "or.h" -#include "replaycache.h" +#include "core/or/or.h" +#include "feature/hs_common/replaycache.h" /** Free the replaycache r and all of its entries. */ diff --git a/src/or/replaycache.h b/src/feature/hs_common/replaycache.h index 81a8d907fd..3118a88a1a 100644 --- a/src/or/replaycache.h +++ b/src/feature/hs_common/replaycache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,11 +9,11 @@ #ifndef TOR_REPLAYCACHE_H #define TOR_REPLAYCACHE_H -typedef struct replaycache_s replaycache_t; +typedef struct replaycache_t replaycache_t; #ifdef REPLAYCACHE_PRIVATE -struct replaycache_s { +struct replaycache_t { /* Scrub interval */ time_t scrub_interval; /* Last scrubbed */ @@ -65,4 +65,3 @@ int replaycache_add_test_and_elapsed( void replaycache_scrub_if_needed(replaycache_t *r); #endif /* !defined(TOR_REPLAYCACHE_H) */ - diff --git a/src/or/shared_random_client.c b/src/feature/hs_common/shared_random_client.c index 3aef83cef4..329f053d3b 100644 --- a/src/or/shared_random_client.c +++ b/src/feature/hs_common/shared_random_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,13 +9,14 @@ **/ #define SHARED_RANDOM_CLIENT_PRIVATE -#include "shared_random_client.h" +#include "feature/hs_common/shared_random_client.h" -#include "config.h" -#include "voting_schedule.h" -#include "networkstatus.h" -#include "util.h" -#include "util_format.h" +#include "app/config/config.h" +#include "feature/dircommon/voting_schedule.h" +#include "feature/nodelist/networkstatus.h" +#include "lib/encoding/binascii.h" + +#include "feature/nodelist/networkstatus_st.h" /* Convert a given srv object to a string for the control port. This doesn't * fail and the srv object MUST be valid. */ diff --git a/src/or/shared_random_client.h b/src/feature/hs_common/shared_random_client.h index 89c608d45f..497a015c18 100644 --- a/src/or/shared_random_client.h +++ b/src/feature/hs_common/shared_random_client.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,7 +10,7 @@ #define TOR_SHARED_RANDOM_CLIENT_H /* Dirauth module. */ -#include "dirauth/shared_random.h" +#include "feature/dirauth/shared_random.h" /* Helper functions. */ void sr_srv_encode(char *dst, size_t dst_len, const sr_srv_t *srv); diff --git a/src/feature/nodelist/authority_cert_st.h b/src/feature/nodelist/authority_cert_st.h new file mode 100644 index 0000000000..c2846548c4 --- /dev/null +++ b/src/feature/nodelist/authority_cert_st.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef AUTHORITY_CERT_ST_H +#define AUTHORITY_CERT_ST_H + +#include "feature/nodelist/signed_descriptor_st.h" + +/** Certificate for v3 directory protocol: binds long-term authority identity + * keys to medium-term authority signing keys. */ +struct authority_cert_t { + /** Information relating to caching this cert on disk and looking it up. */ + signed_descriptor_t cache_info; + /** This authority's long-term authority identity key. */ + crypto_pk_t *identity_key; + /** This authority's medium-term signing key. */ + crypto_pk_t *signing_key; + /** The digest of <b>signing_key</b> */ + char signing_key_digest[DIGEST_LEN]; + /** The listed expiration time of this certificate. */ + time_t expires; + /** This authority's IPv4 address, in host order. */ + uint32_t addr; + /** This authority's directory port. */ + uint16_t dir_port; +}; + +#endif + diff --git a/src/feature/nodelist/desc_store_st.h b/src/feature/nodelist/desc_store_st.h new file mode 100644 index 0000000000..168a83b230 --- /dev/null +++ b/src/feature/nodelist/desc_store_st.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DESC_STORE_ST_H +#define DESC_STORE_ST_H + +/** Allowable types of desc_store_t. */ +typedef enum store_type_t { + ROUTER_STORE = 0, + EXTRAINFO_STORE = 1 +} store_type_t; + +/** A 'store' is a set of descriptors saved on disk, with accompanying + * journal, mmaped as needed, rebuilt as needed. */ +struct desc_store_t { + /** Filename (within DataDir) for the store. We append .tmp to this + * filename for a temporary file when rebuilding the store, and .new to this + * filename for the journal. */ + const char *fname_base; + /** Human-readable description of what this store contains. */ + const char *description; + + tor_mmap_t *mmap; /**< A mmap for the main file in the store. */ + + store_type_t type; /**< What's stored in this store? */ + + /** The size of the router log, in bytes. */ + size_t journal_len; + /** The size of the router store, in bytes. */ + size_t store_len; + /** Total bytes dropped since last rebuild: this is space currently + * used in the cache and the journal that could be freed by a rebuild. */ + size_t bytes_dropped; +}; + +#endif diff --git a/src/feature/nodelist/document_signature_st.h b/src/feature/nodelist/document_signature_st.h new file mode 100644 index 0000000000..0291e099bf --- /dev/null +++ b/src/feature/nodelist/document_signature_st.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef DOCUMENT_SIGNATURE_ST_H +#define DOCUMENT_SIGNATURE_ST_H + +/** A signature of some document by an authority. */ +struct document_signature_t { + /** Declared SHA-1 digest of this voter's identity key */ + char identity_digest[DIGEST_LEN]; + /** Declared SHA-1 digest of signing key used by this voter. */ + char signing_key_digest[DIGEST_LEN]; + /** Algorithm used to compute the digest of the document. */ + digest_algorithm_t alg; + /** Signature of the signed thing. */ + char *signature; + /** Length of <b>signature</b> */ + int signature_len; + unsigned int bad_signature : 1; /**< Set to true if we've tried to verify + * the sig, and we know it's bad. */ + unsigned int good_signature : 1; /**< Set to true if we've verified the sig + * as good. */ +}; + +#endif + diff --git a/src/feature/nodelist/extrainfo_st.h b/src/feature/nodelist/extrainfo_st.h new file mode 100644 index 0000000000..f5d977e751 --- /dev/null +++ b/src/feature/nodelist/extrainfo_st.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef EXTRAINFO_ST_H +#define EXTRAINFO_ST_H + +#include "feature/nodelist/signed_descriptor_st.h" + +/** Information needed to keep and cache a signed extra-info document. */ +struct extrainfo_t { + signed_descriptor_t cache_info; + /** SHA256 digest of this document */ + uint8_t digest256[DIGEST256_LEN]; + /** The router's nickname. */ + char nickname[MAX_NICKNAME_LEN+1]; + /** True iff we found the right key for this extra-info, verified the + * signature, and found it to be bad. */ + unsigned int bad_sig : 1; + /** If present, we didn't have the right key to verify this extra-info, + * so this is a copy of the signature in the document. */ + char *pending_sig; + /** Length of pending_sig. */ + size_t pending_sig_len; +}; + +#endif + diff --git a/src/or/microdesc.c b/src/feature/nodelist/microdesc.c index b4a934e095..4d6285d6cf 100644 --- a/src/or/microdesc.c +++ b/src/feature/nodelist/microdesc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ +/* Copyright (c) 2009-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,19 +8,34 @@ * less-frequently-changing router information. */ -#include "or.h" -#include "circuitbuild.h" -#include "config.h" -#include "directory.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" +#include "core/or/or.h" + +#include "lib/fdio/fdio.h" + +#include "core/or/circuitbuild.h" +#include "app/config/config.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/entrynodes.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" + +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /** A data structure to hold a bunch of cached microdescriptors. There are * two active files in the cache: a "cache file" that we mmap, and a "journal @@ -189,7 +204,7 @@ dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) char annotation[ISO_TIME_LEN+32]; format_iso_time(buf, md->last_listed); tor_snprintf(annotation, sizeof(annotation), "@last-listed %s\n", buf); - if (write_all(fd, annotation, strlen(annotation), 0) < 0) { + if (write_all_to_fd(fd, annotation, strlen(annotation)) < 0) { log_warn(LD_DIR, "Couldn't write microdescriptor annotation: %s", strerror(errno)); @@ -202,7 +217,7 @@ dump_microdescriptor(int fd, microdesc_t *md, size_t *annotation_len_out) } md->off = tor_fd_getpos(fd); - written = write_all(fd, md->body, md->bodylen, 0); + written = write_all_to_fd(fd, md->body, md->bodylen); if (written != (ssize_t)md->bodylen) { written = written < 0 ? 0 : written; log_warn(LD_DIR, @@ -706,9 +721,9 @@ microdesc_cache_rebuild(microdesc_cache_t *cache, int force) off_real = tor_fd_getpos(fd); if (off_real != off) { log_warn(LD_BUG, "Discontinuity in position in microdescriptor cache." - "By my count, I'm at "I64_FORMAT - ", but I should be at "I64_FORMAT, - I64_PRINTF_ARG(off), I64_PRINTF_ARG(off_real)); + "By my count, I'm at %"PRId64 + ", but I should be at %"PRId64, + (off), (off_real)); if (off_real >= 0) off = off_real; } @@ -1042,4 +1057,3 @@ usable_consensus_flavor,(void)) return FLAV_NS; } } - diff --git a/src/or/microdesc.h b/src/feature/nodelist/microdesc.h index 83a90bd8ff..f11b841cf1 100644 --- a/src/or/microdesc.h +++ b/src/feature/nodelist/microdesc.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/feature/nodelist/microdesc_st.h b/src/feature/nodelist/microdesc_st.h new file mode 100644 index 0000000000..e9dc3e0174 --- /dev/null +++ b/src/feature/nodelist/microdesc_st.h @@ -0,0 +1,74 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef MICRODESC_ST_H +#define MICRODESC_ST_H + +struct curve25519_public_key_t; +struct ed25519_public_key_t; +struct short_policy_t; + +/** A microdescriptor is the smallest amount of information needed to build a + * circuit through a router. They are generated by the directory authorities, + * using information from the uploaded routerinfo documents. They are not + * self-signed, but are rather authenticated by having their hash in a signed + * networkstatus document. */ +struct microdesc_t { + /** Hashtable node, used to look up the microdesc by its digest. */ + HT_ENTRY(microdesc_t) node; + + /* Cache information */ + + /** When was this microdescriptor last listed in a consensus document? + * Once a microdesc has been unlisted long enough, we can drop it. + */ + time_t last_listed; + /** Where is this microdescriptor currently stored? */ + saved_location_bitfield_t saved_location : 3; + /** If true, do not attempt to cache this microdescriptor on disk. */ + unsigned int no_save : 1; + /** If true, this microdesc has an entry in the microdesc_map */ + unsigned int held_in_map : 1; + /** Reference count: how many node_ts have a reference to this microdesc? */ + unsigned int held_by_nodes; + + /** If saved_location == SAVED_IN_CACHE, this field holds the offset of the + * microdescriptor in the cache. */ + off_t off; + + /* The string containing the microdesc. */ + + /** A pointer to the encoded body of the microdescriptor. If the + * saved_location is SAVED_IN_CACHE, then the body is a pointer into an + * mmap'd region. Otherwise, it is a malloc'd string. The string might not + * be NUL-terminated; take the length from <b>bodylen</b>. */ + char *body; + /** The length of the microdescriptor in <b>body</b>. */ + size_t bodylen; + /** A SHA256-digest of the microdescriptor. */ + char digest[DIGEST256_LEN]; + + /* Fields in the microdescriptor. */ + + /** As routerinfo_t.onion_pkey */ + crypto_pk_t *onion_pkey; + /** As routerinfo_t.onion_curve25519_pkey */ + struct curve25519_public_key_t *onion_curve25519_pkey; + /** Ed25519 identity key, if included. */ + struct ed25519_public_key_t *ed25519_identity_pkey; + /** As routerinfo_t.ipv6_addr */ + tor_addr_t ipv6_addr; + /** As routerinfo_t.ipv6_orport */ + uint16_t ipv6_orport; + /** As routerinfo_t.family */ + smartlist_t *family; + /** IPv4 exit policy summary */ + struct short_policy_t *exit_policy; + /** IPv6 exit policy summary */ + struct short_policy_t *ipv6_exit_policy; +}; + +#endif diff --git a/src/or/networkstatus.c b/src/feature/nodelist/networkstatus.c index 998eaf74e6..e9d36cbdcb 100644 --- a/src/or/networkstatus.c +++ b/src/feature/nodelist/networkstatus.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -37,42 +37,60 @@ */ #define NETWORKSTATUS_PRIVATE -#include "or.h" -#include "bridges.h" -#include "channel.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "circuitstats.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "consdiffmgr.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "dirserv.h" -#include "dos.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "protover.h" -#include "relay.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "scheduler.h" -#include "transports.h" -#include "torcert.h" -#include "channelpadding.h" -#include "voting_schedule.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" -#include "dirauth/shared_random.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "core/or/channel.h" +#include "core/or/circuitmux.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/circuitstats.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "core/or/dos.h" +#include "feature/client/entrynodes.h" +#include "feature/hibernate/hibernate.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/protover.h" +#include "core/or/relay.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "core/or/scheduler.h" +#include "feature/client/transports.h" +#include "feature/nodelist/torcert.h" +#include "core/or/channelpadding.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/mode.h" +#include "feature/dirauth/shared_random.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/document_signature_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/networkstatus_voter_info_st.h" +#include "feature/dirauth/ns_detached_signatures_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "feature/dirauth/vote_microdesc_hash_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /** Most recently received and validated v3 "ns"-flavored consensus network * status. */ @@ -593,8 +611,11 @@ networkstatus_check_consensus_signature(networkstatus_t *consensus, char *tmp = smartlist_join_strings(list_good, " ", 0, NULL); smartlist_add_asprintf(sl, "A consensus needs %d good signatures from recognized " - "authorities for us to accept it. This one has %d (%s).", - n_required, n_good, tmp); + "authorities for us to accept it. " + "This %s one has %d (%s).", + n_required, + networkstatus_get_flavor_name(consensus->flavor), + n_good, tmp); tor_free(tmp); if (n_no_signature) { tmp = smartlist_join_strings(list_no_signature, " ", 0, NULL); @@ -2703,4 +2724,3 @@ networkstatus_free_all(void) tor_free(waiting->body); } } - diff --git a/src/or/networkstatus.h b/src/feature/nodelist/networkstatus.h index 94f85c3c29..cc6badf0b2 100644 --- a/src/or/networkstatus.h +++ b/src/feature/nodelist/networkstatus.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_NETWORKSTATUS_H #define TOR_NETWORKSTATUS_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" void networkstatus_reset_warnings(void); void networkstatus_reset_download_failures(void); diff --git a/src/feature/nodelist/networkstatus_sr_info_st.h b/src/feature/nodelist/networkstatus_sr_info_st.h new file mode 100644 index 0000000000..6c937a75f5 --- /dev/null +++ b/src/feature/nodelist/networkstatus_sr_info_st.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NETWORKSTATUS_SR_INFO_ST_H +#define NETWORKSTATUS_SR_INFO_ST_H + +struct networkstatus_sr_info_t { + /* Indicate if the dirauth partitipates in the SR protocol with its vote. + * This is tied to the SR flag in the vote. */ + unsigned int participate:1; + /* Both vote and consensus: Current and previous SRV. If list is empty, + * this means none were found in either the consensus or vote. */ + struct sr_srv_t *previous_srv; + struct sr_srv_t *current_srv; + /* Vote only: List of commitments. */ + smartlist_t *commits; +}; + +#endif + diff --git a/src/feature/nodelist/networkstatus_st.h b/src/feature/nodelist/networkstatus_st.h new file mode 100644 index 0000000000..46b0f53c0b --- /dev/null +++ b/src/feature/nodelist/networkstatus_st.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NETWORKSTATUS_ST_H +#define NETWORKSTATUS_ST_H + +#include "feature/nodelist/networkstatus_sr_info_st.h" + +/** Enumerates the possible seriousness values of a networkstatus document. */ +typedef enum networkstatus_type_t { + NS_TYPE_VOTE, + NS_TYPE_CONSENSUS, + NS_TYPE_OPINION, +} networkstatus_type_t; + +/** A common structure to hold a v3 network status vote, or a v3 network + * status consensus. */ +struct networkstatus_t { + networkstatus_type_t type; /**< Vote, consensus, or opinion? */ + consensus_flavor_t flavor; /**< If a consensus, what kind? */ + unsigned int has_measured_bws : 1;/**< True iff this networkstatus contains + * measured= bandwidth values. */ + + time_t published; /**< Vote only: Time when vote was written. */ + time_t valid_after; /**< Time after which this vote or consensus applies. */ + time_t fresh_until; /**< Time before which this is the most recent vote or + * consensus. */ + time_t valid_until; /**< Time after which this vote or consensus should not + * be used. */ + + /** Consensus only: what method was used to produce this consensus? */ + int consensus_method; + /** Vote only: what methods is this voter willing to use? */ + smartlist_t *supported_methods; + + /** List of 'package' lines describing hashes of downloadable packages */ + smartlist_t *package_lines; + + /** How long does this vote/consensus claim that authorities take to + * distribute their votes to one another? */ + int vote_seconds; + /** How long does this vote/consensus claim that authorities take to + * distribute their consensus signatures to one another? */ + int dist_seconds; + + /** Comma-separated list of recommended client software, or NULL if this + * voter has no opinion. */ + char *client_versions; + char *server_versions; + + /** Lists of subprotocol versions which are _recommended_ for relays and + * clients, or which are _require_ for relays and clients. Tor shouldn't + * make any more network connections if a required protocol is missing. + */ + char *recommended_relay_protocols; + char *recommended_client_protocols; + char *required_relay_protocols; + char *required_client_protocols; + + /** List of flags that this vote/consensus applies to routers. If a flag is + * not listed here, the voter has no opinion on what its value should be. */ + smartlist_t *known_flags; + + /** List of key=value strings for the parameters in this vote or + * consensus, sorted by key. */ + smartlist_t *net_params; + + /** List of key=value strings for the bw weight parameters in the + * consensus. */ + smartlist_t *weight_params; + + /** List of networkstatus_voter_info_t. For a vote, only one element + * is included. For a consensus, one element is included for every voter + * whose vote contributed to the consensus. */ + smartlist_t *voters; + + struct authority_cert_t *cert; /**< Vote only: the voter's certificate. */ + + /** Digests of this document, as signed. */ + common_digests_t digests; + /** A SHA3-256 digest of the document, not including signatures: used for + * consensus diffs */ + uint8_t digest_sha3_as_signed[DIGEST256_LEN]; + + /** List of router statuses, sorted by identity digest. For a vote, + * the elements are vote_routerstatus_t; for a consensus, the elements + * are routerstatus_t. */ + smartlist_t *routerstatus_list; + + /** If present, a map from descriptor digest to elements of + * routerstatus_list. */ + digestmap_t *desc_digest_map; + + /** Contains the shared random protocol data from a vote or consensus. */ + networkstatus_sr_info_t sr_info; +}; + +#endif diff --git a/src/feature/nodelist/networkstatus_voter_info_st.h b/src/feature/nodelist/networkstatus_voter_info_st.h new file mode 100644 index 0000000000..93ff3cd418 --- /dev/null +++ b/src/feature/nodelist/networkstatus_voter_info_st.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NETWORKSTATUS_VOTER_INFO_ST_H +#define NETWORKSTATUS_VOTER_INFO_ST_H + +/** Information about a single voter in a vote or a consensus. */ +struct networkstatus_voter_info_t { + /** Declared SHA-1 digest of this voter's identity key */ + char identity_digest[DIGEST_LEN]; + char *nickname; /**< Nickname of this voter */ + /** Digest of this voter's "legacy" identity key, if any. In vote only; for + * consensuses, we treat legacy keys as additional signers. */ + char legacy_id_digest[DIGEST_LEN]; + char *address; /**< Address of this voter, in string format. */ + uint32_t addr; /**< Address of this voter, in IPv4, in host order. */ + uint16_t dir_port; /**< Directory port of this voter */ + uint16_t or_port; /**< OR port of this voter */ + char *contact; /**< Contact information for this voter. */ + char vote_digest[DIGEST_LEN]; /**< Digest of this voter's vote, as signed. */ + + /* Nothing from here on is signed. */ + /** The signature of the document and the signature's status. */ + smartlist_t *sigs; +}; + +#endif diff --git a/src/feature/nodelist/node_st.h b/src/feature/nodelist/node_st.h new file mode 100644 index 0000000000..8d182050ac --- /dev/null +++ b/src/feature/nodelist/node_st.h @@ -0,0 +1,102 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef NODE_ST_H +#define NODE_ST_H + +#include "feature/hs/hsdir_index_st.h" +#include "lib/crypt_ops/crypto_ed25519.h" + +/** A node_t represents a Tor router. + * + * Specifically, a node_t is a Tor router as we are using it: a router that + * we are considering for circuits, connections, and so on. A node_t is a + * thin wrapper around the routerstatus, routerinfo, and microdesc for a + * single router, and provides a consistent interface for all of them. + * + * Also, a node_t has mutable state. While a routerinfo, a routerstatus, + * and a microdesc have[*] only the information read from a router + * descriptor, a consensus entry, and a microdescriptor (respectively)... + * a node_t has flags based on *our own current opinion* of the node. + * + * [*] Actually, there is some leftover information in each that is mutable. + * We should try to excise that. + */ +struct node_t { + /* Indexing information */ + + /** Used to look up the node_t by its identity digest. */ + HT_ENTRY(node_t) ht_ent; + /** Used to look up the node_t by its ed25519 identity digest. */ + HT_ENTRY(node_t) ed_ht_ent; + /** Position of the node within the list of nodes */ + int nodelist_idx; + + /** The identity digest of this node_t. No more than one node_t per + * identity may exist at a time. */ + char identity[DIGEST_LEN]; + + /** The ed25519 identity of this node_t. This field is nonzero iff we + * currently have an ed25519 identity for this node in either md or ri, + * _and_ this node has been inserted to the ed25519-to-node map in the + * nodelist. + */ + ed25519_public_key_t ed25519_id; + + microdesc_t *md; + routerinfo_t *ri; + routerstatus_t *rs; + + /* local info: copied from routerstatus, then possibly frobbed based + * on experience. Authorities set this stuff directly. Note that + * these reflect knowledge of the primary (IPv4) OR port only. */ + + unsigned int is_running:1; /**< As far as we know, is this OR currently + * running? */ + unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR? + * (For Authdir: Have we validated this OR?) */ + unsigned int is_fast:1; /** Do we think this is a fast OR? */ + unsigned int is_stable:1; /** Do we think this is a stable OR? */ + unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */ + unsigned int is_exit:1; /**< Do we think this is an OK exit? */ + unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, + * or otherwise nasty? */ + unsigned int is_hs_dir:1; /**< True iff this router is a hidden service + * directory according to the authorities. */ + + /* Local info: warning state. */ + + unsigned int name_lookup_warned:1; /**< Have we warned the user for referring + * to this (unnamed) router by nickname? + */ + + /** Local info: we treat this node as if it rejects everything */ + unsigned int rejects_all:1; + + /* Local info: derived. */ + + /** True if the IPv6 OR port is preferred over the IPv4 OR port. + * XX/teor - can this become out of date if the torrc changes? */ + unsigned int ipv6_preferred:1; + + /** According to the geoip db what country is this router in? */ + /* XXXprop186 what is this suppose to mean with multiple OR ports? */ + country_t country; + + /* The below items are used only by authdirservers for + * reachability testing. */ + + /** When was the last time we could reach this OR? */ + time_t last_reachable; /* IPv4. */ + time_t last_reachable6; /* IPv6. */ + + /* Hidden service directory index data. This is used by a service or client + * in order to know what's the hs directory index for this node at the time + * the consensus is set. */ + struct hsdir_index_t hsdir_index; +}; + +#endif diff --git a/src/or/nodelist.c b/src/feature/nodelist/nodelist.c index ce1830083f..03122ba0f7 100644 --- a/src/or/nodelist.c +++ b/src/feature/nodelist/nodelist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -40,33 +40,41 @@ #define NODELIST_PRIVATE -#include "or.h" -#include "address.h" -#include "address_set.h" -#include "bridges.h" -#include "config.h" -#include "control.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "geoip.h" -#include "hs_common.h" -#include "hs_client.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "protover.h" -#include "rendservice.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "torcert.h" +#include "core/or/or.h" +#include "lib/net/address.h" +#include "core/or/address_set.h" +#include "feature/client/bridges.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/entrynodes.h" +#include "feature/stats/geoip.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_client.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "feature/rend/rendservice.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "feature/nodelist/torcert.h" #include <string.h> -#include "dirauth/mode.h" +#include "feature/dirauth/mode.h" + +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "feature/nodelist/routerstatus_st.h" static void nodelist_drop_node(node_t *node, int remove_from_ht); #define node_free(val) \ @@ -643,6 +651,15 @@ nodelist_set_consensus(networkstatus_t *ns) } } +/** Return 1 iff <b>node</b> has Exit flag and no BadExit flag. + * Otherwise, return 0. + */ +int +node_is_good_exit(const node_t *node) +{ + return node->is_exit && ! node->is_bad_exit; +} + /** Helper: return true iff a node has a usable amount of information*/ static inline int node_is_usable(const node_t *node) @@ -2243,9 +2260,14 @@ compute_frac_paths_available(const networkstatus_t *consensus, * browsing (as distinct from hidden service web browsing). */ } - f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD); - f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID); - f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT); + f_guard = frac_nodes_with_descriptors(guards, WEIGHT_FOR_GUARD, 1); + f_mid = frac_nodes_with_descriptors(mid, WEIGHT_FOR_MID, 0); + f_exit = frac_nodes_with_descriptors(exits, WEIGHT_FOR_EXIT, 0); + + /* If we are using bridges and have at least one bridge with a full + * descriptor, assume f_guard is 1.0. */ + if (options->UseBridges && num_bridges_usable(0) > 0) + f_guard = 1.0; log_debug(LD_NET, "f_guard: %.2f, f_mid: %.2f, f_exit: %.2f", @@ -2299,9 +2321,10 @@ compute_frac_paths_available(const networkstatus_t *consensus, np, nu); - f_myexit= frac_nodes_with_descriptors(myexits,WEIGHT_FOR_EXIT); + f_myexit= frac_nodes_with_descriptors(myexits, WEIGHT_FOR_EXIT, 0); f_myexit_unflagged= - frac_nodes_with_descriptors(myexits_unflagged,WEIGHT_FOR_EXIT); + frac_nodes_with_descriptors(myexits_unflagged, + WEIGHT_FOR_EXIT, 0); log_debug(LD_NET, "f_exit: %.2f, f_myexit: %.2f, f_myexit_unflagged: %.2f", diff --git a/src/or/nodelist.h b/src/feature/nodelist/nodelist.h index dbe9ad18ff..ed3a542971 100644 --- a/src/or/nodelist.h +++ b/src/feature/nodelist/nodelist.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,15 +12,19 @@ #ifndef TOR_NODELIST_H #define TOR_NODELIST_H +struct ed25519_public_key_t; +struct curve25519_public_key_t; + #define node_assert_ok(n) STMT_BEGIN { \ tor_assert((n)->ri || (n)->rs); \ } STMT_END MOCK_DECL(node_t *, node_get_mutable_by_id,(const char *identity_digest)); MOCK_DECL(const node_t *, node_get_by_id, (const char *identity_digest)); -node_t *node_get_mutable_by_ed25519_id(const ed25519_public_key_t *ed_id); +node_t *node_get_mutable_by_ed25519_id( + const struct ed25519_public_key_t *ed_id); MOCK_DECL(const node_t *, node_get_by_ed25519_id, - (const ed25519_public_key_t *ed_id)); + (const struct ed25519_public_key_t *ed_id)); #define NNF_NO_WARN_UNNAMED (1u<<0) @@ -47,6 +51,7 @@ void node_get_verbose_nickname(const node_t *node, void node_get_verbose_nickname_by_id(const char *id_digest, char *verbose_name_out); int node_is_dir(const node_t *node); +int node_is_good_exit(const node_t *node); int node_has_any_descriptor(const node_t *node); int node_has_preferred_descriptor(const node_t *node, int for_direct_connect); @@ -64,9 +69,9 @@ uint32_t node_get_prim_addr_ipv4h(const node_t *node); void node_get_address_string(const node_t *node, char *cp, size_t len); long node_get_declared_uptime(const node_t *node); const smartlist_t *node_get_declared_family(const node_t *node); -const ed25519_public_key_t *node_get_ed25519_id(const node_t *node); +const struct ed25519_public_key_t *node_get_ed25519_id(const node_t *node); int node_ed25519_id_matches(const node_t *node, - const ed25519_public_key_t *id); + const struct ed25519_public_key_t *id); int node_supports_ed25519_link_authentication(const node_t *node, int compatible_with_us); int node_supports_v3_hsdir(const node_t *node); @@ -88,7 +93,7 @@ void node_get_prim_dirport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_dirport(const node_t *node, tor_addr_port_t *ap_out); void node_get_pref_ipv6_dirport(const node_t *node, tor_addr_port_t *ap_out); int node_has_curve25519_onion_key(const node_t *node); -const curve25519_public_key_t *node_get_curve25519_onion_key( +const struct curve25519_public_key_t *node_get_curve25519_onion_key( const node_t *node); MOCK_DECL(smartlist_t *, nodelist_get_list, (void)); @@ -161,4 +166,3 @@ node_set_hsdir_index(node_t *node, const networkstatus_t *ns); MOCK_DECL(int, get_estimated_address_per_node, (void)); #endif /* !defined(TOR_NODELIST_H) */ - diff --git a/src/or/parsecommon.c b/src/feature/nodelist/parsecommon.c index 9bd00e17ce..4f1c3fd421 100644 --- a/src/or/parsecommon.c +++ b/src/feature/nodelist/parsecommon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,9 +6,17 @@ * \brief Common code to parse and validate various type of descriptors. **/ -#include "parsecommon.h" -#include "torlog.h" -#include "util_format.h" +#include "feature/nodelist/parsecommon.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/encoding/binascii.h" +#include "lib/container/smartlist.h" +#include "lib/string/util_string.h" +#include "lib/string/printf.h" +#include "lib/memarea/memarea.h" +#include "lib/crypt_ops/crypto.h" + +#include <string.h> #define MIN_ANNOTATION A_PURPOSE #define MAX_ANNOTATION A_UNKNOWN_ @@ -448,4 +456,3 @@ find_all_by_keyword(const smartlist_t *s, directory_keyword k) }); return out; } - diff --git a/src/or/parsecommon.h b/src/feature/nodelist/parsecommon.h index d33faf8ec7..d0f3810c0b 100644 --- a/src/or/parsecommon.h +++ b/src/feature/nodelist/parsecommon.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,9 +9,11 @@ #ifndef TOR_PARSECOMMON_H #define TOR_PARSECOMMON_H -#include "container.h" -#include "crypto.h" -#include "memarea.h" +#include <stddef.h> + +struct smartlist_t; +struct crypto_pk_t; +struct memarea_t; /** Enumeration of possible token types. The ones starting with K_ correspond * to directory 'keywords'. A_ is for an annotation, R or C is related to @@ -205,7 +207,7 @@ typedef struct directory_token_t { size_t object_size; /**< Bytes in object_body */ char *object_body; /**< Contents of object, base64-decoded. */ - crypto_pk_t *key; /**< For public keys only. Heap-allocated. */ + struct crypto_pk_t *key; /**< For public keys only. Heap-allocated. */ char *error; /**< For ERR_ tokens only. */ } directory_token_t; @@ -297,26 +299,26 @@ typedef struct token_rule_t { void token_clear(directory_token_t *tok); -int tokenize_string(memarea_t *area, +int tokenize_string(struct memarea_t *area, const char *start, const char *end, - smartlist_t *out, + struct smartlist_t *out, token_rule_t *table, int flags); -directory_token_t *get_next_token(memarea_t *area, +directory_token_t *get_next_token(struct memarea_t *area, const char **s, const char *eos, token_rule_t *table); -directory_token_t *find_by_keyword_(smartlist_t *s, +directory_token_t *find_by_keyword_(struct smartlist_t *s, directory_keyword keyword, const char *keyword_str); #define find_by_keyword(s, keyword) \ find_by_keyword_((s), (keyword), #keyword) -directory_token_t *find_opt_by_keyword(const smartlist_t *s, +directory_token_t *find_opt_by_keyword(const struct smartlist_t *s, directory_keyword keyword); -smartlist_t * find_all_by_keyword(const smartlist_t *s, directory_keyword k); +struct smartlist_t * find_all_by_keyword(const struct smartlist_t *s, + directory_keyword k); #endif /* !defined(TOR_PARSECOMMON_H) */ - diff --git a/src/feature/nodelist/routerinfo_st.h b/src/feature/nodelist/routerinfo_st.h new file mode 100644 index 0000000000..ca8fd40e3b --- /dev/null +++ b/src/feature/nodelist/routerinfo_st.h @@ -0,0 +1,108 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ROUTERINFO_ST_H +#define ROUTERINFO_ST_H + +#include "feature/nodelist/signed_descriptor_st.h" + +struct curve25519_public_key_t; + +/** Information about another onion router in the network. */ +struct routerinfo_t { + signed_descriptor_t cache_info; + char *nickname; /**< Human-readable OR name. */ + + uint32_t addr; /**< IPv4 address of OR, in host order. */ + uint16_t or_port; /**< Port for TLS connections. */ + uint16_t dir_port; /**< Port for HTTP directory connections. */ + + /** A router's IPv6 address, if it has one. */ + /* XXXXX187 Actually these should probably be part of a list of addresses, + * not just a special case. Use abstractions to access these; don't do it + * directly. */ + tor_addr_t ipv6_addr; + uint16_t ipv6_orport; + + crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */ + crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ + /** Public curve25519 key for onions */ + struct curve25519_public_key_t *onion_curve25519_pkey; + /** What's the earliest expiration time on all the certs in this + * routerinfo? */ + time_t cert_expiration_time; + + char *platform; /**< What software/operating system is this OR using? */ + + char *protocol_list; /**< Encoded list of subprotocol versions supported + * by this OR */ + + /* link info */ + uint32_t bandwidthrate; /**< How many bytes does this OR add to its token + * bucket per second? */ + uint32_t bandwidthburst; /**< How large is this OR's token bucket? */ + /** How many bytes/s is this router known to handle? */ + uint32_t bandwidthcapacity; + smartlist_t *exit_policy; /**< What streams will this OR permit + * to exit on IPv4? NULL for 'reject *:*'. */ + /** What streams will this OR permit to exit on IPv6? + * NULL for 'reject *:*' */ + struct short_policy_t *ipv6_exit_policy; + long uptime; /**< How many seconds the router claims to have been up */ + smartlist_t *declared_family; /**< Nicknames of router which this router + * claims are its family. */ + char *contact_info; /**< Declared contact info for this router. */ + unsigned int is_hibernating:1; /**< Whether the router claims to be + * hibernating */ + unsigned int caches_extra_info:1; /**< Whether the router says it caches and + * serves extrainfo documents. */ + unsigned int allow_single_hop_exits:1; /**< Whether the router says + * it allows single hop exits. */ + + unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be + * a hidden service directory. */ + unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this + * router rejects everything. */ + /** True if, after we have added this router, we should re-launch + * tests for it. */ + unsigned int needs_retest_if_added:1; + + /** True iff this router included "tunnelled-dir-server" in its descriptor, + * implying it accepts tunnelled directory requests, or it advertised + * dir_port > 0. */ + unsigned int supports_tunnelled_dir_requests:1; + + /** Used during voting to indicate that we should not include an entry for + * this routerinfo. Used only during voting. */ + unsigned int omit_from_vote:1; + + /** Flags to summarize the protocol versions for this routerinfo_t. */ + protover_summary_flags_t pv; + +/** Tor can use this router for general positions in circuits; we got it + * from a directory server as usual, or we're an authority and a server + * uploaded it. */ +#define ROUTER_PURPOSE_GENERAL 0 +/** Tor should avoid using this router for circuit-building: we got it + * from a controller. If the controller wants to use it, it'll have to + * ask for it by identity. */ +#define ROUTER_PURPOSE_CONTROLLER 1 +/** Tor should use this router only for bridge positions in circuits: we got + * it via a directory request from the bridge itself, or a bridge + * authority. */ +#define ROUTER_PURPOSE_BRIDGE 2 +/** Tor should not use this router; it was marked in cached-descriptors with + * a purpose we didn't recognize. */ +#define ROUTER_PURPOSE_UNKNOWN 255 + + /** In what way did we find out about this router? One of ROUTER_PURPOSE_*. + * Routers of different purposes are kept segregated and used for different + * things; see notes on ROUTER_PURPOSE_* macros above. + */ + uint8_t purpose; +}; + +#endif diff --git a/src/or/routerlist.c b/src/feature/nodelist/routerlist.c index 2f27af7f06..12226fee64 100644 --- a/src/or/routerlist.c +++ b/src/feature/nodelist/routerlist.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -91,39 +91,59 @@ **/ #define ROUTERLIST_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "bridges.h" -#include "crypto_ed25519.h" -#include "circuitstats.h" -#include "config.h" -#include "connection.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "fp_pair.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "reasons.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "sandbox.h" -#include "torcert.h" - -#include "dirauth/dirvote.h" -#include "dirauth/mode.h" +#include "core/or/or.h" +#include "lib/err/backtrace.h" +#include "feature/client/bridges.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "core/or/circuitstats.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/entrynodes.h" +#include "feature/dircommon/fp_pair.h" +#include "feature/stats/geoip.h" +#include "feature/hibernate/hibernate.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/or/reasons.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "lib/sandbox/sandbox.h" +#include "feature/nodelist/torcert.h" +#include "lib/math/fp.h" + +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/mode.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/document_signature_st.h" +#include "feature/nodelist/extrainfo_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/networkstatus_voter_info_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" + +#include "lib/crypt_ops/digestset.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif // #define DEBUG_ROUTERLIST @@ -1786,6 +1806,12 @@ router_pick_dirserver_generic(smartlist_t *sourcelist, const routerstatus_t *choice; int busy = 0; + if (smartlist_len(sourcelist) == 1) { + /* If there's only one choice, then we should disable the logic that + * would otherwise prevent us from choosing ourself. */ + flags |= PDS_ALLOW_SELF; + } + choice = router_pick_trusteddirserver_impl(sourcelist, type, flags, &busy); if (choice || !(flags & PDS_RETRY_IF_NO_SERVERS)) return choice; @@ -2746,10 +2772,15 @@ compute_weighted_bandwidths(const smartlist_t *sl, /** For all nodes in <b>sl</b>, return the fraction of those nodes, weighted * by their weighted bandwidths with rule <b>rule</b>, for which we have - * descriptors. */ + * descriptors. + * + * If <b>for_direct_connect</b> is true, we intend to connect to the node + * directly, as the first hop of a circuit; otherwise, we intend to connect + * to it indirectly, or use it as if we were connecting to it indirectly. */ double frac_nodes_with_descriptors(const smartlist_t *sl, - bandwidth_weight_rule_t rule) + bandwidth_weight_rule_t rule, + int for_direct_conn) { double *bandwidths = NULL; double total, present; @@ -2761,7 +2792,7 @@ frac_nodes_with_descriptors(const smartlist_t *sl, total <= 0.0) { int n_with_descs = 0; SMARTLIST_FOREACH(sl, const node_t *, node, { - if (node_has_any_descriptor(node)) + if (node_has_preferred_descriptor(node, for_direct_conn)) n_with_descs++; }); tor_free(bandwidths); @@ -2770,7 +2801,7 @@ frac_nodes_with_descriptors(const smartlist_t *sl, present = 0.0; SMARTLIST_FOREACH_BEGIN(sl, const node_t *, node) { - if (node_has_any_descriptor(node)) + if (node_has_preferred_descriptor(node, for_direct_conn)) present += bandwidths[node_sl_idx]; } SMARTLIST_FOREACH_END(node); @@ -3328,10 +3359,10 @@ dump_routerlist_mem_usage(int severity) olddescs += sd->signed_descriptor_len); tor_log(severity, LD_DIR, - "In %d live descriptors: "U64_FORMAT" bytes. " - "In %d old descriptors: "U64_FORMAT" bytes.", - smartlist_len(routerlist->routers), U64_PRINTF_ARG(livedescs), - smartlist_len(routerlist->old_routers), U64_PRINTF_ARG(olddescs)); + "In %d live descriptors: %"PRIu64" bytes. " + "In %d old descriptors: %"PRIu64" bytes.", + smartlist_len(routerlist->routers), (livedescs), + smartlist_len(routerlist->old_routers), (olddescs)); } /** Debugging helper: If <b>idx</b> is nonnegative, assert that <b>ri</b> is @@ -4098,7 +4129,8 @@ routerlist_remove_old_cached_routers_with_id(time_t now, signed_descriptor_t *r_next; lifespans[i-lo].idx = i; if (r->last_listed_as_valid_until >= now || - (retain && digestset_contains(retain, r->signed_descriptor_digest))) { + (retain && digestset_probably_contains(retain, + r->signed_descriptor_digest))) { must_keep[i-lo] = 1; } if (i < hi) { @@ -4193,7 +4225,7 @@ routerlist_remove_old_routers(void) router = smartlist_get(routerlist->routers, i); if (router->cache_info.published_on <= cutoff && router->cache_info.last_listed_as_valid_until < now && - !digestset_contains(retain, + !digestset_probably_contains(retain, router->cache_info.signed_descriptor_digest)) { /* Too old: remove it. (If we're a cache, just move it into * old_routers.) */ @@ -4214,7 +4246,7 @@ routerlist_remove_old_routers(void) sd = smartlist_get(routerlist->old_routers, i); if (sd->published_on <= cutoff && sd->last_listed_as_valid_until < now && - !digestset_contains(retain, sd->signed_descriptor_digest)) { + !digestset_probably_contains(retain, sd->signed_descriptor_digest)) { /* Too old. Remove it. */ routerlist_remove_old(routerlist, sd, i--); } @@ -5820,4 +5852,3 @@ refresh_all_country_info(void) nodelist_refresh_countries(); } - diff --git a/src/or/routerlist.h b/src/feature/nodelist/routerlist.h index 83f4d1002f..4b7406364f 100644 --- a/src/or/routerlist.h +++ b/src/feature/nodelist/routerlist.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,7 +11,91 @@ #ifndef TOR_ROUTERLIST_H #define TOR_ROUTERLIST_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" + +/** Return value for router_add_to_routerlist() and dirserv_add_descriptor() */ +typedef enum was_router_added_t { + /* Router was added successfully. */ + ROUTER_ADDED_SUCCESSFULLY = 1, + /* Extrainfo document was rejected because no corresponding router + * descriptor was found OR router descriptor was rejected because + * it was incompatible with its extrainfo document. */ + ROUTER_BAD_EI = -1, + /* Router descriptor was rejected because it is already known. */ + ROUTER_IS_ALREADY_KNOWN = -2, + /* General purpose router was rejected, because it was not listed + * in consensus. */ + ROUTER_NOT_IN_CONSENSUS = -3, + /* Router was neither in directory consensus nor in any of + * networkstatus documents. Caching it to access later. + * (Applies to fetched descriptors only.) */ + ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS = -4, + /* Router was rejected by directory authority. */ + ROUTER_AUTHDIR_REJECTS = -5, + /* Bridge descriptor was rejected because such bridge was not one + * of the bridges we have listed in our configuration. */ + ROUTER_WAS_NOT_WANTED = -6, + /* Router descriptor was rejected because it was older than + * OLD_ROUTER_DESC_MAX_AGE. */ + ROUTER_WAS_TOO_OLD = -7, /* note contrast with 'NOT_NEW' */ + /* DOCDOC */ + ROUTER_CERTS_EXPIRED = -8 +} was_router_added_t; + +/** Flags to be passed to control router_choose_random_node() to indicate what + * kind of nodes to pick according to what algorithm. */ +typedef enum router_crn_flags_t { + CRN_NEED_UPTIME = 1<<0, + CRN_NEED_CAPACITY = 1<<1, + CRN_NEED_GUARD = 1<<2, + /* XXXX not used, apparently. */ + CRN_WEIGHT_AS_EXIT = 1<<5, + CRN_NEED_DESC = 1<<6, + /* On clients, only provide nodes that satisfy ClientPreferIPv6OR */ + CRN_PREF_ADDR = 1<<7, + /* On clients, only provide nodes that we can connect to directly, based on + * our firewall rules */ + CRN_DIRECT_CONN = 1<<8, + /* On clients, only provide nodes with HSRend >= 2 protocol version which + * is required for hidden service version >= 3. */ + CRN_RENDEZVOUS_V3 = 1<<9, +} router_crn_flags_t; + +/** Possible ways to weight routers when choosing one randomly. See + * routerlist_sl_choose_by_bandwidth() for more information.*/ +typedef enum bandwidth_weight_rule_t { + NO_WEIGHTING, WEIGHT_FOR_EXIT, WEIGHT_FOR_MID, WEIGHT_FOR_GUARD, + WEIGHT_FOR_DIR +} bandwidth_weight_rule_t; + +/* Flags for pick_directory_server() and pick_trusteddirserver(). */ +/** Flag to indicate that we should not automatically be willing to use + * ourself to answer a directory request. + * Passed to router_pick_directory_server (et al).*/ +#define PDS_ALLOW_SELF (1<<0) +/** Flag to indicate that if no servers seem to be up, we should mark all + * directory servers as up and try again. + * Passed to router_pick_directory_server (et al).*/ +#define PDS_RETRY_IF_NO_SERVERS (1<<1) +/** Flag to indicate that we should not exclude directory servers that + * our ReachableAddress settings would exclude. This usually means that + * we're going to connect to the server over Tor, and so we don't need to + * worry about our firewall telling us we can't. + * Passed to router_pick_directory_server (et al).*/ +#define PDS_IGNORE_FASCISTFIREWALL (1<<2) +/** Flag to indicate that we should not use any directory authority to which + * we have an existing directory connection for downloading server descriptors + * or extrainfo documents. + * + * Passed to router_pick_directory_server (et al) + */ +#define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3) +/** Flag to indicate that we should not use any directory authority to which + * we have an existing directory connection for downloading microdescs. + * + * Passed to router_pick_directory_server (et al) + */ +#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4) int get_n_authorities(dirinfo_type_t type); int trusted_dirs_reload_certs(void); @@ -74,7 +158,8 @@ uint32_t router_get_advertised_bandwidth_capped(const routerinfo_t *router); const node_t *node_sl_choose_by_bandwidth(const smartlist_t *sl, bandwidth_weight_rule_t rule); double frac_nodes_with_descriptors(const smartlist_t *sl, - bandwidth_weight_rule_t rule); + bandwidth_weight_rule_t rule, + int for_direct_conn); const node_t *router_choose_random_node(smartlist_t *excludedsmartlist, struct routerset_t *excludedset, @@ -260,4 +345,3 @@ STATIC int router_is_already_dir_fetching(const tor_addr_port_t *ap, #endif /* defined(ROUTERLIST_PRIVATE) */ #endif /* !defined(TOR_ROUTERLIST_H) */ - diff --git a/src/feature/nodelist/routerlist_st.h b/src/feature/nodelist/routerlist_st.h new file mode 100644 index 0000000000..26cc66138c --- /dev/null +++ b/src/feature/nodelist/routerlist_st.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ROUTERLIST_ST_H +#define ROUTERLIST_ST_H + +#include "feature/nodelist/desc_store_st.h" + +/** Contents of a directory of onion routers. */ +struct routerlist_t { + /** Map from server identity digest to a member of routers. */ + struct digest_ri_map_t *identity_map; + /** Map from server descriptor digest to a signed_descriptor_t from + * routers or old_routers. */ + struct digest_sd_map_t *desc_digest_map; + /** Map from extra-info digest to an extrainfo_t. Only exists for + * routers in routers or old_routers. */ + struct digest_ei_map_t *extra_info_map; + /** Map from extra-info digests to a signed_descriptor_t for a router + * descriptor having that extra-info digest. Only exists for + * routers in routers or old_routers. */ + struct digest_sd_map_t *desc_by_eid_map; + /** List of routerinfo_t for all currently live routers we know. */ + smartlist_t *routers; + /** List of signed_descriptor_t for older router descriptors we're + * caching. */ + smartlist_t *old_routers; + /** Store holding server descriptors. If present, any router whose + * cache_info.saved_location == SAVED_IN_CACHE is stored in this file + * starting at cache_info.saved_offset */ + desc_store_t desc_store; + /** Store holding extra-info documents. */ + desc_store_t extrainfo_store; +}; + +#endif + diff --git a/src/or/routerparse.c b/src/feature/nodelist/routerparse.c index 7af41c3baf..166806e9c1 100644 --- a/src/or/routerparse.c +++ b/src/feature/nodelist/routerparse.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -55,34 +55,58 @@ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "circuitstats.h" -#include "config.h" -#include "crypto_util.h" -#include "dirauth/shared_random.h" -#include "dirserv.h" -#include "entrynodes.h" -#include "memarea.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "parsecommon.h" -#include "policies.h" -#include "protover.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "sandbox.h" -#include "shared_random_client.h" -#include "torcert.h" -#include "voting_schedule.h" +#include "core/or/or.h" +#include "core/or/circuitstats.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dirauth/shared_random.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/entrynodes.h" +#include "lib/memarea/memarea.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/parsecommon.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "feature/rend/rendcommon.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "lib/sandbox/sandbox.h" +#include "feature/hs_common/shared_random_client.h" +#include "feature/nodelist/torcert.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/dirauth/dirvote.h" + +#include "core/or/addr_policy_st.h" +#include "feature/nodelist/authority_cert_st.h" +#include "feature/nodelist/document_signature_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/extrainfo_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/networkstatus_voter_info_st.h" +#include "feature/dirauth/ns_detached_signatures_st.h" +#include "feature/rend/rend_authorized_client_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "core/or/tor_version_st.h" +#include "feature/dirauth/vote_microdesc_hash_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" + +#include "lib/container/bloomfilt.h" #undef log #include <math.h> - -#include "dirauth/dirvote.h" +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /****************************************************************************/ @@ -855,8 +879,8 @@ dump_desc_populate_fifo_from_directory(const char *dirname) /* Log some stats */ log_info(LD_DIR, "Reloaded unparseable descriptor dump FIFO with %d dump(s) " - "totaling " U64_FORMAT " bytes", - smartlist_len(descs_dumped), U64_PRINTF_ARG(len_descs_dumped)); + "totaling %"PRIu64 " bytes", + smartlist_len(descs_dumped), (len_descs_dumped)); } /* Free the original list */ @@ -2705,7 +2729,7 @@ routerstatus_parse_entry_from_string(memarea_t *area, for (i=0; i < tok->n_args; ++i) { int p = smartlist_string_pos(vote->known_flags, tok->args[i]); if (p >= 0) { - vote_rs->flags |= (U64_LITERAL(1)<<p); + vote_rs->flags |= (UINT64_C(1)<<p); } else { log_warn(LD_DIR, "Flags line had a flag %s not listed in known_flags.", escaped(tok->args[i])); @@ -2928,8 +2952,8 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) // We use > 1 as the check for these because they are computed as integers. // Sometimes there are rounding errors. if (fabs(Wmm - weight_scale) > 1) { - log_warn(LD_BUG, "Wmm=%f != "I64_FORMAT, - Wmm, I64_PRINTF_ARG(weight_scale)); + log_warn(LD_BUG, "Wmm=%f != %"PRId64, + Wmm, (weight_scale)); valid = 0; } @@ -2949,20 +2973,20 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) } if (fabs(Wgg + Wmg - weight_scale) > 0.001*weight_scale) { - log_warn(LD_BUG, "Wgg=%f != "I64_FORMAT" - Wmg=%f", Wgg, - I64_PRINTF_ARG(weight_scale), Wmg); + log_warn(LD_BUG, "Wgg=%f != %"PRId64" - Wmg=%f", Wgg, + (weight_scale), Wmg); valid = 0; } if (fabs(Wee + Wme - weight_scale) > 0.001*weight_scale) { - log_warn(LD_BUG, "Wee=%f != "I64_FORMAT" - Wme=%f", Wee, - I64_PRINTF_ARG(weight_scale), Wme); + log_warn(LD_BUG, "Wee=%f != %"PRId64" - Wme=%f", Wee, + (weight_scale), Wme); valid = 0; } if (fabs(Wgd + Wmd + Wed - weight_scale) > 0.001*weight_scale) { - log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != "I64_FORMAT, - Wgd, Wmd, Wed, I64_PRINTF_ARG(weight_scale)); + log_warn(LD_BUG, "Wgd=%f + Wmd=%f + Wed=%f != %"PRId64, + Wgd, Wmd, Wed, (weight_scale)); valid = 0; } @@ -3020,36 +3044,36 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Mtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Mtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Mtotal, Gtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3076,12 +3100,12 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (Rtotal > Stotal) { log_warn(LD_DIR, "Bw Weight Failure for %s: Rtotal %f > Stotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Rtotal, Stotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3089,12 +3113,12 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (3*Rtotal > T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Rtotal %f > T " - I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT - " D="I64_FORMAT" T="I64_FORMAT". " + "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64 + " D=%"PRId64" T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", - casename, Rtotal*3, I64_PRINTF_ARG(T), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + casename, Rtotal*3, (T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3102,12 +3126,12 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (3*Stotal > T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Stotal %f > T " - I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT - " D="I64_FORMAT" T="I64_FORMAT". " + "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64 + " D=%"PRId64" T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", - casename, Stotal*3, I64_PRINTF_ARG(T), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + casename, Stotal*3, (T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3115,13 +3139,13 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (3*Mtotal < T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Mtotal %f < T " - I64_FORMAT". " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "%"PRId64". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", - casename, Mtotal*3, I64_PRINTF_ARG(T), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + casename, Mtotal*3, (T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3134,36 +3158,36 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Mtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Mtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Mtotal, Gtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3171,12 +3195,12 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3201,12 +3225,12 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (3*Stotal > T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*Stotal %f > T " - I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT - " D="I64_FORMAT" T="I64_FORMAT". " + "%"PRId64". G=%"PRId64" M=%"PRId64" E=%"PRId64 + " D=%"PRId64" T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", - casename, Stotal*3, I64_PRINTF_ARG(T), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + casename, Stotal*3, (T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3214,12 +3238,12 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (fabs(NStotal-Mtotal) > 0.01*MAX(NStotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: NStotal %f != Mtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, NStotal, Mtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3228,12 +3252,12 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (3*NStotal < T) { log_warn(LD_DIR, "Bw Weight Failure for %s: 3*NStotal %f < T " - I64_FORMAT". G="I64_FORMAT" M="I64_FORMAT - " E="I64_FORMAT" D="I64_FORMAT" T="I64_FORMAT". " + "%"PRId64". G=%"PRId64" M=%"PRId64 + " E=%"PRId64" D=%"PRId64" T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", - casename, NStotal*3, I64_PRINTF_ARG(T), - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + casename, NStotal*3, (T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -3243,36 +3267,36 @@ networkstatus_verify_bw_weights(networkstatus_t *ns, int consensus_method) if (fabs(Etotal-Mtotal) > 0.01*MAX(Etotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Mtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Mtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Etotal-Gtotal) > 0.01*MAX(Etotal,Gtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Etotal %f != Gtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Etotal, Gtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } if (fabs(Gtotal-Mtotal) > 0.01*MAX(Gtotal,Mtotal)) { log_warn(LD_DIR, "Bw Weight Failure for %s: Mtotal %f != Gtotal %f. " - "G="I64_FORMAT" M="I64_FORMAT" E="I64_FORMAT" D="I64_FORMAT - " T="I64_FORMAT". " + "G=%"PRId64" M=%"PRId64" E=%"PRId64" D=%"PRId64 + " T=%"PRId64". " "Wgg=%f Wgd=%f Wmg=%f Wme=%f Wmd=%f Wee=%f Wed=%f", casename, Mtotal, Gtotal, - I64_PRINTF_ARG(G), I64_PRINTF_ARG(M), I64_PRINTF_ARG(E), - I64_PRINTF_ARG(D), I64_PRINTF_ARG(T), + (G), (M), (E), + (D), (T), Wgg, Wgd, Wmg, Wme, Wmd, Wee, Wed); valid = 0; } @@ -5667,4 +5691,3 @@ routerparse_free_all(void) { dump_desc_fifo_cleanup(); } - diff --git a/src/or/routerparse.h b/src/feature/nodelist/routerparse.h index 418fd3acdb..87c2a75aa5 100644 --- a/src/or/routerparse.h +++ b/src/feature/nodelist/routerparse.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,6 +12,22 @@ #ifndef TOR_ROUTERPARSE_H #define TOR_ROUTERPARSE_H +/** Possible statuses of a version of Tor, given opinions from the directory + * servers. */ +typedef enum version_status_t { + VS_RECOMMENDED=0, /**< This version is listed as recommended. */ + VS_OLD=1, /**< This version is older than any recommended version. */ + VS_NEW=2, /**< This version is newer than any recommended version. */ + VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version + * in its series, but later recommended versions exist. + */ + VS_UNRECOMMENDED=4, /**< This version is not recommended (general case). */ + VS_EMPTY=5, /**< The version list was empty; no agreed-on versions. */ + VS_UNKNOWN, /**< We have no idea. */ +} version_status_t; + +enum networkstatus_type_t; + int router_get_router_hash(const char *s, size_t s_len, char *digest); int router_get_dir_hash(const char *s, char *digest); int router_get_networkstatus_v3_hashes(const char *s, @@ -43,6 +59,7 @@ routerinfo_t *router_parse_entry_from_string(const char *s, const char *end, int allow_annotations, const char *prepend_annotations, int *can_dl_again_out); +struct digest_ri_map_t; extrainfo_t *extrainfo_parse_entry_from_string(const char *s, const char *end, int cache_copy, struct digest_ri_map_t *routermap, int *can_dl_again_out); @@ -64,8 +81,8 @@ void dump_distinct_digest_count(int severity); int compare_vote_routerstatus_entries(const void **_a, const void **_b); int networkstatus_verify_bw_weights(networkstatus_t *ns, int); networkstatus_t *networkstatus_parse_vote_from_string(const char *s, - const char **eos_out, - networkstatus_type_t ns_type); + const char **eos_out, + enum networkstatus_type_t ns_type); ns_detached_signatures_t *networkstatus_parse_detached_signatures( const char *s, const char *eos); @@ -142,4 +159,3 @@ STATIC void summarize_protover_flags(protover_summary_flags_t *out, #define ED_DESC_SIGNATURE_PREFIX "Tor router descriptor signature v1" #endif /* !defined(TOR_ROUTERPARSE_H) */ - diff --git a/src/or/routerset.c b/src/feature/nodelist/routerset.c index a2599b316c..cd42697748 100644 --- a/src/or/routerset.c +++ b/src/feature/nodelist/routerset.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. +n * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -27,14 +27,20 @@ #define ROUTERSET_PRIVATE -#include "or.h" -#include "bridges.h" -#include "geoip.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerparse.h" -#include "routerset.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "feature/stats/geoip.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" + +#include "core/or/addr_policy_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" /** Return a new empty routerset. */ routerset_t * @@ -455,4 +461,3 @@ routerset_free_(routerset_t *routerset) bitarray_free(routerset->countries); tor_free(routerset); } - diff --git a/src/or/routerset.h b/src/feature/nodelist/routerset.h index 53e8c66c5e..8a13ca042a 100644 --- a/src/or/routerset.h +++ b/src/feature/nodelist/routerset.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -45,6 +45,8 @@ void routerset_free_(routerset_t *routerset); int routerset_len(const routerset_t *set); #ifdef ROUTERSET_PRIVATE +#include "lib/container/bitarray.h" + STATIC char * routerset_get_countryname(const char *c); STATIC int routerset_contains(const routerset_t *set, const tor_addr_t *addr, uint16_t orport, @@ -85,4 +87,3 @@ struct routerset_t { }; #endif /* defined(ROUTERSET_PRIVATE) */ #endif /* !defined(TOR_ROUTERSET_H) */ - diff --git a/src/feature/nodelist/routerstatus_st.h b/src/feature/nodelist/routerstatus_st.h new file mode 100644 index 0000000000..714aa27435 --- /dev/null +++ b/src/feature/nodelist/routerstatus_st.h @@ -0,0 +1,80 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef ROUTERSTATUS_ST_H +#define ROUTERSTATUS_ST_H + +#include "feature/dirclient/download_status_st.h" + +/** Contents of a single router entry in a network status object. + */ +struct routerstatus_t { + time_t published_on; /**< When was this router published? */ + char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it + * has. */ + char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity + * key. */ + /** Digest of the router's most recent descriptor or microdescriptor. + * If it's a descriptor, we only use the first DIGEST_LEN bytes. */ + char descriptor_digest[DIGEST256_LEN]; + uint32_t addr; /**< IPv4 address for this router, in host order. */ + uint16_t or_port; /**< IPv4 OR port for this router. */ + uint16_t dir_port; /**< Directory port for this router. */ + tor_addr_t ipv6_addr; /**< IPv6 address for this router. */ + uint16_t ipv6_orport; /**< IPv6 OR port for this router. */ + unsigned int is_authority:1; /**< True iff this router is an authority. */ + unsigned int is_exit:1; /**< True iff this router is a good exit. */ + unsigned int is_stable:1; /**< True iff this router stays up a long time. */ + unsigned int is_fast:1; /**< True iff this router has good bandwidth. */ + /** True iff this router is called 'running' in the consensus. We give it + * this funny name so that we don't accidentally use this bit as a view of + * whether we think the router is *currently* running. If that's what you + * want to know, look at is_running in node_t. */ + unsigned int is_flagged_running:1; + unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */ + unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another + * router. */ + unsigned int is_valid:1; /**< True iff this router isn't invalid. */ + unsigned int is_possible_guard:1; /**< True iff this router would be a good + * choice as an entry guard. */ + unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for + * an exit node. */ + unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden + * service directory. */ + unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort + * or it claims to accept tunnelled dir requests. + */ + + unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ + unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ + unsigned int bw_is_unmeasured:1; /**< This is a consensus entry, with + * the Unmeasured flag set. */ + + /** Flags to summarize the protocol versions for this routerstatus_t. */ + protover_summary_flags_t pv; + + uint32_t bandwidth_kb; /**< Bandwidth (capacity) of the router as reported in + * the vote/consensus, in kilobytes/sec. */ + + /** The consensus has guardfraction information for this router. */ + unsigned int has_guardfraction:1; + /** The guardfraction value of this router. */ + uint32_t guardfraction_percentage; + + char *exitsummary; /**< exit policy summary - + * XXX weasel: this probably should not stay a string. */ + + /* ---- The fields below aren't derived from the networkstatus; they + * hold local information only. */ + + time_t last_dir_503_at; /**< When did this router last tell us that it + * was too busy to serve directory info? */ + download_status_t dl_status; + +}; + +#endif + diff --git a/src/feature/nodelist/signed_descriptor_st.h b/src/feature/nodelist/signed_descriptor_st.h new file mode 100644 index 0000000000..bffad62895 --- /dev/null +++ b/src/feature/nodelist/signed_descriptor_st.h @@ -0,0 +1,61 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef SIGNED_DESCRIPTOR_ST_H +#define SIGNED_DESCRIPTOR_ST_H + +#include "feature/dirclient/download_status_st.h" + +/** Information need to cache an onion router's descriptor. */ +struct signed_descriptor_t { + /** Pointer to the raw server descriptor, preceded by annotations. Not + * necessarily NUL-terminated. If saved_location is SAVED_IN_CACHE, this + * pointer is null. */ + char *signed_descriptor_body; + /** Length of the annotations preceding the server descriptor. */ + size_t annotations_len; + /** Length of the server descriptor. */ + size_t signed_descriptor_len; + /** Digest of the server descriptor, computed as specified in + * dir-spec.txt. */ + char signed_descriptor_digest[DIGEST_LEN]; + /** Identity digest of the router. */ + char identity_digest[DIGEST_LEN]; + /** Declared publication time of the descriptor. */ + time_t published_on; + /** For routerdescs only: digest of the corresponding extrainfo. */ + char extra_info_digest[DIGEST_LEN]; + /** For routerdescs only: A SHA256-digest of the extrainfo (if any) */ + char extra_info_digest256[DIGEST256_LEN]; + /** Certificate for ed25519 signing key. */ + struct tor_cert_st *signing_key_cert; + /** For routerdescs only: Status of downloading the corresponding + * extrainfo. */ + download_status_t ei_dl_status; + /** Where is the descriptor saved? */ + saved_location_t saved_location; + /** If saved_location is SAVED_IN_CACHE or SAVED_IN_JOURNAL, the offset of + * this descriptor in the corresponding file. */ + off_t saved_offset; + /** What position is this descriptor within routerlist->routers or + * routerlist->old_routers? -1 for none. */ + int routerlist_index; + /** The valid-until time of the most recent consensus that listed this + * descriptor. 0 for "never listed in a consensus, so far as we know." */ + time_t last_listed_as_valid_until; + /* If true, we do not ever try to save this object in the cache. */ + unsigned int do_not_cache : 1; + /* If true, this item is meant to represent an extrainfo. */ + unsigned int is_extrainfo : 1; + /* If true, we got an extrainfo for this item, and the digest was right, + * but it was incompatible. */ + unsigned int extrainfo_is_bogus : 1; + /* If true, we are willing to transmit this item unencrypted. */ + unsigned int send_unencrypted : 1; +}; + +#endif + diff --git a/src/or/torcert.c b/src/feature/nodelist/torcert.c index 1c5afd965a..172d4f9de3 100644 --- a/src/or/torcert.c +++ b/src/feature/nodelist/torcert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -25,15 +25,16 @@ * that one is authority_cert_t, and it's mostly handled in routerlist.c. */ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "torcert.h" -#include "ed25519_cert.h" -#include "torlog.h" -#include "util.h" -#include "compat.h" -#include "link_handshake.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/nodelist/torcert.h" +#include "trunnel/ed25519_cert.h" +#include "lib/log/torlog.h" +#include "trunnel/link_handshake.h" +#include "lib/tls/tortls.h" + +#include "core/or/or_handshake_certs_st.h" /** Helper for tor_cert_create(): signs any 32 bytes, not just an ed25519 * key. @@ -167,7 +168,7 @@ tor_cert_parse(const uint8_t *encoded, const size_t len) memcpy(cert->signed_key.pubkey, parsed->certified_key, 32); int64_t valid_until_64 = ((int64_t)parsed->exp_field) * 3600; -#if SIZEOF_TIME_T < SIZEOF_INT64_T +#if SIZEOF_TIME_T < 8 if (valid_until_64 > TIME_MAX) valid_until_64 = TIME_MAX - 1; #endif @@ -722,4 +723,3 @@ tor_cert_encode_ed22519(const tor_cert_t *cert, char **cert_str_out) tor_free(ed_cert_b64); return ret; } - diff --git a/src/or/torcert.h b/src/feature/nodelist/torcert.h index 18ca60b5a8..5fa97679df 100644 --- a/src/or/torcert.h +++ b/src/feature/nodelist/torcert.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TORCERT_H_INCLUDED #define TORCERT_H_INCLUDED -#include "crypto_ed25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" #define SIGNED_KEY_TYPE_ED25519 0x01 @@ -49,6 +49,8 @@ typedef struct tor_cert_st { unsigned cert_valid : 1; } tor_cert_t; +struct tor_tls_t; + tor_cert_t *tor_cert_create(const ed25519_keypair_t *signing_key, uint8_t cert_type, const ed25519_public_key_t *signed_key, @@ -90,15 +92,15 @@ void or_handshake_certs_free_(or_handshake_certs_t *certs); FREE_AND_NULL(or_handshake_certs_t, or_handshake_certs_free_, (certs)) int or_handshake_certs_rsa_ok(int severity, or_handshake_certs_t *certs, - tor_tls_t *tls, + struct tor_tls_t *tls, time_t now); int or_handshake_certs_ed25519_ok(int severity, or_handshake_certs_t *certs, - tor_tls_t *tls, + struct tor_tls_t *tls, time_t now); void or_handshake_certs_check_both(int severity, or_handshake_certs_t *certs, - tor_tls_t *tls, + struct tor_tls_t *tls, time_t now, const ed25519_public_key_t **ed_id_out, const common_digests_t **rsa_id_out); @@ -106,4 +108,3 @@ void or_handshake_certs_check_both(int severity, int tor_cert_encode_ed22519(const tor_cert_t *cert, char **cert_str_out); #endif /* !defined(TORCERT_H_INCLUDED) */ - diff --git a/src/feature/nodelist/vote_routerstatus_st.h b/src/feature/nodelist/vote_routerstatus_st.h new file mode 100644 index 0000000000..ad0d35b4e6 --- /dev/null +++ b/src/feature/nodelist/vote_routerstatus_st.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef VOTE_ROUTERSTATUS_ST_H +#define VOTE_ROUTERSTATUS_ST_H + +#include "feature/nodelist/routerstatus_st.h" +#include "lib/defs/x25519_sizes.h" + +/** The claim about a single router, made in a vote. */ +struct vote_routerstatus_t { + routerstatus_t status; /**< Underlying 'status' object for this router. + * Flags are redundant. */ + /** How many known-flags are allowed in a vote? This is the width of + * the flags field of vote_routerstatus_t */ +#define MAX_KNOWN_FLAGS_IN_VOTE 64 + uint64_t flags; /**< Bit-field for all recognized flags; index into + * networkstatus_t.known_flags. */ + char *version; /**< The version that the authority says this router is + * running. */ + char *protocols; /**< The protocols that this authority says this router + * provides. */ + unsigned int has_measured_bw:1; /**< The vote had a measured bw */ + /** True iff the vote included an entry for ed25519 ID, or included + * "id ed25519 none" to indicate that there was no ed25519 ID. */ + unsigned int has_ed25519_listing:1; + /** True if the Ed25519 listing here is the consensus-opinion for the + * Ed25519 listing; false if there was no consensus on Ed25519 key status, + * or if this VRS doesn't reflect it. */ + unsigned int ed25519_reflects_consensus:1; + uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */ + /** The hash or hashes that the authority claims this microdesc has. */ + vote_microdesc_hash_t *microdesc; + /** Ed25519 identity for this router, or zero if it has none. */ + uint8_t ed25519_id[ED25519_PUBKEY_LEN]; +}; + +#endif diff --git a/src/or/dns.c b/src/feature/relay/dns.c index ba734ed900..f4e39dfd3d 100644 --- a/src/or/dns.c +++ b/src/feature/relay/dns.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -49,21 +49,30 @@ #define DNS_PRIVATE -#include "or.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "crypto_rand.h" -#include "dns.h" -#include "main.h" -#include "policies.h" -#include "relay.h" -#include "router.h" +#include "core/or/or.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/relay/dns.h" +#include "core/mainloop/main.h" +#include "core/or/policies.h" +#include "core/or/relay.h" +#include "feature/relay/router.h" #include "ht.h" -#include "sandbox.h" +#include "lib/sandbox/sandbox.h" +#include "lib/evloop/compat_libevent.h" + +#include "core/or/edge_connection_st.h" +#include "core/or/or_circuit_st.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + #include <event2/event.h> #include <event2/dns.h> @@ -2132,4 +2141,3 @@ dns_insert_cache_entry(cached_resolve_t *new_entry) { HT_INSERT(cache_map, &cache_root, new_entry); } - diff --git a/src/or/dns.h b/src/feature/relay/dns.h index 28d9f947b4..69c1764b73 100644 --- a/src/or/dns.h +++ b/src/feature/relay/dns.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -41,7 +41,7 @@ void dns_reset_correctness_checks(void); void dump_dns_mem_usage(int severity); #ifdef DNS_PRIVATE -#include "dns_structs.h" +#include "feature/relay/dns_structs.h" MOCK_DECL(STATIC int,dns_resolve_impl,(edge_connection_t *exitconn, int is_resolve,or_circuit_t *oncirc, char **hostname_out, diff --git a/src/or/dns_structs.h b/src/feature/relay/dns_structs.h index e22f23ac15..28c48ca0bc 100644 --- a/src/or/dns_structs.h +++ b/src/feature/relay/dns_structs.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/ext_orport.c b/src/feature/relay/ext_orport.c index b842442caf..7de57ac65d 100644 --- a/src/or/ext_orport.c +++ b/src/feature/relay/ext_orport.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -17,17 +17,18 @@ */ #define EXT_ORPORT_PRIVATE -#include "or.h" -#include "connection.h" -#include "connection_or.h" -#include "control.h" -#include "config.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "ext_orport.h" -#include "main.h" -#include "proto_ext_or.h" -#include "util.h" +#include "core/or/or.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/relay/ext_orport.h" +#include "core/mainloop/main.h" +#include "core/proto/proto_ext_or.h" + +#include "core/or/or_connection_st.h" /** Allocate and return a structure capable of holding an Extended * ORPort message of body length <b>len</b>. */ diff --git a/src/or/ext_orport.h b/src/feature/relay/ext_orport.h index 09acbc407e..7eebfdb25b 100644 --- a/src/or/ext_orport.h +++ b/src/feature/relay/ext_orport.h @@ -1,12 +1,31 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef EXT_ORPORT_H #define EXT_ORPORT_H +/** States of the Extended ORPort protocol. Be careful before changing + * the numbers: they matter. */ +#define EXT_OR_CONN_STATE_MIN_ 1 +/** Extended ORPort authentication is waiting for the authentication + * type selected by the client. */ +#define EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE 1 +/** Extended ORPort authentication is waiting for the client nonce. */ +#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE 2 +/** Extended ORPort authentication is waiting for the client hash. */ +#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH 3 +#define EXT_OR_CONN_STATE_AUTH_MAX 3 +/** Authentication finished and the Extended ORPort is now accepting + * traffic. */ +#define EXT_OR_CONN_STATE_OPEN 4 +/** Extended ORPort is flushing its last messages and preparing to + * start accepting OR connections. */ +#define EXT_OR_CONN_STATE_FLUSHING 5 +#define EXT_OR_CONN_STATE_MAX_ 5 + int connection_ext_or_start_auth(or_connection_t *or_conn); ext_or_cmd_t *ext_or_cmd_new(uint16_t len); @@ -43,4 +62,3 @@ extern int ext_or_auth_cookie_is_set; #endif /* defined(EXT_ORPORT_PRIVATE) */ #endif /* !defined(EXT_ORPORT_H) */ - diff --git a/src/or/router.c b/src/feature/relay/router.c index 5485ec913e..973d3e1100 100644 --- a/src/or/router.c +++ b/src/feature/relay/router.c @@ -1,43 +1,60 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTER_PRIVATE -#include "or.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "crypto_curve25519.h" -#include "directory.h" -#include "dirserv.h" -#include "dns.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "protover.h" -#include "relay.h" -#include "rephist.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "statefile.h" -#include "torcert.h" -#include "transports.h" -#include "routerset.h" - -#include "dirauth/mode.h" +#include "core/or/or.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/relay/dns.h" +#include "feature/stats/geoip.h" +#include "feature/hibernate/hibernate.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "core/or/protover.h" +#include "core/or/relay.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "app/config/statefile.h" +#include "feature/nodelist/torcert.h" +#include "feature/client/transports.h" +#include "feature/nodelist/routerset.h" + +#include "feature/dirauth/mode.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "core/or/crypt_path_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/dirclient/dir_server_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/extrainfo_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" +#include "app/config/or_state_st.h" +#include "core/or/port_cfg_st.h" +#include "feature/nodelist/routerinfo_st.h" + +#include "lib/osinfo/uname.h" +#include "lib/tls/tortls.h" +#include "lib/encoding/confline.h" +#include "lib/crypt_ops/crypto_format.h" /** * \file router.c @@ -1342,10 +1359,10 @@ router_should_be_dirserver(const or_options_t *options, int dir_port) interval_length = 1; } log_info(LD_GENERAL, "Calculating whether to advertise %s: effective " - "bwrate: %u, AccountingMax: "U64_FORMAT", " + "bwrate: %u, AccountingMax: %"PRIu64", " "accounting interval length %d", dir_port ? "dirport" : "begindir", - effective_bw, U64_PRINTF_ARG(options->AccountingMax), + effective_bw, (options->AccountingMax), interval_length); acc_bytes = options->AccountingMax; diff --git a/src/or/router.h b/src/feature/relay/router.h index 752f2f2dbe..51ac365798 100644 --- a/src/or/router.h +++ b/src/feature/relay/router.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,10 @@ #ifndef TOR_ROUTER_H #define TOR_ROUTER_H -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" + +struct curve25519_keypair_t; +struct ed25519_keypair_t; #define TOR_ROUTERINFO_ERROR_NO_EXT_ADDR (-1) #define TOR_ROUTERINFO_ERROR_CANNOT_PARSE (-2) @@ -107,10 +110,10 @@ MOCK_DECL(int,router_pick_published_address,(const or_options_t *options, int router_build_fresh_descriptor(routerinfo_t **r, extrainfo_t **e); int router_rebuild_descriptor(int force); char *router_dump_router_to_string(routerinfo_t *router, - const crypto_pk_t *ident_key, - const crypto_pk_t *tap_key, - const curve25519_keypair_t *ntor_keypair, - const ed25519_keypair_t *signing_keypair); + const crypto_pk_t *ident_key, + const crypto_pk_t *tap_key, + const struct curve25519_keypair_t *ntor_keypair, + const struct ed25519_keypair_t *signing_keypair); char *router_dump_exit_policy_to_string(const routerinfo_t *router, int include_ipv4, int include_ipv6); @@ -126,7 +129,7 @@ int router_has_orport(const routerinfo_t *router, const tor_addr_port_t *orport); int extrainfo_dump_to_string(char **s, extrainfo_t *extrainfo, crypto_pk_t *ident_key, - const ed25519_keypair_t *signing_keypair); + const struct ed25519_keypair_t *signing_keypair); int is_legal_nickname(const char *s); int is_legal_nickname_or_hexdigest(const char *s); int is_legal_hexdigest(const char *s); @@ -156,4 +159,3 @@ STATIC int router_write_fingerprint(int hashed); #endif #endif /* !defined(TOR_ROUTER_H) */ - diff --git a/src/or/routerkeys.c b/src/feature/relay/routerkeys.c index 43460da8cc..f12eb3d332 100644 --- a/src/or/routerkeys.c +++ b/src/feature/relay/routerkeys.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,17 +14,25 @@ * (TODO: The keys in router.c should go here too.) */ -#include "or.h" -#include "config.h" -#include "crypto_util.h" -#include "router.h" -#include "crypto_pwbox.h" -#include "routerkeys.h" -#include "torcert.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/torcert.h" + +#include "lib/crypt_ops/crypto_pwbox.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/term/getpass.h" +#include "lib/tls/tortls.h" +#include "lib/crypt_ops/crypto_format.h" #define ENC_KEY_HEADER "Boxed Ed25519 key" #define ENC_KEY_TAG "master" +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + /* DOCDOC */ static ssize_t do_getpass(const char *prompt, char *buf, size_t buflen, @@ -44,7 +52,7 @@ do_getpass(const char *prompt, char *buf, size_t buflen, if (options->use_keygen_passphrase_fd) { twice = 0; fd = options->keygen_passphrase_fd; - length = read_all(fd, buf, buflen-1, 0); + length = read_all_from_fd(fd, buf, buflen-1); if (length >= 0) buf[length] = 0; goto done_reading; @@ -1403,4 +1411,3 @@ routerkeys_free_all(void) rsa_ed_crosscert = NULL; // redundant rsa_ed_crosscert_len = 0; } - diff --git a/src/or/routerkeys.h b/src/feature/relay/routerkeys.h index 3e67952ea0..a6f06f6e20 100644 --- a/src/or/routerkeys.h +++ b/src/feature/relay/routerkeys.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_ROUTERKEYS_H #define TOR_ROUTERKEYS_H -#include "crypto_ed25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" #define INIT_ED_KEY_CREATE (1u<<0) #define INIT_ED_KEY_REPLACE (1u<<1) diff --git a/src/feature/rend/rend_authorized_client_st.h b/src/feature/rend/rend_authorized_client_st.h new file mode 100644 index 0000000000..7ccf9771e1 --- /dev/null +++ b/src/feature/rend/rend_authorized_client_st.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_AUTHORIZED_CLIENT_ST_H +#define REND_AUTHORIZED_CLIENT_ST_H + +/** Hidden-service side configuration of client authorization. */ +struct rend_authorized_client_t { + char *client_name; + uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; + crypto_pk_t *client_key; +}; + +#endif + diff --git a/src/feature/rend/rend_encoded_v2_service_descriptor_st.h b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h new file mode 100644 index 0000000000..0555ef6728 --- /dev/null +++ b/src/feature/rend/rend_encoded_v2_service_descriptor_st.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H +#define REND_ENCODED_V2_SERVICE_DESCRIPTOR_ST_H + +/** ASCII-encoded v2 hidden service descriptor. */ +struct rend_encoded_v2_service_descriptor_t { + char desc_id[DIGEST_LEN]; /**< Descriptor ID. */ + char *desc_str; /**< Descriptor string. */ +}; + +#endif + diff --git a/src/feature/rend/rend_intro_point_st.h b/src/feature/rend/rend_intro_point_st.h new file mode 100644 index 0000000000..89fe5ef2b3 --- /dev/null +++ b/src/feature/rend/rend_intro_point_st.h @@ -0,0 +1,76 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_INTRO_POINT_ST_H +#define REND_INTRO_POINT_ST_H + +struct replaycache_t; +struct crypto_pk_t; + +/** Introduction point information. Used both in rend_service_t (on + * the service side) and in rend_service_descriptor_t (on both the + * client and service side). */ +struct rend_intro_point_t { + extend_info_t *extend_info; /**< Extend info for connecting to this + * introduction point via a multi-hop path. */ + struct crypto_pk_t *intro_key; /**< Introduction key that replaces the + * service key, if this descriptor is V2. */ + + /** (Client side only) Flag indicating that a timeout has occurred + * after sending an INTRODUCE cell to this intro point. After a + * timeout, an intro point should not be tried again during the same + * hidden service connection attempt, but it may be tried again + * during a future connection attempt. */ + unsigned int timed_out : 1; + + /** (Client side only) The number of times we have failed to build a + * circuit to this intro point for some reason other than our + * circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */ + unsigned int unreachable_count : 3; + + /** (Service side only) Flag indicating that this intro point was + * included in the last HS descriptor we generated. */ + unsigned int listed_in_last_desc : 1; + + /** (Service side only) A replay cache recording the RSA-encrypted parts + * of INTRODUCE2 cells this intro point's circuit has received. This is + * used to prevent replay attacks. */ + struct replaycache_t *accepted_intro_rsa_parts; + + /** (Service side only) Count of INTRODUCE2 cells accepted from this + * intro point. + */ + int accepted_introduce2_count; + + /** (Service side only) Maximum number of INTRODUCE2 cells that this IP + * will accept. This is a random value between + * INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS and + * INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS. */ + int max_introductions; + + /** (Service side only) The time at which this intro point was first + * published, or -1 if this intro point has not yet been + * published. */ + time_t time_published; + + /** (Service side only) The time at which this intro point should + * (start to) expire, or -1 if we haven't decided when this intro + * point should expire. */ + time_t time_to_expire; + + /** (Service side only) The amount of circuit creation we've made to this + * intro point. This is incremented every time we do a circuit relaunch on + * this object which is triggered when the circuit dies but the node is + * still in the consensus. After MAX_INTRO_POINT_CIRCUIT_RETRIES, we give + * up on it. */ + unsigned int circuit_retries; + + /** (Service side only) Set if this intro point has an established circuit + * and unset if it doesn't. */ + unsigned int circuit_established:1; +}; + +#endif diff --git a/src/feature/rend/rend_service_descriptor_st.h b/src/feature/rend/rend_service_descriptor_st.h new file mode 100644 index 0000000000..8ea8a62305 --- /dev/null +++ b/src/feature/rend/rend_service_descriptor_st.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef REND_SERVICE_DESCRIPTOR_ST_H +#define REND_SERVICE_DESCRIPTOR_ST_H + +#define REND_PROTOCOL_VERSION_BITMASK_WIDTH 16 + +/** Information used to connect to a hidden service. Used on both the + * service side and the client side. */ +struct rend_service_descriptor_t { + crypto_pk_t *pk; /**< This service's public key. */ + int version; /**< Version of the descriptor format: 0 or 2. */ + time_t timestamp; /**< Time when the descriptor was generated. */ + /** Bitmask: which introduce/rendezvous protocols are supported? + * (We allow bits '0', '1', '2' and '3' to be set.) */ + unsigned protocols : REND_PROTOCOL_VERSION_BITMASK_WIDTH; + /** List of the service's introduction points. Elements are removed if + * introduction attempts fail. */ + smartlist_t *intro_nodes; + /** Has descriptor been uploaded to all hidden service directories? */ + int all_uploads_performed; + /** List of hidden service directories to which an upload request for + * this descriptor could be sent. Smartlist exists only when at least one + * of the previous upload requests failed (otherwise it's not important + * to know which uploads succeeded and which not). */ + smartlist_t *successful_uploads; +}; + +#endif + diff --git a/src/or/rendcache.c b/src/feature/rend/rendcache.c index d27e1c293f..7af5063ba5 100644 --- a/src/or/rendcache.c +++ b/src/feature/rend/rendcache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,13 +7,17 @@ **/ #define RENDCACHE_PRIVATE -#include "rendcache.h" +#include "feature/rend/rendcache.h" -#include "config.h" -#include "rephist.h" -#include "routerlist.h" -#include "routerparse.h" -#include "rendcommon.h" +#include "app/config/config.h" +#include "feature/stats/rephist.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/rend/rendcommon.h" + +#include "core/or/extend_info_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" /** Map from service id (as generated by rend_get_service_id) to * rend_cache_entry_t. */ @@ -908,9 +912,7 @@ rend_cache_store_v2_desc_as_client(const char *desc, if (n_intro_points <= 0) { log_warn(LD_REND, "Failed to parse introduction points. Either the " "service has published a corrupt descriptor or you have " - "provided invalid authorization data, or (maybe!) the " - "server is deliberately serving broken data in an attempt " - "to crash you with bug 21018."); + "provided invalid authorization data."); goto err; } else if (n_intro_points > MAX_INTRO_POINTS) { log_warn(LD_REND, "Found too many introduction points on a hidden " diff --git a/src/or/rendcache.h b/src/feature/rend/rendcache.h index 8b6fd5b671..455e51645c 100644 --- a/src/or/rendcache.h +++ b/src/feature/rend/rendcache.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_RENDCACHE_H #define TOR_RENDCACHE_H -#include "or.h" -#include "rendcommon.h" +#include "core/or/or.h" +#include "feature/rend/rendcommon.h" /** How old do we let hidden service descriptors get before discarding * them as too old? */ diff --git a/src/or/rendclient.c b/src/feature/rend/rendclient.c index 7ef12a4faf..9f62156eb9 100644 --- a/src/or/rendclient.c +++ b/src/feature/rend/rendclient.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,31 +7,43 @@ * \brief Client code to access location-hidden services. **/ -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "hs_circuit.h" -#include "hs_client.h" -#include "hs_common.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" +#include "core/or/or.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_common.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/relay.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "lib/encoding/confline.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" +#include "feature/nodelist/routerstatus_st.h" static extend_info_t *rend_client_get_random_intro_impl( const rend_cache_entry_t *rend_query, @@ -248,7 +260,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, } if (crypto_dh_get_public(cpath->rend_dh_handshake_state, tmp+dh_offset, - DH_KEY_LEN)<0) { + DH1024_KEY_LEN)<0) { log_warn(LD_BUG, "Internal error: couldn't extract g^x."); status = -2; goto perm_err; @@ -259,7 +271,7 @@ rend_client_send_introduction(origin_circuit_t *introcirc, r = crypto_pk_obsolete_public_hybrid_encrypt(intro_key, payload+DIGEST_LEN, sizeof(payload)-DIGEST_LEN, tmp, - (int)(dh_offset+DH_KEY_LEN), + (int)(dh_offset+DH1024_KEY_LEN), PK_PKCS1_OAEP_PADDING, 0); if (r<0) { log_warn(LD_BUG,"Internal error: hybrid pk encrypt failed."); @@ -864,7 +876,7 @@ int rend_client_receive_rendezvous(origin_circuit_t *circ, const uint8_t *request, size_t request_len) { - if (request_len != DH_KEY_LEN+DIGEST_LEN) { + if (request_len != DH1024_KEY_LEN+DIGEST_LEN) { log_warn(LD_PROTOCOL,"Incorrect length (%d) on RENDEZVOUS2 cell.", (int)request_len); goto err; @@ -1243,4 +1255,3 @@ rend_client_non_anonymous_mode_enabled(const or_options_t *options) return 0; #endif /* defined(NON_ANONYMOUS_MODE_ENABLED) */ } - diff --git a/src/or/rendclient.h b/src/feature/rend/rendclient.h index e8495ce09c..e41faa4932 100644 --- a/src/or/rendclient.h +++ b/src/feature/rend/rendclient.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #ifndef TOR_RENDCLIENT_H #define TOR_RENDCLIENT_H -#include "rendcache.h" +#include "feature/rend/rendcache.h" void rend_client_purge_state(void); diff --git a/src/or/rendcommon.c b/src/feature/rend/rendcommon.c index f3fa2f64d1..5bf9477446 100644 --- a/src/or/rendcommon.c +++ b/src/feature/rend/rendcommon.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,25 +10,37 @@ #define RENDCOMMON_PRIVATE -#include "or.h" -#include "circuitbuild.h" -#include "circuituse.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "hs_client.h" -#include "hs_common.h" -#include "hs_intropoint.h" -#include "networkstatus.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendmid.h" -#include "rendservice.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" -#include "routerparse.h" +#include "core/or/or.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_intropoint.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendmid.h" +#include "feature/rend/rendservice.h" +#include "feature/stats/rephist.h" +#include "feature/hs_common/replaycache.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" +#include "feature/nodelist/routerstatus_st.h" /** Return 0 if one and two are the same service ids, else -1 or 1 */ int @@ -1042,4 +1054,3 @@ rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc, match: return 1; } - diff --git a/src/or/rendcommon.h b/src/feature/rend/rendcommon.h index 1ed0f62609..4ea35f88c2 100644 --- a/src/or/rendcommon.h +++ b/src/feature/rend/rendcommon.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/rendmid.c b/src/feature/rend/rendmid.c index c4a34ca62c..22cd6c3435 100644 --- a/src/or/rendmid.c +++ b/src/feature/rend/rendmid.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,18 +7,20 @@ * \brief Implement introductions points and rendezvous points. **/ -#include "or.h" -#include "channel.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "crypto.h" -#include "dos.h" -#include "relay.h" -#include "rendmid.h" -#include "rephist.h" -#include "hs_circuitmap.h" -#include "hs_intropoint.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto.h" +#include "core/or/dos.h" +#include "core/or/relay.h" +#include "feature/rend/rendmid.h" +#include "feature/stats/rephist.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_intropoint.h" + +#include "core/or/or_circuit_st.h" /** Respond to an ESTABLISH_INTRO cell by checking the signed data and * setting the circuit's purpose and service pk digest. @@ -155,7 +157,8 @@ rend_mid_introduce_legacy(or_circuit_t *circ, const uint8_t *request, * to revise this protocol anyway. */ if (request_len < (DIGEST_LEN+(MAX_NICKNAME_LEN+1)+REND_COOKIE_LEN+ - DH_KEY_LEN+CIPHER_KEY_LEN+PKCS1_OAEP_PADDING_OVERHEAD)) { + DH1024_KEY_LEN+CIPHER_KEY_LEN+ + PKCS1_OAEP_PADDING_OVERHEAD)) { log_warn(LD_PROTOCOL, "Impossibly short INTRODUCE1 cell on circuit %u; " "responding with nack.", (unsigned)circ->p_circ_id); @@ -365,4 +368,3 @@ rend_mid_rendezvous(or_circuit_t *circ, const uint8_t *request, circuit_mark_for_close(TO_CIRCUIT(circ), reason); return -1; } - diff --git a/src/or/rendmid.h b/src/feature/rend/rendmid.h index 6cc1fc8d95..907a0c6a73 100644 --- a/src/or/rendmid.h +++ b/src/feature/rend/rendmid.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/or/rendservice.c b/src/feature/rend/rendservice.c index 92c323b10d..da4a98b3d1 100644 --- a/src/or/rendservice.c +++ b/src/feature/rend/rendservice.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,32 +9,57 @@ #define RENDSERVICE_PRIVATE -#include "or.h" -#include "circpathbias.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "directory.h" -#include "hs_common.h" -#include "hs_config.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "rendclient.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "router.h" -#include "relay.h" -#include "rephist.h" -#include "replaycache.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" +#include "core/or/or.h" +#include "feature/client/circpathbias.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "feature/dircache/directory.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_config.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/relay/router.h" +#include "core/or/relay.h" +#include "feature/stats/rephist.h" +#include "feature/hs_common/replaycache.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "lib/encoding/confline.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/crypt_path_reference_st.h" +#include "core/or/edge_connection_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/rend/rend_authorized_client_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif struct rend_service_t; static origin_circuit_t *find_intro_circuit(rend_intro_point_t *intro, @@ -1992,7 +2017,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, * part 1. */ replay = replaycache_add_test_and_elapsed( service->accepted_intro_dh_parts, - parsed_req->dh, DH_KEY_LEN, + parsed_req->dh, DH1024_KEY_LEN, &elapsed); if (replay) { @@ -2042,7 +2067,7 @@ rend_service_receive_introduction(origin_circuit_t *circuit, } if (crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh, (char *)(parsed_req->dh), - DH_KEY_LEN, keys, + DH1024_KEY_LEN, keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN)<0) { log_warn(LD_BUG, "Internal error: couldn't complete DH handshake"); reason = END_CIRC_REASON_INTERNAL; @@ -2323,7 +2348,7 @@ rend_service_begin_parse_intro(const uint8_t *request, /* min key length plus digest length plus nickname length */ if (request_len < (DIGEST_LEN + REND_COOKIE_LEN + (MAX_NICKNAME_LEN + 1) + - DH_KEY_LEN + 42)) { + DH1024_KEY_LEN + 42)) { if (err_msg_out) { tor_asprintf(&err_msg, "got a truncated INTRODUCE%d cell", @@ -2859,14 +2884,14 @@ rend_service_parse_intro_plaintext( */ ver_invariant_len = intro->plaintext_len - ver_specific_len; - if (ver_invariant_len < REND_COOKIE_LEN + DH_KEY_LEN) { + if (ver_invariant_len < REND_COOKIE_LEN + DH1024_KEY_LEN) { tor_asprintf(&err_msg, "decrypted plaintext of INTRODUCE%d cell was truncated (%ld bytes)", (int)(intro->type), (long)(intro->plaintext_len)); status = -5; goto err; - } else if (ver_invariant_len > REND_COOKIE_LEN + DH_KEY_LEN) { + } else if (ver_invariant_len > REND_COOKIE_LEN + DH1024_KEY_LEN) { tor_asprintf(&err_msg, "decrypted plaintext of INTRODUCE%d cell was too long (%ld bytes)", (int)(intro->type), @@ -2879,7 +2904,7 @@ rend_service_parse_intro_plaintext( REND_COOKIE_LEN); memcpy(intro->dh, intro->plaintext + ver_specific_len + REND_COOKIE_LEN, - DH_KEY_LEN); + DH1024_KEY_LEN); } /* Flag it as being fully parsed */ @@ -3436,12 +3461,12 @@ rend_service_rendezvous_has_opened(origin_circuit_t *circuit) /* All we need to do is send a RELAY_RENDEZVOUS1 cell... */ memcpy(buf, rend_cookie, REND_COOKIE_LEN); if (crypto_dh_get_public(hop->rend_dh_handshake_state, - buf+REND_COOKIE_LEN, DH_KEY_LEN)<0) { + buf+REND_COOKIE_LEN, DH1024_KEY_LEN)<0) { log_warn(LD_GENERAL,"Couldn't get DH public key."); reason = END_CIRC_REASON_INTERNAL; goto err; } - memcpy(buf+REND_COOKIE_LEN+DH_KEY_LEN, hop->rend_circ_nonce, + memcpy(buf+REND_COOKIE_LEN+DH1024_KEY_LEN, hop->rend_circ_nonce, DIGEST_LEN); /* Send the cell */ @@ -4424,4 +4449,3 @@ set_rend_rend_service_staging_list(smartlist_t *new_list) } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/or/rendservice.h b/src/feature/rend/rendservice.h index cc872ab575..7096789629 100644 --- a/src/or/rendservice.h +++ b/src/feature/rend/rendservice.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,14 +12,15 @@ #ifndef TOR_RENDSERVICE_H #define TOR_RENDSERVICE_H -#include "or.h" -#include "hs_service.h" +#include "core/or/or.h" +#include "feature/hs/hs_service.h" -typedef struct rend_intro_cell_s rend_intro_cell_t; +typedef struct rend_intro_cell_t rend_intro_cell_t; +struct config_line_t; /* This can be used for both INTRODUCE1 and INTRODUCE2 */ -struct rend_intro_cell_s { +struct rend_intro_cell_t { /* Is this an INTRODUCE1 or INTRODUCE2? (set to 1 or 2) */ uint8_t type; /* Public key digest */ @@ -58,7 +59,7 @@ struct rend_intro_cell_s { /* Rendezvous cookie */ uint8_t rc[REND_COOKIE_LEN]; /* Diffie-Hellman data */ - uint8_t dh[DH_KEY_LEN]; + uint8_t dh[DH1024_KEY_LEN]; }; #ifdef RENDSERVICE_PRIVATE @@ -138,7 +139,7 @@ STATIC void rend_service_prune_list_impl_(void); #endif /* defined(RENDSERVICE_PRIVATE) */ int rend_num_services(void); -int rend_config_service(const config_line_t *line_, +int rend_config_service(const struct config_line_t *line_, const or_options_t *options, hs_service_config_t *config); void rend_service_prune_list(void); @@ -218,4 +219,3 @@ int rend_service_reveal_startup_time(const or_options_t *options); int rend_service_non_anonymous_mode_enabled(const or_options_t *options); #endif /* !defined(TOR_RENDSERVICE_H) */ - diff --git a/src/or/geoip.c b/src/feature/stats/geoip.c index d59043a7f6..d891bd80e2 100644 --- a/src/or/geoip.c +++ b/src/feature/stats/geoip.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -28,15 +28,18 @@ */ #define GEOIP_PRIVATE -#include "or.h" +#include "core/or/or.h" #include "ht.h" -#include "buffers.h" -#include "config.h" -#include "control.h" -#include "dnsserv.h" -#include "dos.h" -#include "geoip.h" -#include "routerlist.h" +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "feature/client/dnsserv.h" +#include "core/or/dos.h" +#include "feature/stats/geoip.h" +#include "feature/nodelist/routerlist.h" + +#include "lib/container/order.h" +#include "lib/time/tvdiff.h" static void init_geoip_countries(void); @@ -1037,12 +1040,12 @@ geoip_get_transport_history(void) void *transport_count_ptr = strmap_get(transport_counts, transport_name); uintptr_t transport_count = (uintptr_t) transport_count_ptr; - log_debug(LD_GENERAL, "We got "U64_FORMAT" clients with transport '%s'.", - U64_PRINTF_ARG((uint64_t)transport_count), transport_name); + log_debug(LD_GENERAL, "We got %"PRIu64" clients with transport '%s'.", + ((uint64_t)transport_count), transport_name); - smartlist_add_asprintf(string_chunks, "%s="U64_FORMAT, + smartlist_add_asprintf(string_chunks, "%s=%"PRIu64, transport_name, - U64_PRINTF_ARG(round_uint64_to_next_multiple_of( + (round_uint64_to_next_multiple_of( (uint64_t)transport_count, granularity))); } SMARTLIST_FOREACH_END(transport_name); @@ -1884,4 +1887,3 @@ geoip_free_all(void) memset(geoip_digest, 0, sizeof(geoip_digest)); memset(geoip6_digest, 0, sizeof(geoip6_digest)); } - diff --git a/src/or/geoip.h b/src/feature/stats/geoip.h index 753bdbf82a..a2175c01e5 100644 --- a/src/or/geoip.h +++ b/src/feature/stats/geoip.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,66 @@ #ifndef TOR_GEOIP_H #define TOR_GEOIP_H -#include "testsupport.h" -#include "dos.h" +#include "lib/testsupport/testsupport.h" +#include "core/or/dos.h" + +/** Indicates an action that we might be noting geoip statistics on. + * Note that if we're noticing CONNECT, we're a bridge, and if we're noticing + * the others, we're not. + */ +typedef enum { + /** We've noticed a connection as a bridge relay or entry guard. */ + GEOIP_CLIENT_CONNECT = 0, + /** We've served a networkstatus consensus as a directory server. */ + GEOIP_CLIENT_NETWORKSTATUS = 1, +} geoip_client_action_t; +/** Indicates either a positive reply or a reason for rejectng a network + * status request that will be included in geoip statistics. */ +typedef enum { + /** Request is answered successfully. */ + GEOIP_SUCCESS = 0, + /** V3 network status is not signed by a sufficient number of requested + * authorities. */ + GEOIP_REJECT_NOT_ENOUGH_SIGS = 1, + /** Requested network status object is unavailable. */ + GEOIP_REJECT_UNAVAILABLE = 2, + /** Requested network status not found. */ + GEOIP_REJECT_NOT_FOUND = 3, + /** Network status has not been modified since If-Modified-Since time. */ + GEOIP_REJECT_NOT_MODIFIED = 4, + /** Directory is busy. */ + GEOIP_REJECT_BUSY = 5, +} geoip_ns_response_t; +#define GEOIP_NS_RESPONSE_NUM 6 + +/** Directory requests that we are measuring can be either direct or + * tunneled. */ +typedef enum { + DIRREQ_DIRECT = 0, + DIRREQ_TUNNELED = 1, +} dirreq_type_t; + +/** Possible states for either direct or tunneled directory requests that + * are relevant for determining network status download times. */ +typedef enum { + /** Found that the client requests a network status; applies to both + * direct and tunneled requests; initial state of a request that we are + * measuring. */ + DIRREQ_IS_FOR_NETWORK_STATUS = 0, + /** Finished writing a network status to the directory connection; + * applies to both direct and tunneled requests; completes a direct + * request. */ + DIRREQ_FLUSHING_DIR_CONN_FINISHED = 1, + /** END cell sent to circuit that initiated a tunneled request. */ + DIRREQ_END_CELL_SENT = 2, + /** Flushed last cell from queue of the circuit that initiated a + * tunneled request to the outbuf of the OR connection. */ + DIRREQ_CIRC_QUEUE_FLUSHED = 3, + /** Flushed last byte from buffer of the channel belonging to the + * circuit that initiated a tunneled request; completes a tunneled + * request. */ + DIRREQ_CHANNEL_BUFFER_FLUSHED = 4 +} dirreq_state_t; #ifdef GEOIP_PRIVATE STATIC int geoip_parse_entry(const char *line, sa_family_t family); @@ -97,4 +155,3 @@ char *geoip_get_bridge_stats_controller(time_t); char *format_client_stats_heartbeat(time_t now); #endif /* !defined(TOR_GEOIP_H) */ - diff --git a/src/or/rephist.c b/src/feature/stats/rephist.c index c7117bad63..6bb680c5dc 100644 --- a/src/or/rephist.c +++ b/src/feature/stats/rephist.c @@ -1,5 +1,5 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -74,20 +74,33 @@ * (The "rephist" name originally stood for "reputation and history". ) **/ -#include "or.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "config.h" -#include "crypto_rand.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "rephist.h" -#include "router.h" -#include "routerlist.h" +#include "core/or/or.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/stats/rephist.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" #include "ht.h" -#include "channelpadding.h" -#include "connection_or.h" -#include "statefile.h" +#include "core/or/channelpadding.h" +#include "core/or/connection_or.h" +#include "app/config/statefile.h" + +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/or_circuit_st.h" +#include "app/config/or_state_st.h" + +#include "lib/container/bloomfilt.h" +#include "lib/container/order.h" +#include "lib/math/fp.h" +#include "lib/math/laplace.h" + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif static void bw_arrays_init(void); static void predicted_ports_alloc(void); @@ -1210,9 +1223,9 @@ rep_hist_bandwidth_assess(void) r = find_largest_max(read_array); w = find_largest_max(write_array); if (r>w) - return (int)(U64_TO_DBL(w)/NUM_SECS_ROLLING_MEASURE); + return (int)(((double)w)/NUM_SECS_ROLLING_MEASURE); else - return (int)(U64_TO_DBL(r)/NUM_SECS_ROLLING_MEASURE); + return (int)(((double)r)/NUM_SECS_ROLLING_MEASURE); } /** Print the bandwidth history of b (either [dir-]read_array or @@ -1258,9 +1271,9 @@ rep_hist_fill_bandwidth_history(char *buf, size_t len, const bw_array_t *b) total = cutoff; if (n==(b->num_maxes_set-1)) - tor_snprintf(cp, len-(cp-buf), U64_FORMAT, U64_PRINTF_ARG(total)); + tor_snprintf(cp, len-(cp-buf), "%"PRIu64, (total)); else - tor_snprintf(cp, len-(cp-buf), U64_FORMAT",", U64_PRINTF_ARG(total)); + tor_snprintf(cp, len-(cp-buf), "%"PRIu64",", (total)); cp += strlen(cp); } return cp-buf; @@ -1372,17 +1385,17 @@ rep_hist_update_bwhist_state_section(or_state_t *state, for (j=0; j < b->num_maxes_set; ++j,++i) { if (i >= NUM_TOTALS) i = 0; - smartlist_add_asprintf(*s_values, U64_FORMAT, - U64_PRINTF_ARG(b->totals[i] & ~0x3ff)); + smartlist_add_asprintf(*s_values, "%"PRIu64, + (b->totals[i] & ~0x3ff)); maxval = b->maxima[i] / NUM_SECS_ROLLING_MEASURE; - smartlist_add_asprintf(*s_maxima, U64_FORMAT, - U64_PRINTF_ARG(maxval & ~0x3ff)); + smartlist_add_asprintf(*s_maxima, "%"PRIu64, + (maxval & ~0x3ff)); } - smartlist_add_asprintf(*s_values, U64_FORMAT, - U64_PRINTF_ARG(b->total_in_period & ~0x3ff)); + smartlist_add_asprintf(*s_values, "%"PRIu64, + (b->total_in_period & ~0x3ff)); maxval = b->max_total / NUM_SECS_ROLLING_MEASURE; - smartlist_add_asprintf(*s_maxima, U64_FORMAT, - U64_PRINTF_ARG(maxval & ~0x3ff)); + smartlist_add_asprintf(*s_maxima, "%"PRIu64, + (maxval & ~0x3ff)); } /** Update <b>state</b> with the newest bandwidth history. Done before @@ -1956,8 +1969,8 @@ rep_hist_format_exit_stats(time_t now) exit_bytes_written[cur_port], EXIT_STATS_ROUND_UP_BYTES); num /= 1024; - smartlist_add_asprintf(written_strings, "%d="U64_FORMAT, - cur_port, U64_PRINTF_ARG(num)); + smartlist_add_asprintf(written_strings, "%d=%"PRIu64, + cur_port, (num)); other_written -= exit_bytes_written[cur_port]; } if (exit_bytes_read[cur_port] > 0) { @@ -1965,8 +1978,8 @@ rep_hist_format_exit_stats(time_t now) exit_bytes_read[cur_port], EXIT_STATS_ROUND_UP_BYTES); num /= 1024; - smartlist_add_asprintf(read_strings, "%d="U64_FORMAT, - cur_port, U64_PRINTF_ARG(num)); + smartlist_add_asprintf(read_strings, "%d=%"PRIu64, + cur_port, (num)); other_read -= exit_bytes_read[cur_port]; } if (exit_streams[cur_port] > 0) { @@ -1982,13 +1995,13 @@ rep_hist_format_exit_stats(time_t now) other_written = round_uint64_to_next_multiple_of(other_written, EXIT_STATS_ROUND_UP_BYTES); other_written /= 1024; - smartlist_add_asprintf(written_strings, "other="U64_FORMAT, - U64_PRINTF_ARG(other_written)); + smartlist_add_asprintf(written_strings, "other=%"PRIu64, + (other_written)); other_read = round_uint64_to_next_multiple_of(other_read, EXIT_STATS_ROUND_UP_BYTES); other_read /= 1024; - smartlist_add_asprintf(read_strings, "other="U64_FORMAT, - U64_PRINTF_ARG(other_read)); + smartlist_add_asprintf(read_strings, "other=%"PRIu64, + (other_read)); other_streams = round_uint32_to_next_multiple_of(other_streams, EXIT_STATS_ROUND_UP_STREAMS); smartlist_add_asprintf(streams_strings, "other=%u", other_streams); @@ -2248,8 +2261,8 @@ rep_hist_format_buffer_stats(time_t now) time_in_queue_strings = smartlist_new(); for (i = 0; i < SHARES; i++) { smartlist_add_asprintf(processed_cells_strings, - U64_FORMAT, !circs_in_share[i] ? 0 : - U64_PRINTF_ARG(processed_cells[i] / + "%"PRIu64, !circs_in_share[i] ? 0 : + (processed_cells[i] / circs_in_share[i])); } for (i = 0; i < SHARES; i++) { @@ -2916,14 +2929,14 @@ rep_hist_format_hs_stats(time_t now) format_iso_time(t, now); tor_asprintf(&hs_stats_string, "hidserv-stats-end %s (%d s)\n" - "hidserv-rend-relayed-cells "I64_FORMAT" delta_f=%d " + "hidserv-rend-relayed-cells %"PRId64" delta_f=%d " "epsilon=%.2f bin_size=%d\n" - "hidserv-dir-onions-seen "I64_FORMAT" delta_f=%d " + "hidserv-dir-onions-seen %"PRId64" delta_f=%d " "epsilon=%.2f bin_size=%d\n", t, (unsigned) (now - start_of_hs_stats_interval), - I64_PRINTF_ARG(obfuscated_cells_seen), REND_CELLS_DELTA_F, + (obfuscated_cells_seen), REND_CELLS_DELTA_F, REND_CELLS_EPSILON, REND_CELLS_BIN_SIZE, - I64_PRINTF_ARG(obfuscated_onions_seen), + (obfuscated_onions_seen), ONIONS_SEEN_DELTA_F, ONIONS_SEEN_EPSILON, ONIONS_SEEN_BIN_SIZE); @@ -3109,33 +3122,33 @@ rep_hist_get_padding_count_lines(void) } tor_asprintf(&result, "padding-counts %s (%d s)" - " bin-size="U64_FORMAT - " write-drop="U64_FORMAT - " write-pad="U64_FORMAT - " write-total="U64_FORMAT - " read-drop="U64_FORMAT - " read-pad="U64_FORMAT - " read-total="U64_FORMAT - " enabled-read-pad="U64_FORMAT - " enabled-read-total="U64_FORMAT - " enabled-write-pad="U64_FORMAT - " enabled-write-total="U64_FORMAT - " max-chanpad-timers="U64_FORMAT + " bin-size=%"PRIu64 + " write-drop=%"PRIu64 + " write-pad=%"PRIu64 + " write-total=%"PRIu64 + " read-drop=%"PRIu64 + " read-pad=%"PRIu64 + " read-total=%"PRIu64 + " enabled-read-pad=%"PRIu64 + " enabled-read-total=%"PRIu64 + " enabled-write-pad=%"PRIu64 + " enabled-write-total=%"PRIu64 + " max-chanpad-timers=%"PRIu64 "\n", padding_published.first_published_at, REPHIST_CELL_PADDING_COUNTS_INTERVAL, - U64_PRINTF_ARG(ROUND_CELL_COUNTS_TO), - U64_PRINTF_ARG(padding_published.write_drop_cell_count), - U64_PRINTF_ARG(padding_published.write_pad_cell_count), - U64_PRINTF_ARG(padding_published.write_cell_count), - U64_PRINTF_ARG(padding_published.read_drop_cell_count), - U64_PRINTF_ARG(padding_published.read_pad_cell_count), - U64_PRINTF_ARG(padding_published.read_cell_count), - U64_PRINTF_ARG(padding_published.enabled_read_pad_cell_count), - U64_PRINTF_ARG(padding_published.enabled_read_cell_count), - U64_PRINTF_ARG(padding_published.enabled_write_pad_cell_count), - U64_PRINTF_ARG(padding_published.enabled_write_cell_count), - U64_PRINTF_ARG(padding_published.maximum_chanpad_timers) + (uint64_t)ROUND_CELL_COUNTS_TO, + (padding_published.write_drop_cell_count), + (padding_published.write_pad_cell_count), + (padding_published.write_cell_count), + (padding_published.read_drop_cell_count), + (padding_published.read_pad_cell_count), + (padding_published.read_cell_count), + (padding_published.enabled_read_pad_cell_count), + (padding_published.enabled_read_cell_count), + (padding_published.enabled_write_pad_cell_count), + (padding_published.enabled_write_cell_count), + (padding_published.maximum_chanpad_timers) ); return result; @@ -3149,22 +3162,22 @@ rep_hist_log_link_protocol_counts(void) { log_notice(LD_HEARTBEAT, "Since startup, we have initiated " - U64_FORMAT" v1 connections, " - U64_FORMAT" v2 connections, " - U64_FORMAT" v3 connections, and " - U64_FORMAT" v4 connections; and received " - U64_FORMAT" v1 connections, " - U64_FORMAT" v2 connections, " - U64_FORMAT" v3 connections, and " - U64_FORMAT" v4 connections.", - U64_PRINTF_ARG(link_proto_count[1][1]), - U64_PRINTF_ARG(link_proto_count[2][1]), - U64_PRINTF_ARG(link_proto_count[3][1]), - U64_PRINTF_ARG(link_proto_count[4][1]), - U64_PRINTF_ARG(link_proto_count[1][0]), - U64_PRINTF_ARG(link_proto_count[2][0]), - U64_PRINTF_ARG(link_proto_count[3][0]), - U64_PRINTF_ARG(link_proto_count[4][0])); + "%"PRIu64" v1 connections, " + "%"PRIu64" v2 connections, " + "%"PRIu64" v3 connections, and " + "%"PRIu64" v4 connections; and received " + "%"PRIu64" v1 connections, " + "%"PRIu64" v2 connections, " + "%"PRIu64" v3 connections, and " + "%"PRIu64" v4 connections.", + (link_proto_count[1][1]), + (link_proto_count[2][1]), + (link_proto_count[3][1]), + (link_proto_count[4][1]), + (link_proto_count[1][0]), + (link_proto_count[2][0]), + (link_proto_count[3][0]), + (link_proto_count[4][0])); } /** Free all storage held by the OR/link history caches, by the @@ -3205,4 +3218,3 @@ rep_hist_free_all(void) tor_assert_nonfatal(rephist_total_alloc == 0); tor_assert_nonfatal_once(rephist_total_num == 0); } - diff --git a/src/or/rephist.h b/src/feature/stats/rephist.h index 5072721592..06a5e48211 100644 --- a/src/or/rephist.h +++ b/src/feature/stats/rephist.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/include.am b/src/include.am index 90ecf90d45..b5cca7e30a 100644 --- a/src/include.am +++ b/src/include.am @@ -1,11 +1,45 @@ include src/ext/include.am +include src/lib/arch/include.am +include src/lib/err/include.am +include src/lib/cc/include.am +include src/lib/ctime/include.am +include src/lib/compress/include.am +include src/lib/container/include.am +include src/lib/crypt_ops/include.am +include src/lib/defs/include.am +include src/lib/encoding/include.am +include src/lib/evloop/include.am +include src/lib/fdio/include.am +include src/lib/fs/include.am +include src/lib/include.libdonna.am +include src/lib/intmath/include.am +include src/lib/lock/include.am +include src/lib/log/include.am +include src/lib/math/include.am +include src/lib/memarea/include.am +include src/lib/meminfo/include.am +include src/lib/malloc/include.am +include src/lib/net/include.am +include src/lib/osinfo/include.am +include src/lib/process/include.am +include src/lib/sandbox/include.am +include src/lib/string/include.am +include src/lib/smartlist_core/include.am +include src/lib/term/include.am +include src/lib/testsupport/include.am +include src/lib/thread/include.am +include src/lib/time/include.am +include src/lib/tls/include.am +include src/lib/trace/include.am +include src/lib/wallclock/include.am include src/trunnel/include.am -include src/common/include.am -include src/or/include.am + +include src/core/include.am +include src/app/include.am + include src/rust/include.am include src/test/include.am include src/tools/include.am include src/win32/include.am include src/config/include.am include src/test/fuzz/include.am -include src/trace/include.am diff --git a/src/lib/arch/.may_include b/src/lib/arch/.may_include new file mode 100644 index 0000000000..4285c3dcb8 --- /dev/null +++ b/src/lib/arch/.may_include @@ -0,0 +1,2 @@ +orconfig.h +lib/cc/*.h diff --git a/src/lib/arch/bytes.h b/src/lib/arch/bytes.h new file mode 100644 index 0000000000..a2e2224d3c --- /dev/null +++ b/src/lib/arch/bytes.h @@ -0,0 +1,182 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_BYTES_H +#define TOR_BYTES_H + +/** + * \file bytes.h + * + * \brief Inline functions for reading and writing multibyte values from + * the middle of strings, and for manipulating byte order. + **/ + +#include <string.h> +#include "lib/cc/torint.h" + +/* The uint8 variants are defined to make the code more uniform. */ +static inline uint8_t +get_uint8(const void *cp) +{ + return *(const uint8_t*)(cp); +} +static inline void +set_uint8(void *cp, uint8_t v) +{ + *(uint8_t*)cp = v; +} + +/** + * Read a 16-bit value beginning at <b>cp</b>. Equivalent to + * *(uint16_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +static inline uint16_t +get_uint16(const void *cp) +{ + uint16_t v; + memcpy(&v,cp,2); + return v; +} +/** + * Read a 32-bit value beginning at <b>cp</b>. Equivalent to + * *(uint32_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +static inline uint32_t +get_uint32(const void *cp) +{ + uint32_t v; + memcpy(&v,cp,4); + return v; +} +/** + * Read a 64-bit value beginning at <b>cp</b>. Equivalent to + * *(uint64_t*)(cp), but will not cause segfaults on platforms that forbid + * unaligned memory access. + */ +static inline uint64_t +get_uint64(const void *cp) +{ + uint64_t v; + memcpy(&v,cp,8); + return v; +} + +/** + * Set a 16-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to + * *(uint16_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +static inline void +set_uint16(void *cp, uint16_t v) +{ + memcpy(cp,&v,2); +} +/** + * Set a 32-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to + * *(uint32_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +static inline void +set_uint32(void *cp, uint32_t v) +{ + memcpy(cp,&v,4); +} +/** + * Set a 64-bit value beginning at <b>cp</b> to <b>v</b>. Equivalent to + * *(uint64_t*)(cp) = v, but will not cause segfaults on platforms that forbid + * unaligned memory access. */ +static inline void +set_uint64(void *cp, uint64_t v) +{ + memcpy(cp,&v,8); +} + +#ifdef WORDS_BIGENDIAN +static inline uint16_t +tor_htons(uint32_t a) +{ + return a; +} + +static inline uint16_t +tor_ntohs(uint64_t a) +{ + return a; +} + +static inline uint32_t +tor_htonl(uint32_t a) +{ + return a; +} + +static inline uint32_t +tor_ntohl(uint64_t a) +{ + return a; +} + +static inline uint64_t +tor_htonll(uint64_t a) +{ + return a; +} + +static inline uint64_t +tor_ntohll(uint64_t a) +{ + return a; +} +#else +static inline uint16_t +tor_htons(uint16_t a) +{ + /* Our compilers will indeed recognize this as bswap. */ + return + ((a & 0x00ff) << 8) | + ((a & 0xff00) >> 8); +} + +static inline uint16_t +tor_ntohs(uint16_t a) +{ + return tor_htons(a); +} + +static inline uint32_t +tor_htonl(uint32_t a) +{ + /* Our compilers will indeed recognize this as bswap. */ + return + ((a & 0x000000ff) <<24) | + ((a & 0x0000ff00) << 8) | + ((a & 0x00ff0000) >> 8) | + ((a & 0xff000000) >>24); +} + +static inline uint32_t +tor_ntohl(uint32_t a) +{ + return tor_htonl(a); +} + +/** Return a uint64_t value from <b>a</b> in network byte order. */ +static inline uint64_t +tor_htonll(uint64_t a) +{ + /* Little endian. The worst... */ + return tor_htonl((uint32_t)(a>>32)) | + (((uint64_t)tor_htonl((uint32_t)a))<<32); +} + +/** Return a uint64_t value from <b>a</b> in host byte order. */ +static inline uint64_t +tor_ntohll(uint64_t a) +{ + return tor_htonll(a); +} +#endif + +#endif diff --git a/src/lib/arch/include.am b/src/lib/arch/include.am new file mode 100644 index 0000000000..f92ee9222f --- /dev/null +++ b/src/lib/arch/include.am @@ -0,0 +1,3 @@ + +noinst_HEADERS += \ + src/lib/arch/bytes.h diff --git a/src/lib/cc/.may_include b/src/lib/cc/.may_include new file mode 100644 index 0000000000..2b06e8519c --- /dev/null +++ b/src/lib/cc/.may_include @@ -0,0 +1 @@ +orconfig.h diff --git a/src/lib/cc/compat_compiler.h b/src/lib/cc/compat_compiler.h new file mode 100644 index 0000000000..0f1acc381a --- /dev/null +++ b/src/lib/cc/compat_compiler.h @@ -0,0 +1,214 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_COMPILER_H +#define TOR_COMPAT_COMPILER_H + +#include "orconfig.h" +#include <inttypes.h> + +#if defined(__has_feature) +# if __has_feature(address_sanitizer) +/* Some of the fancy glibc strcmp() macros include references to memory that + * clang rejects because it is off the end of a less-than-3. Clang hates this, + * even though those references never actually happen. */ +# undef strcmp +#endif /* __has_feature(address_sanitizer) */ +#endif /* defined(__has_feature) */ + +#ifndef NULL_REP_IS_ZERO_BYTES +#error "It seems your platform does not represent NULL as zero. We can't cope." +#endif + +#ifndef DOUBLE_0_REP_IS_ZERO_BYTES +#error "It seems your platform does not represent 0.0 as zeros. We can't cope." +#endif + +#if 'a'!=97 || 'z'!=122 || 'A'!=65 || ' '!=32 +#error "It seems that you encode characters in something other than ASCII." +#endif + +/* GCC can check printf and scanf types on arbitrary functions. */ +#ifdef __GNUC__ +#define CHECK_PRINTF(formatIdx, firstArg) \ + __attribute__ ((format(printf, formatIdx, firstArg))) +#else +#define CHECK_PRINTF(formatIdx, firstArg) +#endif /* defined(__GNUC__) */ +#ifdef __GNUC__ +#define CHECK_SCANF(formatIdx, firstArg) \ + __attribute__ ((format(scanf, formatIdx, firstArg))) +#else +#define CHECK_SCANF(formatIdx, firstArg) +#endif /* defined(__GNUC__) */ + +/* What GCC do we have? */ +#ifdef __GNUC__ +#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +#define GCC_VERSION 0 +#endif + +/* Temporarily enable and disable warnings. */ +#ifdef __GNUC__ +# define PRAGMA_STRINGIFY_(s) #s +# define PRAGMA_JOIN_STRINGIFY_(a,b) PRAGMA_STRINGIFY_(a ## b) +/* Support for macro-generated pragmas (c99) */ +# define PRAGMA_(x) _Pragma (#x) +# ifdef __clang__ +# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(clang diagnostic x) +# else +# define PRAGMA_DIAGNOSTIC_(x) PRAGMA_(GCC diagnostic x) +# endif +# if defined(__clang__) || GCC_VERSION >= 406 +/* we have push/pop support */ +# define DISABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(push) \ + PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +# define ENABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(pop) +#else /* !(defined(__clang__) || GCC_VERSION >= 406) */ +/* older version of gcc: no push/pop support. */ +# define DISABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(ignored PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +# define ENABLE_GCC_WARNING(warningopt) \ + PRAGMA_DIAGNOSTIC_(warning PRAGMA_JOIN_STRINGIFY_(-W,warningopt)) +#endif /* defined(__clang__) || GCC_VERSION >= 406 */ +#else /* !(defined(__GNUC__)) */ +/* not gcc at all */ +# define DISABLE_GCC_WARNING(warning) +# define ENABLE_GCC_WARNING(warning) +#endif /* defined(__GNUC__) */ + +/* inline is __inline on windows. */ +#ifdef _WIN32 +#define inline __inline +#endif + +/* Try to get a reasonable __func__ substitute in place. */ +#if defined(_MSC_VER) + +#define __func__ __FUNCTION__ + +#else +/* For platforms where autoconf works, make sure __func__ is defined + * sanely. */ +#ifndef HAVE_MACRO__func__ +#ifdef HAVE_MACRO__FUNCTION__ +#define __func__ __FUNCTION__ +#elif HAVE_MACRO__FUNC__ +#define __func__ __FUNC__ +#else +#define __func__ "???" +#endif /* defined(HAVE_MACRO__FUNCTION__) || ... */ +#endif /* !defined(HAVE_MACRO__func__) */ +#endif /* defined(_MSC_VER) */ + +#ifdef ENUM_VALS_ARE_SIGNED +#define ENUM_BF(t) unsigned +#else +/** Wrapper for having a bitfield of an enumerated type. Where possible, we + * just use the enumerated type (so the compiler can help us and notice + * problems), but if enumerated types are unsigned, we must use unsigned, + * so that the loss of precision doesn't make large values negative. */ +#define ENUM_BF(t) t +#endif /* defined(ENUM_VALS_ARE_SIGNED) */ + +/* GCC has several useful attributes. */ +#if defined(__GNUC__) && __GNUC__ >= 3 +#define ATTR_NORETURN __attribute__((noreturn)) +#define ATTR_CONST __attribute__((const)) +#define ATTR_MALLOC __attribute__((malloc)) +#define ATTR_NORETURN __attribute__((noreturn)) +#define ATTR_WUR __attribute__((warn_unused_result)) +#define ATTR_UNUSED __attribute__ ((unused)) + +/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value + * of <b>exp</b> will probably be true. + * + * In other words, "if (PREDICT_LIKELY(foo))" is the same as "if (foo)", + * except that it tells the compiler that the branch will be taken most of the + * time. This can generate slightly better code with some CPUs. + */ +#define PREDICT_LIKELY(exp) __builtin_expect(!!(exp), 1) +/** Macro: Evaluates to <b>exp</b> and hints the compiler that the value + * of <b>exp</b> will probably be false. + * + * In other words, "if (PREDICT_UNLIKELY(foo))" is the same as "if (foo)", + * except that it tells the compiler that the branch will usually not be + * taken. This can generate slightly better code with some CPUs. + */ +#define PREDICT_UNLIKELY(exp) __builtin_expect(!!(exp), 0) +#else /* !(defined(__GNUC__) && __GNUC__ >= 3) */ +#define ATTR_NORETURN +#define ATTR_CONST +#define ATTR_MALLOC +#define ATTR_NORETURN +#define ATTR_UNUSED +#define ATTR_WUR +#define PREDICT_LIKELY(exp) (exp) +#define PREDICT_UNLIKELY(exp) (exp) +#endif /* defined(__GNUC__) && __GNUC__ >= 3 */ + +/** Expands to a syntactically valid empty statement. */ +#define STMT_NIL (void)0 + +/** Expands to a syntactically valid empty statement, explicitly (void)ing its + * argument. */ +#define STMT_VOID(a) while (0) { (void)(a); } + +#ifdef __GNUC__ +/** STMT_BEGIN and STMT_END are used to wrap blocks inside macros so that + * the macro can be used as if it were a single C statement. */ +#define STMT_BEGIN (void) ({ +#define STMT_END }) +#elif defined(sun) || defined(__sun__) +#define STMT_BEGIN if (1) { +#define STMT_END } else STMT_NIL +#else +#define STMT_BEGIN do { +#define STMT_END } while (0) +#endif /* defined(__GNUC__) || ... */ + +/* Some tools (like coccinelle) don't like to see operators as macro + * arguments. */ +#define OP_LT < +#define OP_GT > +#define OP_GE >= +#define OP_LE <= +#define OP_EQ == +#define OP_NE != + +#if defined(__MINGW32__) || defined(__MINGW64__) +#define MINGW_ANY +#endif + +/** Macro: yield a pointer to the field at position <b>off</b> within the + * structure <b>st</b>. Example: + * <pre> + * struct a { int foo; int bar; } x; + * off_t bar_offset = offsetof(struct a, bar); + * int *bar_p = STRUCT_VAR_P(&x, bar_offset); + * *bar_p = 3; + * </pre> + */ +#define STRUCT_VAR_P(st, off) ((void*) ( ((char*)(st)) + (off) ) ) + +/** Macro: yield a pointer to an enclosing structure given a pointer to + * a substructure at offset <b>off</b>. Example: + * <pre> + * struct base { ... }; + * struct subtype { int x; struct base b; } x; + * struct base *bp = &x.base; + * struct *sp = SUBTYPE_P(bp, struct subtype, b); + * </pre> + */ +#define SUBTYPE_P(p, subtype, basemember) \ + ((void*) ( ((char*)(p)) - offsetof(subtype, basemember) )) + +/** Macro: Yields the number of elements in array x. */ +#define ARRAY_LENGTH(x) ((sizeof(x)) / sizeof(x[0])) + +#endif /* !defined(TOR_COMPAT_H) */ diff --git a/src/lib/cc/include.am b/src/lib/cc/include.am new file mode 100644 index 0000000000..2ae90f97dd --- /dev/null +++ b/src/lib/cc/include.am @@ -0,0 +1,4 @@ + +noinst_HEADERS += \ + src/lib/cc/compat_compiler.h \ + src/lib/cc/torint.h diff --git a/src/lib/cc/torint.h b/src/lib/cc/torint.h new file mode 100644 index 0000000000..91db25833b --- /dev/null +++ b/src/lib/cc/torint.h @@ -0,0 +1,123 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file torint.h + * \brief Header file to define uint32_t and friends + **/ + +#ifndef TOR_TORINT_H +#define TOR_TORINT_H + +/** + * \file torint.h + * + * \brief Integer definitions used throughout Tor. + **/ + +#include "orconfig.h" + +#include <stdint.h> +#include <stdbool.h> +#include <limits.h> + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_LIMITS_H +#include <sys/limits.h> +#endif + +#ifndef SIZE_MAX +#if SIZEOF_SIZE_T == 8 +#define SIZE_MAX UINT64_MAX +#elif SIZEOF_SIZE_T == 4 +#define SIZE_MAX UINT32_MAX +#else +#error "Can't define SIZE_MAX" +#endif /* SIZEOF_SIZE_T == 8 || ... */ +#endif /* !defined(SIZE_MAX) */ + +#ifndef HAVE_SSIZE_T +#if SIZEOF_SIZE_T == 8 +typedef int64_t ssize_t; +#elif SIZEOF_SIZE_T == 4 +typedef int32_t ssize_t; +#else +#error "Can't define ssize_t." +#endif /* SIZEOF_SIZE_T == 8 || ... */ +#endif /* !defined(HAVE_SSIZE_T) */ + +/* This assumes a sane (2's-complement) representation. But if you + * aren't 2's complement, and you don't define LONG_MAX, then you're so + * bizarre that I want nothing to do with you. */ +#ifndef USING_TWOS_COMPLEMENT +#error "Seems that your platform doesn't use 2's complement arithmetic. Argh." +#endif + +#ifndef TIME_MAX + +#if (SIZEOF_TIME_T == SIZEOF_INT) +#define TIME_MAX ((time_t)INT_MAX) +#elif (SIZEOF_TIME_T == SIZEOF_LONG) +#define TIME_MAX ((time_t)LONG_MAX) +#elif (SIZEOF_TIME_T == 8) +#define TIME_MAX ((time_t)INT64_MAX) +#else +#error "Can't define TIME_MAX" +#endif /* (SIZEOF_TIME_T == SIZEOF_INT) || ... */ + +#endif /* !defined(TIME_MAX) */ + +#ifndef TIME_MIN + +#if (SIZEOF_TIME_T == SIZEOF_INT) +#define TIME_MIN ((time_t)INT_MIN) +#elif (SIZEOF_TIME_T == SIZEOF_LONG) +#define TIME_MIN ((time_t)LONG_MIN) +#elif (SIZEOF_TIME_T == 8) +#define TIME_MIN ((time_t)INT64_MIN) +#else +#error "Can't define TIME_MIN" +#endif /* (SIZEOF_TIME_T == SIZEOF_INT) || ... */ + +#endif /* !defined(TIME_MIN) */ + +#ifndef SIZE_MAX +#if (SIZEOF_SIZE_T == 4) +#define SIZE_MAX UINT32_MAX +#elif (SIZEOF_SIZE_T == 8) +#define SIZE_MAX UINT64_MAX +#else +#error "Can't define SIZE_MAX" +#endif /* (SIZEOF_SIZE_T == 4) || ... */ +#endif /* !defined(SIZE_MAX) */ + +#ifdef _WIN32 +# ifdef _WIN64 +# define TOR_PRIuSZ PRIu64 +# else +# define TOR_PRIuSZ PRIu32 +# endif +#else +# define TOR_PRIuSZ "zu" +#endif + +#ifndef SSIZE_MAX +#if (SIZEOF_SIZE_T == 4) +#define SSIZE_MAX INT32_MAX +#elif (SIZEOF_SIZE_T == 8) +#define SSIZE_MAX INT64_MAX +#else +#error "Can't define SSIZE_MAX" +#endif /* (SIZEOF_SIZE_T == 4) || ... */ +#endif /* !defined(SSIZE_MAX) */ + +/** Any ssize_t larger than this amount is likely to be an underflow. */ +#define SSIZE_T_CEILING ((ssize_t)(SSIZE_MAX-16)) +/** Any size_t larger than this amount is likely to be an underflow. */ +#define SIZE_T_CEILING ((size_t)(SSIZE_MAX-16)) + +#endif /* !defined(TOR_TORINT_H) */ diff --git a/src/lib/compress/.may_include b/src/lib/compress/.may_include new file mode 100644 index 0000000000..68fe9f1c54 --- /dev/null +++ b/src/lib/compress/.may_include @@ -0,0 +1,12 @@ +orconfig.h +lib/arch/*.h +lib/cc/*.h +lib/compress/*.h +lib/container/*.h +lib/ctime/*.h +lib/intmath/*.h +lib/log/*.h +lib/malloc/*.h +lib/string/*.h +lib/testsupport/*.h +lib/thread/*.h diff --git a/src/common/compress.c b/src/lib/compress/compress.c index cb1549f1aa..e87e788f14 100644 --- a/src/common/compress.c +++ b/src/lib/compress/compress.c @@ -1,32 +1,39 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file compress.c - * \brief Common compression API. + * \brief Common compression API implementation. + * + * This file provides a unified interface to all the compression libraries Tor + * knows how to use. **/ #include "orconfig.h" #include <stdlib.h> #include <stdio.h> -#include <assert.h> #include <string.h> -#include "torint.h" +#include "lib/cc/torint.h" #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_lzma.h" -#include "compress_none.h" -#include "compress_zlib.h" -#include "compress_zstd.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/arch/bytes.h" +#include "lib/ctime/di_ops.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_lzma.h" +#include "lib/compress/compress_none.h" +#include "lib/compress/compress_zlib.h" +#include "lib/compress/compress_zstd.h" +#include "lib/intmath/cmp.h" +#include "lib/malloc/util_malloc.h" +#include "lib/thread/threads.h" /** Total number of bytes allocated for compression state overhead. */ static atomic_counter_t total_compress_allocation; @@ -277,7 +284,7 @@ detect_compression_method(const char *in, size_t in_len) if (in_len > 2 && fast_memeq(in, "\x1f\x8b", 2)) { return GZIP_METHOD; } else if (in_len > 2 && (in[0] & 0x0f) == 8 && - (ntohs(get_uint16(in)) % 31) == 0) { + (tor_ntohs(get_uint16(in)) % 31) == 0) { return ZLIB_METHOD; } else if (in_len > 2 && fast_memeq(in, "\x5d\x00\x00", 3)) { @@ -672,4 +679,3 @@ tor_compress_log_init_warnings(void) { tor_zstd_warn_if_version_mismatched(); } - diff --git a/src/common/compress.h b/src/lib/compress/compress.h index 65d63a4386..4466e27c4d 100644 --- a/src/common/compress.h +++ b/src/lib/compress/compress.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,11 +11,14 @@ #ifndef TOR_COMPRESS_H #define TOR_COMPRESS_H +#include <stddef.h> +#include "lib/testsupport/testsupport.h" + /** Enumeration of what kind of compression to use. Only ZLIB_METHOD and * GZIP_METHOD is guaranteed to be supported by the compress/uncompress * functions here. Call tor_compress_supports_method() to check if a given * compression schema is supported by Tor. */ -typedef enum { +typedef enum compress_method_t { NO_METHOD=0, // This method must be first. GZIP_METHOD=1, ZLIB_METHOD=2, @@ -29,7 +32,7 @@ typedef enum { * BEST_COMPRESSION saves the most bandwidth; LOW_COMPRESSION saves the most * memory. **/ -typedef enum { +typedef enum compression_level_t { BEST_COMPRESSION, HIGH_COMPRESSION, MEDIUM_COMPRESSION, LOW_COMPRESSION } compression_level_t; @@ -89,5 +92,8 @@ size_t tor_compress_state_size(const tor_compress_state_t *state); void tor_compress_init(void); void tor_compress_log_init_warnings(void); -#endif /* !defined(TOR_COMPRESS_H) */ +struct buf_t; +int buf_add_compress(struct buf_t *buf, struct tor_compress_state_t *state, + const char *data, size_t data_len, int done); +#endif /* !defined(TOR_COMPRESS_H) */ diff --git a/src/lib/compress/compress_buf.c b/src/lib/compress/compress_buf.c new file mode 100644 index 0000000000..63ee9e0102 --- /dev/null +++ b/src/lib/compress/compress_buf.c @@ -0,0 +1,83 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compress_buf.c + * + * \brief Working with compressed data in buffers. + **/ + +#define BUFFERS_PRIVATE +#include "lib/cc/compat_compiler.h" +#include "lib/container/buffers.h" +#include "lib/compress/compress.h" +#include "lib/log/util_bug.h" + +#ifdef PARANOIA +/** Helper: If PARANOIA is defined, assert that the buffer in local variable + * <b>buf</b> is well-formed. */ +#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END +#else +#define check() STMT_NIL +#endif /* defined(PARANOIA) */ + +/** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the + * compression state <b>state</b>, appending the result to <b>buf</b>. If + * <b>done</b> is true, flush the data in the state and finish the + * compression/uncompression. Return -1 on failure, 0 on success. */ +int +buf_add_compress(buf_t *buf, tor_compress_state_t *state, + const char *data, size_t data_len, + const int done) +{ + char *next; + size_t old_avail, avail; + int over = 0; + + do { + int need_new_chunk = 0; + if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) { + size_t cap = data_len / 4; + buf_add_chunk_with_capacity(buf, cap, 1); + } + next = CHUNK_WRITE_PTR(buf->tail); + avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail); + switch (tor_compress_process(state, &next, &avail, + &data, &data_len, done)) { + case TOR_COMPRESS_DONE: + over = 1; + break; + case TOR_COMPRESS_ERROR: + return -1; + case TOR_COMPRESS_OK: + if (data_len == 0) { + tor_assert_nonfatal(!done); + over = 1; + } + break; + case TOR_COMPRESS_BUFFER_FULL: + if (avail) { + /* The compression module says we need more room + * (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically, + * whether were going to or not. */ + need_new_chunk = 1; + } + if (data_len == 0 && !done) { + /* We've consumed all the input data, though, so there's no + * point in forging ahead right now. */ + over = 1; + } + break; + } + buf->datalen += old_avail - avail; + buf->tail->datalen += old_avail - avail; + if (need_new_chunk) { + buf_add_chunk_with_capacity(buf, data_len/4, 1); + } + + } while (!over); + check(); + return 0; +} diff --git a/src/common/compress_lzma.c b/src/lib/compress/compress_lzma.c index 051c59ba2d..3b6f91b84b 100644 --- a/src/common/compress_lzma.c +++ b/src/lib/compress/compress_lzma.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,12 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_lzma.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_lzma.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/thread/threads.h" #ifdef HAVE_LZMA #include <lzma.h> @@ -358,4 +360,3 @@ tor_lzma_init(void) { atomic_counter_init(&total_lzma_allocation); } - diff --git a/src/common/compress_lzma.h b/src/lib/compress/compress_lzma.h index 38a447c1f3..9ef3382a25 100644 --- a/src/common/compress_lzma.h +++ b/src/lib/compress/compress_lzma.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/common/compress_none.c b/src/lib/compress/compress_none.c index 34314e4af7..9574c47a7e 100644 --- a/src/common/compress_none.c +++ b/src/lib/compress/compress_none.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,10 +16,12 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_none.h" +#include "lib/log/torlog.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_none.h" +#include "lib/intmath/cmp.h" + +#include <string.h> /** Transfer some bytes using the identity transformation. Read up to * *<b>in_len</b> bytes from *<b>in</b>, and write up to *<b>out_len</b> bytes @@ -50,4 +52,3 @@ tor_cnone_compress_process(char **out, size_t *out_len, return TOR_COMPRESS_BUFFER_FULL; } } - diff --git a/src/common/compress_none.h b/src/lib/compress/compress_none.h index 77c3cef47b..5c395bbb30 100644 --- a/src/common/compress_none.h +++ b/src/lib/compress/compress_none.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/common/compress_zlib.c b/src/lib/compress/compress_zlib.c index 23d71d27be..12e6727dee 100644 --- a/src/common/compress_zlib.c +++ b/src/lib/compress/compress_zlib.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,11 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_zlib.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_zlib.h" +#include "lib/thread/threads.h" /* zlib 1.2.4 and 1.2.5 do some "clever" things with macros. Instead of saying "(defined(FOO) ? FOO : 0)" they like to say "FOO-0", on the theory @@ -301,4 +302,3 @@ tor_zlib_init(void) { atomic_counter_init(&total_zlib_allocation); } - diff --git a/src/common/compress_zlib.h b/src/lib/compress/compress_zlib.h index e3c1a2b339..7af68044de 100644 --- a/src/common/compress_zlib.h +++ b/src/lib/compress/compress_zlib.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/common/compress_zstd.c b/src/lib/compress/compress_zstd.c index 316a3fb417..0a553db55c 100644 --- a/src/common/compress_zstd.c +++ b/src/lib/compress/compress_zstd.c @@ -1,6 +1,6 @@ /* Copyright (c) 2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,10 +13,12 @@ #include "orconfig.h" -#include "util.h" -#include "torlog.h" -#include "compress.h" -#include "compress_zstd.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_zstd.h" +#include "lib/string/printf.h" +#include "lib/thread/threads.h" #ifdef ENABLE_ZSTD_ADVANCED_APIS /* This is a lie, but we make sure it doesn't get us in trouble by wrapping @@ -533,4 +535,3 @@ tor_zstd_set_static_apis_disabled_for_testing(int disabled) static_apis_disable_for_testing = disabled; } #endif - diff --git a/src/common/compress_zstd.h b/src/lib/compress/compress_zstd.h index bd42cf65ce..1177537a9e 100644 --- a/src/common/compress_zstd.h +++ b/src/lib/compress/compress_zstd.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** diff --git a/src/lib/compress/include.am b/src/lib/compress/include.am new file mode 100644 index 0000000000..75c9032bd2 --- /dev/null +++ b/src/lib/compress/include.am @@ -0,0 +1,26 @@ + +noinst_LIBRARIES += src/lib/libtor-compress.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-compress-testing.a +endif + +src_lib_libtor_compress_a_SOURCES = \ + src/lib/compress/compress.c \ + src/lib/compress/compress_buf.c \ + src/lib/compress/compress_lzma.c \ + src/lib/compress/compress_none.c \ + src/lib/compress/compress_zlib.c \ + src/lib/compress/compress_zstd.c + +src_lib_libtor_compress_testing_a_SOURCES = \ + $(src_lib_libtor_compress_a_SOURCES) +src_lib_libtor_compress_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_compress_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/compress/compress.h \ + src/lib/compress/compress_lzma.h \ + src/lib/compress/compress_none.h \ + src/lib/compress/compress_zlib.h \ + src/lib/compress/compress_zstd.h diff --git a/src/lib/container/.may_include b/src/lib/container/.may_include new file mode 100644 index 0000000000..90de5eda40 --- /dev/null +++ b/src/lib/container/.may_include @@ -0,0 +1,18 @@ +orconfig.h +lib/cc/*.h +lib/container/*.h +lib/ctime/*.h +lib/defs/*.h +lib/malloc/*.h +lib/err/*.h +lib/smartlist_core/*.h +lib/string/*.h +lib/testsupport/testsupport.h +lib/intmath/*.h +lib/log/*.h + +# XXXX I am unsure about this one. It's only here for buffers.c +lib/time/*.h + +ht.h +siphash.h diff --git a/src/lib/container/bitarray.h b/src/lib/container/bitarray.h new file mode 100644 index 0000000000..172d56cc06 --- /dev/null +++ b/src/lib/container/bitarray.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_BITARRAY_H +#define TOR_BITARRAY_H + +/** + * \file bitarray.h + * + * \brief Implements a variable-sized (but non-resizeable) bit-array. + **/ + +#include "orconfig.h" +#include <string.h> +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + +#if SIZEOF_INT == 4 +#define BITARRAY_SHIFT 5 +#elif SIZEOF_INT == 8 +#define BITARRAY_SHIFT 6 +#else +#error "int is neither 4 nor 8 bytes. I can't deal with that." +#endif /* SIZEOF_INT == 4 || ... */ +#define BITARRAY_MASK ((1u<<BITARRAY_SHIFT)-1) + +/** A random-access array of one-bit-wide elements. */ +typedef unsigned int bitarray_t; +/** Create a new bit array that can hold <b>n_bits</b> bits. */ +static inline bitarray_t * +bitarray_init_zero(unsigned int n_bits) +{ + /* round up to the next int. */ + size_t sz = (n_bits+BITARRAY_MASK) >> BITARRAY_SHIFT; + return tor_calloc(sz, sizeof(unsigned int)); +} +/** Expand <b>ba</b> from holding <b>n_bits_old</b> to <b>n_bits_new</b>, + * clearing all new bits. Returns a possibly changed pointer to the + * bitarray. */ +static inline bitarray_t * +bitarray_expand(bitarray_t *ba, + unsigned int n_bits_old, unsigned int n_bits_new) +{ + size_t sz_old = (n_bits_old+BITARRAY_MASK) >> BITARRAY_SHIFT; + size_t sz_new = (n_bits_new+BITARRAY_MASK) >> BITARRAY_SHIFT; + char *ptr; + if (sz_new <= sz_old) + return ba; + ptr = tor_reallocarray(ba, sz_new, sizeof(unsigned int)); + /* This memset does nothing to the older excess bytes. But they were + * already set to 0 by bitarry_init_zero. */ + memset(ptr+sz_old*sizeof(unsigned int), 0, + (sz_new-sz_old)*sizeof(unsigned int)); + return (bitarray_t*) ptr; +} +/** Free the bit array <b>ba</b>. */ +static inline void +bitarray_free_(bitarray_t *ba) +{ + tor_free(ba); +} +#define bitarray_free(ba) FREE_AND_NULL(bitarray_t, bitarray_free_, (ba)) + +/** Set the <b>bit</b>th bit in <b>b</b> to 1. */ +static inline void +bitarray_set(bitarray_t *b, int bit) +{ + b[bit >> BITARRAY_SHIFT] |= (1u << (bit & BITARRAY_MASK)); +} +/** Set the <b>bit</b>th bit in <b>b</b> to 0. */ +static inline void +bitarray_clear(bitarray_t *b, int bit) +{ + b[bit >> BITARRAY_SHIFT] &= ~ (1u << (bit & BITARRAY_MASK)); +} +/** Return true iff <b>bit</b>th bit in <b>b</b> is nonzero. NOTE: does + * not necessarily return 1 on true. */ +static inline unsigned int +bitarray_is_set(bitarray_t *b, int bit) +{ + return b[bit >> BITARRAY_SHIFT] & (1u << (bit & BITARRAY_MASK)); +} + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/container/bloomfilt.c b/src/lib/container/bloomfilt.c new file mode 100644 index 0000000000..1cab817e18 --- /dev/null +++ b/src/lib/container/bloomfilt.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file bloomfilt.c + * \brief Uses bitarray_t to implement a bloom filter. + **/ + +#include <stdlib.h> + +#include "lib/malloc/util_malloc.h" +#include "lib/container/bloomfilt.h" +#include "lib/intmath/bits.h" +#include "lib/log/util_bug.h" +#include "siphash.h" + +/** How many bloom-filter bits we set per address. This is twice the + * BLOOMFILT_N_HASHES value, since we split the siphash output into two 32-bit + * values. */ +#define N_BITS_PER_ITEM (BLOOMFILT_N_HASHES * 2) + +struct bloomfilt_t { + /** siphash keys to make BLOOMFILT_N_HASHES independent hashes for each + * items. */ + struct sipkey key[BLOOMFILT_N_HASHES]; + bloomfilt_hash_fn hashfn; /**< Function used to generate hashes */ + uint32_t mask; /**< One less than the number of bits in <b>ba</b>; always + * one less than a power of two. */ + bitarray_t *ba; /**< A bit array to implement the Bloom filter. */ +}; + +#define BIT(set, n) ((n) & (set)->mask) + +/** Add the element <b>item</b> to <b>set</b>. */ +void +bloomfilt_add(bloomfilt_t *set, + const void *item) +{ + int i; + for (i = 0; i < BLOOMFILT_N_HASHES; ++i) { + uint64_t h = set->hashfn(&set->key[i], item); + uint32_t high_bits = (uint32_t)(h >> 32); + uint32_t low_bits = (uint32_t)(h); + bitarray_set(set->ba, BIT(set, high_bits)); + bitarray_set(set->ba, BIT(set, low_bits)); + } +} + +/** If <b>item</b> is in <b>set</b>, return nonzero. Otherwise, + * <em>probably</em> return zero. */ +int +bloomfilt_probably_contains(const bloomfilt_t *set, + const void *item) +{ + int i, matches = 0; + for (i = 0; i < BLOOMFILT_N_HASHES; ++i) { + uint64_t h = set->hashfn(&set->key[i], item); + uint32_t high_bits = (uint32_t)(h >> 32); + uint32_t low_bits = (uint32_t)(h); + // Note that !! is necessary here, since bitarray_is_set does not + // necessarily return 1 on true. + matches += !! bitarray_is_set(set->ba, BIT(set, high_bits)); + matches += !! bitarray_is_set(set->ba, BIT(set, low_bits)); + } + return matches == N_BITS_PER_ITEM; +} + +/** Return a newly allocated bloomfilt_t, optimized to hold a total of + * <b>max_elements</b> elements with a reasonably low false positive weight. + * + * Uses the siphash-based function <b>hashfn</b> to compute hard-to-collide + * functions of the items, and the key material <b>random_key</b> to + * key the hash. There must be BLOOMFILT_KEY_LEN bytes in the supplied key. + **/ +bloomfilt_t * +bloomfilt_new(int max_elements, + bloomfilt_hash_fn hashfn, + const uint8_t *random_key) +{ + /* The probability of false positives is about P=(1 - exp(-kn/m))^k, where k + * is the number of hash functions per entry, m is the bits in the array, + * and n is the number of elements inserted. For us, k==4, n<=max_elements, + * and m==n_bits= approximately max_elements*32. This gives + * P<(1-exp(-4*n/(32*n)))^4 == (1-exp(1/-8))^4 == .00019 + * + * It would be more optimal in space vs false positives to get this false + * positive rate by going for k==13, and m==18.5n, but we also want to + * conserve CPU, and k==13 is pretty big. + */ + int n_bits = 1u << (tor_log2(max_elements)+5); + bloomfilt_t *r = tor_malloc(sizeof(bloomfilt_t)); + r->mask = n_bits - 1; + r->ba = bitarray_init_zero(n_bits); + + tor_assert(sizeof(r->key) == BLOOMFILT_KEY_LEN); + memcpy(r->key, random_key, sizeof(r->key)); + + r->hashfn = hashfn; + + return r; +} + +/** Free all storage held in <b>set</b>. */ +void +bloomfilt_free_(bloomfilt_t *set) +{ + if (!set) + return; + bitarray_free(set->ba); + tor_free(set); +} diff --git a/src/lib/container/bloomfilt.h b/src/lib/container/bloomfilt.h new file mode 100644 index 0000000000..14f909cb19 --- /dev/null +++ b/src/lib/container/bloomfilt.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_BLOOMFILT_H +#define TOR_BLOOMFILT_H + +/** + * \file bloomfilt.h + * + * \brief Header for bloomfilt.c + **/ + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/container/bitarray.h" + +/** A set of elements, implemented as a Bloom filter. */ +typedef struct bloomfilt_t bloomfilt_t; + +/** How many 64-bit siphash values to extract per item. */ +#define BLOOMFILT_N_HASHES 2 + +/** How much key material do we need to randomize hashes? */ +#define BLOOMFILT_KEY_LEN (BLOOMFILT_N_HASHES * 16) + +struct sipkey; +typedef uint64_t (*bloomfilt_hash_fn)(const struct sipkey *key, + const void *item); + +void bloomfilt_add(bloomfilt_t *set, const void *item); +int bloomfilt_probably_contains(const bloomfilt_t *set, const void *item); + +bloomfilt_t *bloomfilt_new(int max_elements, + bloomfilt_hash_fn hashfn, + const uint8_t *random_key); +void bloomfilt_free_(bloomfilt_t* set); +#define bloomfilt_free(set) FREE_AND_NULL(bloomfilt_t, bloomfilt_free_, (set)) + +#endif /* !defined(TOR_BLOOMFILT_H) */ diff --git a/src/common/buffers.c b/src/lib/container/buffers.c index a01add9bef..5849704e35 100644 --- a/src/common/buffers.c +++ b/src/lib/container/buffers.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,21 +16,31 @@ * buffers: one for incoming data, and one for outcoming data. These are fed * and drained from functions in connection.c, trigged by events that are * monitored in main.c. + * + * This module only handles the buffer implementation itself. To use a buffer + * with the network, a compressor, or a TLS connection, see the other buffer_* + * modules. **/ #define BUFFERS_PRIVATE #include "orconfig.h" #include <stddef.h> -#include "buffers.h" -#include "compat.h" -#include "compress.h" -#include "util.h" -#include "torint.h" -#include "torlog.h" +#include "lib/container/buffers.h" +#include "lib/cc/torint.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/ctime/di_ops.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" +#include "lib/time/compat_time.h" + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#include <stdlib.h> +#include <string.h> + //#define PARANOIA #ifdef PARANOIA @@ -506,177 +516,6 @@ buf_get_total_allocation(void) return total_bytes_allocated_in_chunks; } -/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into - * <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set - * *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking, - * and the number of bytes read otherwise. */ -static inline int -read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, - int *reached_eof, int *socket_error) -{ - ssize_t read_result; - if (at_most > CHUNK_REMAINING_CAPACITY(chunk)) - at_most = CHUNK_REMAINING_CAPACITY(chunk); - read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0); - - if (read_result < 0) { - int e = tor_socket_errno(fd); - if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ -#ifdef _WIN32 - if (e == WSAENOBUFS) - log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?"); -#endif - *socket_error = e; - return -1; - } - return 0; /* would block. */ - } else if (read_result == 0) { - log_debug(LD_NET,"Encountered eof on fd %d", (int)fd); - *reached_eof = 1; - return 0; - } else { /* actually got bytes. */ - buf->datalen += read_result; - chunk->datalen += read_result; - log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, - (int)buf->datalen); - tor_assert(read_result < INT_MAX); - return (int)read_result; - } -} - -/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most - * <b>at_most</b> bytes, growing the buffer as necessary. If recv() returns 0 - * (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on - * error; else return the number of bytes read. - */ -/* XXXX indicate "read blocked" somehow? */ -int -buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, - int *reached_eof, - int *socket_error) -{ - /* XXXX It's stupid to overload the return values for these functions: - * "error status" and "number of bytes read" are not mutually exclusive. - */ - int r = 0; - size_t total_read = 0; - - check(); - tor_assert(reached_eof); - tor_assert(SOCKET_OK(s)); - - if (BUG(buf->datalen >= INT_MAX)) - return -1; - if (BUG(buf->datalen >= INT_MAX - at_most)) - return -1; - - while (at_most > total_read) { - size_t readlen = at_most - total_read; - chunk_t *chunk; - if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { - chunk = buf_add_chunk_with_capacity(buf, at_most, 1); - if (readlen > chunk->memlen) - readlen = chunk->memlen; - } else { - size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); - chunk = buf->tail; - if (cap < readlen) - readlen = cap; - } - - r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error); - check(); - if (r < 0) - return r; /* Error */ - tor_assert(total_read+r < INT_MAX); - total_read += r; - if ((size_t)r < readlen) { /* eof, block, or no more to read. */ - break; - } - } - return (int)total_read; -} - -/** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk - * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. On success, deduct - * the bytes written from *<b>buf_flushlen</b>. Return the number of bytes - * written on success, 0 on blocking, -1 on failure. - */ -static inline int -flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, - size_t *buf_flushlen) -{ - ssize_t write_result; - - if (sz > chunk->datalen) - sz = chunk->datalen; - write_result = tor_socket_send(s, chunk->data, sz, 0); - - if (write_result < 0) { - int e = tor_socket_errno(s); - if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ -#ifdef _WIN32 - if (e == WSAENOBUFS) - log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?"); -#endif - return -1; - } - log_debug(LD_NET,"write() would block, returning."); - return 0; - } else { - *buf_flushlen -= write_result; - buf_drain(buf, write_result); - tor_assert(write_result < INT_MAX); - return (int)write_result; - } -} - -/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most - * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by - * the number of bytes actually written, and remove the written bytes - * from the buffer. Return the number of bytes written on success, - * -1 on failure. Return 0 if write() would block. - */ -int -buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen) -{ - /* XXXX It's stupid to overload the return values for these functions: - * "error status" and "number of bytes flushed" are not mutually exclusive. - */ - int r; - size_t flushed = 0; - tor_assert(buf_flushlen); - tor_assert(SOCKET_OK(s)); - if (BUG(*buf_flushlen > buf->datalen)) { - *buf_flushlen = buf->datalen; - } - if (BUG(sz > *buf_flushlen)) { - sz = *buf_flushlen; - } - - check(); - while (sz) { - size_t flushlen0; - tor_assert(buf->head); - if (buf->head->datalen >= sz) - flushlen0 = sz; - else - flushlen0 = buf->head->datalen; - - r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen); - check(); - if (r < 0) - return r; - flushed += r; - sz -= r; - if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ - break; - } - tor_assert(flushed < INT_MAX); - return (int)flushed; -} - /** Append <b>string_len</b> bytes from <b>string</b> to the end of * <b>buf</b>. * @@ -1037,65 +876,6 @@ buf_get_line(buf_t *buf, char *data_out, size_t *data_len) return 1; } -/** Compress or uncompress the <b>data_len</b> bytes in <b>data</b> using the - * compression state <b>state</b>, appending the result to <b>buf</b>. If - * <b>done</b> is true, flush the data in the state and finish the - * compression/uncompression. Return -1 on failure, 0 on success. */ -int -buf_add_compress(buf_t *buf, tor_compress_state_t *state, - const char *data, size_t data_len, - const int done) -{ - char *next; - size_t old_avail, avail; - int over = 0; - - do { - int need_new_chunk = 0; - if (!buf->tail || ! CHUNK_REMAINING_CAPACITY(buf->tail)) { - size_t cap = data_len / 4; - buf_add_chunk_with_capacity(buf, cap, 1); - } - next = CHUNK_WRITE_PTR(buf->tail); - avail = old_avail = CHUNK_REMAINING_CAPACITY(buf->tail); - switch (tor_compress_process(state, &next, &avail, - &data, &data_len, done)) { - case TOR_COMPRESS_DONE: - over = 1; - break; - case TOR_COMPRESS_ERROR: - return -1; - case TOR_COMPRESS_OK: - if (data_len == 0) { - tor_assert_nonfatal(!done); - over = 1; - } - break; - case TOR_COMPRESS_BUFFER_FULL: - if (avail) { - /* The compression module says we need more room - * (TOR_COMPRESS_BUFFER_FULL). Start a new chunk automatically, - * whether were going to or not. */ - need_new_chunk = 1; - } - if (data_len == 0 && !done) { - /* We've consumed all the input data, though, so there's no - * point in forging ahead right now. */ - over = 1; - } - break; - } - buf->datalen += old_avail - avail; - buf->tail->datalen += old_avail - avail; - if (need_new_chunk) { - buf_add_chunk_with_capacity(buf, data_len/4, 1); - } - - } while (!over); - check(); - return 0; -} - /** Set *<b>output</b> to contain a copy of the data in *<b>input</b> */ int buf_set_to_copy(buf_t **output, @@ -1143,4 +923,3 @@ buf_assert_ok(buf_t *buf) tor_assert(buf->datalen == total); } } - diff --git a/src/common/buffers.h b/src/lib/container/buffers.h index 4275152de2..c48f83cfc7 100644 --- a/src/common/buffers.h +++ b/src/lib/container/buffers.h @@ -1,24 +1,25 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** * \file buffers.h + * * \brief Header file for buffers.c. **/ #ifndef TOR_BUFFERS_H #define TOR_BUFFERS_H -#include "compat.h" -#include "torint.h" -#include "testsupport.h" +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" -typedef struct buf_t buf_t; +#include <stdarg.h> -struct tor_compress_state_t; +typedef struct buf_t buf_t; buf_t *buf_new(void); buf_t *buf_new_with_capacity(size_t size); @@ -35,21 +36,12 @@ size_t buf_slack(const buf_t *buf); uint32_t buf_get_oldest_chunk_timestamp(const buf_t *buf, uint32_t now); size_t buf_get_total_allocation(void); -int buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, - int *reached_eof, - int *socket_error); - -int buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, - size_t *buf_flushlen); - int buf_add(buf_t *buf, const char *string, size_t string_len); void buf_add_string(buf_t *buf, const char *string); void buf_add_printf(buf_t *buf, const char *format, ...) CHECK_PRINTF(2, 3); void buf_add_vprintf(buf_t *buf, const char *format, va_list args) CHECK_PRINTF(2, 0); -int buf_add_compress(buf_t *buf, struct tor_compress_state_t *state, - const char *data, size_t data_len, int done); int buf_move_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen); void buf_move_all(buf_t *buf_out, buf_t *buf_in); void buf_peek(const buf_t *buf, char *string, size_t string_len); @@ -128,4 +120,3 @@ CHUNK_WRITE_PTR(chunk_t *chunk) #endif /* defined(BUFFERS_PRIVATE) */ #endif /* !defined(TOR_BUFFERS_H) */ - diff --git a/src/common/handles.h b/src/lib/container/handles.h index aef8cd89ef..21ec0dfeec 100644 --- a/src/common/handles.h +++ b/src/lib/container/handles.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -50,8 +50,9 @@ #define TOR_HANDLE_H #include "orconfig.h" -#include "tor_queue.h" -#include "util.h" + +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" #define HANDLE_ENTRY(name, structname) \ struct name ## _handle_head_t *handle_head @@ -150,4 +151,3 @@ } #endif /* !defined(TOR_HANDLE_H) */ - diff --git a/src/lib/container/include.am b/src/lib/container/include.am new file mode 100644 index 0000000000..e6492098b5 --- /dev/null +++ b/src/lib/container/include.am @@ -0,0 +1,27 @@ + +noinst_LIBRARIES += src/lib/libtor-container.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-container-testing.a +endif + +src_lib_libtor_container_a_SOURCES = \ + src/lib/container/bloomfilt.c \ + src/lib/container/buffers.c \ + src/lib/container/map.c \ + src/lib/container/order.c \ + src/lib/container/smartlist.c + +src_lib_libtor_container_testing_a_SOURCES = \ + $(src_lib_libtor_container_a_SOURCES) +src_lib_libtor_container_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_container_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/container/bitarray.h \ + src/lib/container/bloomfilt.h \ + src/lib/container/buffers.h \ + src/lib/container/handles.h \ + src/lib/container/map.h \ + src/lib/container/order.h \ + src/lib/container/smartlist.h diff --git a/src/lib/container/map.c b/src/lib/container/map.c new file mode 100644 index 0000000000..0602eac891 --- /dev/null +++ b/src/lib/container/map.c @@ -0,0 +1,413 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file map.c + * + * \brief Hash-table implementations of a string-to-void* map, and of + * a digest-to-void* map. + **/ + +#include "lib/container/map.h" +#include "lib/ctime/di_ops.h" +#include "lib/defs/digest_sizes.h" +#include "lib/string/util_string.h" +#include "lib/malloc/util_malloc.h" + +#include "lib/log/util_bug.h" + +#include <stdlib.h> +#include <string.h> + +#include "ht.h" + +/** Helper: Declare an entry type and a map type to implement a mapping using + * ht.h. The map type will be called <b>maptype</b>. The key part of each + * entry is declared using the C declaration <b>keydecl</b>. All functions + * and types associated with the map get prefixed with <b>prefix</b> */ +#define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \ + typedef struct prefix ## entry_t { \ + HT_ENTRY(prefix ## entry_t) node; \ + void *val; \ + keydecl; \ + } prefix ## entry_t; \ + struct maptype { \ + HT_HEAD(prefix ## impl, prefix ## entry_t) head; \ + } + +DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_); +DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_); +DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_); + +/** Helper: compare strmap_entry_t objects by key value. */ +static inline int +strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b) +{ + return !strcmp(a->key, b->key); +} + +/** Helper: return a hash value for a strmap_entry_t. */ +static inline unsigned int +strmap_entry_hash(const strmap_entry_t *a) +{ + return (unsigned) siphash24g(a->key, strlen(a->key)); +} + +/** Helper: compare digestmap_entry_t objects by key value. */ +static inline int +digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b) +{ + return tor_memeq(a->key, b->key, DIGEST_LEN); +} + +/** Helper: return a hash value for a digest_map_t. */ +static inline unsigned int +digestmap_entry_hash(const digestmap_entry_t *a) +{ + return (unsigned) siphash24g(a->key, DIGEST_LEN); +} + +/** Helper: compare digestmap_entry_t objects by key value. */ +static inline int +digest256map_entries_eq(const digest256map_entry_t *a, + const digest256map_entry_t *b) +{ + return tor_memeq(a->key, b->key, DIGEST256_LEN); +} + +/** Helper: return a hash value for a digest_map_t. */ +static inline unsigned int +digest256map_entry_hash(const digest256map_entry_t *a) +{ + return (unsigned) siphash24g(a->key, DIGEST256_LEN); +} + +HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, + strmap_entries_eq) +HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash, + strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) + +HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, + digestmap_entries_eq) +HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, + digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_) + +HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node, + digest256map_entry_hash, + digest256map_entries_eq) +HT_GENERATE2(digest256map_impl, digest256map_entry_t, node, + digest256map_entry_hash, + digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_) + +#define strmap_entry_free(ent) \ + FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent)) +#define digestmap_entry_free(ent) \ + FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent)) +#define digest256map_entry_free(ent) \ + FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent)) + +static inline void +strmap_entry_free_(strmap_entry_t *ent) +{ + tor_free(ent->key); + tor_free(ent); +} +static inline void +digestmap_entry_free_(digestmap_entry_t *ent) +{ + tor_free(ent); +} +static inline void +digest256map_entry_free_(digest256map_entry_t *ent) +{ + tor_free(ent); +} + +static inline void +strmap_assign_tmp_key(strmap_entry_t *ent, const char *key) +{ + ent->key = (char*)key; +} +static inline void +digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key) +{ + memcpy(ent->key, key, DIGEST_LEN); +} +static inline void +digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key) +{ + memcpy(ent->key, key, DIGEST256_LEN); +} +static inline void +strmap_assign_key(strmap_entry_t *ent, const char *key) +{ + ent->key = tor_strdup(key); +} +static inline void +digestmap_assign_key(digestmap_entry_t *ent, const char *key) +{ + memcpy(ent->key, key, DIGEST_LEN); +} +static inline void +digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key) +{ + memcpy(ent->key, key, DIGEST256_LEN); +} + +/** + * Macro: implement all the functions for a map that are declared in + * map.h by the DECLARE_MAP_FNS() macro. You must additionally define a + * prefix_entry_free_() function to free entries (and their keys), a + * prefix_assign_tmp_key() function to temporarily set a stack-allocated + * entry to hold a key, and a prefix_assign_key() function to set a + * heap-allocated entry to hold a key. + */ +#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \ + /** Create and return a new empty map. */ \ + MOCK_IMPL(maptype *, \ + prefix##_new,(void)) \ + { \ + maptype *result; \ + result = tor_malloc(sizeof(maptype)); \ + HT_INIT(prefix##_impl, &result->head); \ + return result; \ + } \ + \ + /** Return the item from <b>map</b> whose key matches <b>key</b>, or \ + * NULL if no such value exists. */ \ + void * \ + prefix##_get(const maptype *map, const keytype key) \ + { \ + prefix ##_entry_t *resolve; \ + prefix ##_entry_t search; \ + tor_assert(map); \ + tor_assert(key); \ + prefix ##_assign_tmp_key(&search, key); \ + resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ + if (resolve) { \ + return resolve->val; \ + } else { \ + return NULL; \ + } \ + } \ + \ + /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \ + * return the previous value, or NULL if no such value existed. */ \ + void * \ + prefix##_set(maptype *map, const keytype key, void *val) \ + { \ + prefix##_entry_t search; \ + void *oldval; \ + tor_assert(map); \ + tor_assert(key); \ + tor_assert(val); \ + prefix##_assign_tmp_key(&search, key); \ + /* We a lot of our time in this function, so the code below is */ \ + /* meant to optimize the check/alloc/set cycle by avoiding the two */\ + /* trips to the hash table that we would do in the unoptimized */ \ + /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ + /* HT_SET_HASH and HT_FIND_P.) */ \ + HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ + &(map->head), \ + prefix##_entry_t, &search, ptr, \ + { \ + /* we found an entry. */ \ + oldval = (*ptr)->val; \ + (*ptr)->val = val; \ + return oldval; \ + }, \ + { \ + /* We didn't find the entry. */ \ + prefix##_entry_t *newent = \ + tor_malloc_zero(sizeof(prefix##_entry_t)); \ + prefix##_assign_key(newent, key); \ + newent->val = val; \ + HT_FOI_INSERT_(node, &(map->head), \ + &search, newent, ptr); \ + return NULL; \ + }); \ + } \ + \ + /** Remove the value currently associated with <b>key</b> from the map. \ + * Return the value if one was set, or NULL if there was no entry for \ + * <b>key</b>. \ + * \ + * Note: you must free any storage associated with the returned value. \ + */ \ + void * \ + prefix##_remove(maptype *map, const keytype key) \ + { \ + prefix##_entry_t *resolve; \ + prefix##_entry_t search; \ + void *oldval; \ + tor_assert(map); \ + tor_assert(key); \ + prefix##_assign_tmp_key(&search, key); \ + resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \ + if (resolve) { \ + oldval = resolve->val; \ + prefix##_entry_free(resolve); \ + return oldval; \ + } else { \ + return NULL; \ + } \ + } \ + \ + /** Return the number of elements in <b>map</b>. */ \ + int \ + prefix##_size(const maptype *map) \ + { \ + return HT_SIZE(&map->head); \ + } \ + \ + /** Return true iff <b>map</b> has no entries. */ \ + int \ + prefix##_isempty(const maptype *map) \ + { \ + return HT_EMPTY(&map->head); \ + } \ + \ + /** Assert that <b>map</b> is not corrupt. */ \ + void \ + prefix##_assert_ok(const maptype *map) \ + { \ + tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \ + } \ + \ + /** Remove all entries from <b>map</b>, and deallocate storage for \ + * those entries. If free_val is provided, invoked it every value in \ + * <b>map</b>. */ \ + MOCK_IMPL(void, \ + prefix##_free_, (maptype *map, void (*free_val)(void*))) \ + { \ + prefix##_entry_t **ent, **next, *this; \ + if (!map) \ + return; \ + for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ + ent = next) { \ + this = *ent; \ + next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ + if (free_val) \ + free_val(this->val); \ + prefix##_entry_free(this); \ + } \ + tor_assert(HT_EMPTY(&map->head)); \ + HT_CLEAR(prefix##_impl, &map->head); \ + tor_free(map); \ + } \ + \ + /** return an <b>iterator</b> pointer to the front of a map. \ + * \ + * Iterator example: \ + * \ + * \code \ + * // uppercase values in "map", removing empty values. \ + * \ + * strmap_iter_t *iter; \ + * const char *key; \ + * void *val; \ + * char *cp; \ + * \ + * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \ + * strmap_iter_get(iter, &key, &val); \ + * cp = (char*)val; \ + * if (!*cp) { \ + * iter = strmap_iter_next_rmv(map,iter); \ + * free(val); \ + * } else { \ + * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \ + */ \ + prefix##_iter_t * \ + prefix##_iter_init(maptype *map) \ + { \ + tor_assert(map); \ + return HT_START(prefix##_impl, &map->head); \ + } \ + \ + /** Advance <b>iter</b> a single step to the next entry, and return \ + * its new value. */ \ + prefix##_iter_t * \ + prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \ + { \ + tor_assert(map); \ + tor_assert(iter); \ + return HT_NEXT(prefix##_impl, &map->head, iter); \ + } \ + /** Advance <b>iter</b> a single step to the next entry, removing the \ + * current entry, and return its new value. */ \ + prefix##_iter_t * \ + prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \ + { \ + prefix##_entry_t *rmv; \ + tor_assert(map); \ + tor_assert(iter); \ + tor_assert(*iter); \ + rmv = *iter; \ + iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \ + prefix##_entry_free(rmv); \ + return iter; \ + } \ + /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \ + * to by iter. */ \ + void \ + prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \ + void **valp) \ + { \ + tor_assert(iter); \ + tor_assert(*iter); \ + tor_assert(keyp); \ + tor_assert(valp); \ + *keyp = (*iter)->key; \ + *valp = (*iter)->val; \ + } \ + /** Return true iff <b>iter</b> has advanced past the last entry of \ + * <b>map</b>. */ \ + int \ + prefix##_iter_done(prefix##_iter_t *iter) \ + { \ + return iter == NULL; \ + } + +IMPLEMENT_MAP_FNS(strmap_t, char *, strmap) +IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap) +IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map) + +/** Same as strmap_set, but first converts <b>key</b> to lowercase. */ +void * +strmap_set_lc(strmap_t *map, const char *key, void *val) +{ + /* We could be a little faster by using strcasecmp instead, and a separate + * type, but I don't think it matters. */ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_set(map,lc_key,val); + tor_free(lc_key); + return v; +} + +/** Same as strmap_get, but first converts <b>key</b> to lowercase. */ +void * +strmap_get_lc(const strmap_t *map, const char *key) +{ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_get(map,lc_key); + tor_free(lc_key); + return v; +} + +/** Same as strmap_remove, but first converts <b>key</b> to lowercase */ +void * +strmap_remove_lc(strmap_t *map, const char *key) +{ + void *v; + char *lc_key = tor_strdup(key); + tor_strlower(lc_key); + v = strmap_remove(map,lc_key); + tor_free(lc_key); + return v; +} diff --git a/src/lib/container/map.h b/src/lib/container/map.h new file mode 100644 index 0000000000..ff71622682 --- /dev/null +++ b/src/lib/container/map.h @@ -0,0 +1,261 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_MAP_H +#define TOR_MAP_H + +/** + * \file map.h + * + * \brief Headers for map.c. + **/ + +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" + +#include "siphash.h" + +#define DECLARE_MAP_FNS(maptype, keytype, prefix) \ + typedef struct maptype maptype; \ + typedef struct prefix##entry_t *prefix##iter_t; \ + MOCK_DECL(maptype*, prefix##new, (void)); \ + void* prefix##set(maptype *map, keytype key, void *val); \ + void* prefix##get(const maptype *map, keytype key); \ + void* prefix##remove(maptype *map, keytype key); \ + MOCK_DECL(void, prefix##free_, (maptype *map, void (*free_val)(void*))); \ + int prefix##isempty(const maptype *map); \ + int prefix##size(const maptype *map); \ + prefix##iter_t *prefix##iter_init(maptype *map); \ + prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter); \ + prefix##iter_t *prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter); \ + void prefix##iter_get(prefix##iter_t *iter, keytype *keyp, void **valp); \ + int prefix##iter_done(prefix##iter_t *iter); \ + void prefix##assert_ok(const maptype *map) + +/* Map from const char * to void *. Implemented with a hash table. */ +DECLARE_MAP_FNS(strmap_t, const char *, strmap_); +/* Map from const char[DIGEST_LEN] to void *. Implemented with a hash table. */ +DECLARE_MAP_FNS(digestmap_t, const char *, digestmap_); +/* Map from const uint8_t[DIGEST256_LEN] to void *. Implemented with a hash + * table. */ +DECLARE_MAP_FNS(digest256map_t, const uint8_t *, digest256map_); + +#define MAP_FREE_AND_NULL(maptype, map, fn) \ + do { \ + maptype ## _free_((map), (fn)); \ + (map) = NULL; \ + } while (0) + +#define strmap_free(map, fn) MAP_FREE_AND_NULL(strmap, (map), (fn)) +#define digestmap_free(map, fn) MAP_FREE_AND_NULL(digestmap, (map), (fn)) +#define digest256map_free(map, fn) MAP_FREE_AND_NULL(digest256map, (map), (fn)) + +#undef DECLARE_MAP_FNS + +/** Iterates over the key-value pairs in a map <b>map</b> in order. + * <b>prefix</b> is as for DECLARE_MAP_FNS (i.e., strmap_ or digestmap_). + * The map's keys and values are of type keytype and valtype respectively; + * each iteration assigns them to keyvar and valvar. + * + * Example use: + * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * // use k and r + * } MAP_FOREACH_END. + */ +/* Unpacks to, approximately: + * { + * digestmap_iter_t *k_iter; + * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); + * k_iter = digestmap_iter_next(m, k_iter)) { + * const char *k; + * void *r_voidp; + * routerinfo_t *r; + * digestmap_iter_get(k_iter, &k, &r_voidp); + * r = r_voidp; + * // use k and r + * } + * } + */ +#define MAP_FOREACH(prefix, map, keytype, keyvar, valtype, valvar) \ + STMT_BEGIN \ + prefix##iter_t *keyvar##_iter; \ + for (keyvar##_iter = prefix##iter_init(map); \ + !prefix##iter_done(keyvar##_iter); \ + keyvar##_iter = prefix##iter_next(map, keyvar##_iter)) { \ + keytype keyvar; \ + void *valvar##_voidp; \ + valtype valvar; \ + prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + valvar = valvar##_voidp; + +/** As MAP_FOREACH, except allows members to be removed from the map + * during the iteration via MAP_DEL_CURRENT. Example use: + * + * Example use: + * MAP_FOREACH(digestmap_, m, const char *, k, routerinfo_t *, r) { + * if (is_very_old(r)) + * MAP_DEL_CURRENT(k); + * } MAP_FOREACH_END. + **/ +/* Unpacks to, approximately: + * { + * digestmap_iter_t *k_iter; + * int k_del=0; + * for (k_iter = digestmap_iter_init(m); !digestmap_iter_done(k_iter); + * k_iter = k_del ? digestmap_iter_next(m, k_iter) + * : digestmap_iter_next_rmv(m, k_iter)) { + * const char *k; + * void *r_voidp; + * routerinfo_t *r; + * k_del=0; + * digestmap_iter_get(k_iter, &k, &r_voidp); + * r = r_voidp; + * if (is_very_old(r)) { + * k_del = 1; + * } + * } + * } + */ +#define MAP_FOREACH_MODIFY(prefix, map, keytype, keyvar, valtype, valvar) \ + STMT_BEGIN \ + prefix##iter_t *keyvar##_iter; \ + int keyvar##_del=0; \ + for (keyvar##_iter = prefix##iter_init(map); \ + !prefix##iter_done(keyvar##_iter); \ + keyvar##_iter = keyvar##_del ? \ + prefix##iter_next_rmv(map, keyvar##_iter) : \ + prefix##iter_next(map, keyvar##_iter)) { \ + keytype keyvar; \ + void *valvar##_voidp; \ + valtype valvar; \ + keyvar##_del=0; \ + prefix##iter_get(keyvar##_iter, &keyvar, &valvar##_voidp); \ + valvar = valvar##_voidp; + +/** Used with MAP_FOREACH_MODIFY to remove the currently-iterated-upon + * member of the map. */ +#define MAP_DEL_CURRENT(keyvar) \ + STMT_BEGIN \ + keyvar##_del = 1; \ + STMT_END + +/** Used to end a MAP_FOREACH() block. */ +#define MAP_FOREACH_END } STMT_END ; + +/** As MAP_FOREACH, but does not require declaration of prefix or keytype. + * Example use: + * DIGESTMAP_FOREACH(m, k, routerinfo_t *, r) { + * // use k and r + * } DIGESTMAP_FOREACH_END. + */ +#define DIGESTMAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(digestmap_, map, const char *, keyvar, valtype, valvar) + +/** As MAP_FOREACH_MODIFY, but does not require declaration of prefix or + * keytype. + * Example use: + * DIGESTMAP_FOREACH_MODIFY(m, k, routerinfo_t *, r) { + * if (is_very_old(r)) + * MAP_DEL_CURRENT(k); + * } DIGESTMAP_FOREACH_END. + */ +#define DIGESTMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(digestmap_, map, const char *, keyvar, valtype, valvar) +/** Used to end a DIGESTMAP_FOREACH() block. */ +#define DIGESTMAP_FOREACH_END MAP_FOREACH_END + +#define DIGEST256MAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(digest256map_, map, const uint8_t *, keyvar, valtype, valvar) +#define DIGEST256MAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(digest256map_, map, const uint8_t *, \ + keyvar, valtype, valvar) +#define DIGEST256MAP_FOREACH_END MAP_FOREACH_END + +#define STRMAP_FOREACH(map, keyvar, valtype, valvar) \ + MAP_FOREACH(strmap_, map, const char *, keyvar, valtype, valvar) +#define STRMAP_FOREACH_MODIFY(map, keyvar, valtype, valvar) \ + MAP_FOREACH_MODIFY(strmap_, map, const char *, keyvar, valtype, valvar) +#define STRMAP_FOREACH_END MAP_FOREACH_END + +void* strmap_set_lc(strmap_t *map, const char *key, void *val); +void* strmap_get_lc(const strmap_t *map, const char *key); +void* strmap_remove_lc(strmap_t *map, const char *key); + +#define DECLARE_TYPED_DIGESTMAP_FNS(prefix, maptype, valtype) \ + typedef struct maptype maptype; \ + typedef struct prefix##iter_t *prefix##iter_t; \ + ATTR_UNUSED static inline maptype* \ + prefix##new(void) \ + { \ + return (maptype*)digestmap_new(); \ + } \ + ATTR_UNUSED static inline digestmap_t* \ + prefix##to_digestmap(maptype *map) \ + { \ + return (digestmap_t*)map; \ + } \ + ATTR_UNUSED static inline valtype* \ + prefix##get(maptype *map, const char *key) \ + { \ + return (valtype*)digestmap_get((digestmap_t*)map, key); \ + } \ + ATTR_UNUSED static inline valtype* \ + prefix##set(maptype *map, const char *key, valtype *val) \ + { \ + return (valtype*)digestmap_set((digestmap_t*)map, key, val); \ + } \ + ATTR_UNUSED static inline valtype* \ + prefix##remove(maptype *map, const char *key) \ + { \ + return (valtype*)digestmap_remove((digestmap_t*)map, key); \ + } \ + ATTR_UNUSED static inline void \ + prefix##f##ree_(maptype *map, void (*free_val)(void*)) \ + { \ + digestmap_free_((digestmap_t*)map, free_val); \ + } \ + ATTR_UNUSED static inline int \ + prefix##isempty(maptype *map) \ + { \ + return digestmap_isempty((digestmap_t*)map); \ + } \ + ATTR_UNUSED static inline int \ + prefix##size(maptype *map) \ + { \ + return digestmap_size((digestmap_t*)map); \ + } \ + ATTR_UNUSED static inline \ + prefix##iter_t *prefix##iter_init(maptype *map) \ + { \ + return (prefix##iter_t*) digestmap_iter_init((digestmap_t*)map); \ + } \ + ATTR_UNUSED static inline \ + prefix##iter_t *prefix##iter_next(maptype *map, prefix##iter_t *iter) \ + { \ + return (prefix##iter_t*) digestmap_iter_next( \ + (digestmap_t*)map, (digestmap_iter_t*)iter); \ + } \ + ATTR_UNUSED static inline prefix##iter_t* \ + prefix##iter_next_rmv(maptype *map, prefix##iter_t *iter) \ + { \ + return (prefix##iter_t*) digestmap_iter_next_rmv( \ + (digestmap_t*)map, (digestmap_iter_t*)iter); \ + } \ + ATTR_UNUSED static inline void \ + prefix##iter_get(prefix##iter_t *iter, \ + const char **keyp, \ + valtype **valp) \ + { \ + void *v; \ + digestmap_iter_get((digestmap_iter_t*) iter, keyp, &v); \ + *valp = v; \ + } \ + ATTR_UNUSED static inline int \ + prefix##iter_done(prefix##iter_t *iter) \ + { \ + return digestmap_iter_done((digestmap_iter_t*)iter); \ + } + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/container/order.c b/src/lib/container/order.c new file mode 100644 index 0000000000..1efef2c734 --- /dev/null +++ b/src/lib/container/order.c @@ -0,0 +1,48 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file order.c + * \brief Functions for finding the n'th element of an array. + **/ + +#include <stdlib.h> + +#include "lib/container/order.h" +#include "lib/log/util_bug.h" + +/** Declare a function called <b>funcname</b> that acts as a find_nth_FOO + * function for an array of type <b>elt_t</b>*. + * + * NOTE: The implementation kind of sucks: It's O(n log n), whereas finding + * the kth element of an n-element list can be done in O(n). Then again, this + * implementation is not in critical path, and it is obviously correct. */ +#define IMPLEMENT_ORDER_FUNC(funcname, elt_t) \ + static int \ + _cmp_ ## elt_t(const void *_a, const void *_b) \ + { \ + const elt_t *a = _a, *b = _b; \ + if (*a<*b) \ + return -1; \ + else if (*a>*b) \ + return 1; \ + else \ + return 0; \ + } \ + elt_t \ + funcname(elt_t *array, int n_elements, int nth) \ + { \ + tor_assert(nth >= 0); \ + tor_assert(nth < n_elements); \ + qsort(array, n_elements, sizeof(elt_t), _cmp_ ##elt_t); \ + return array[nth]; \ + } + +IMPLEMENT_ORDER_FUNC(find_nth_int, int) +IMPLEMENT_ORDER_FUNC(find_nth_time, time_t) +IMPLEMENT_ORDER_FUNC(find_nth_double, double) +IMPLEMENT_ORDER_FUNC(find_nth_uint32, uint32_t) +IMPLEMENT_ORDER_FUNC(find_nth_int32, int32_t) +IMPLEMENT_ORDER_FUNC(find_nth_long, long) diff --git a/src/lib/container/order.h b/src/lib/container/order.h new file mode 100644 index 0000000000..f0675f347b --- /dev/null +++ b/src/lib/container/order.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ORDER_H +#define TOR_ORDER_H + +/** + * \file order.h + * + * \brief Header for order.c. + **/ + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +/* These functions, given an <b>array</b> of <b>n_elements</b>, return the + * <b>nth</b> lowest element. <b>nth</b>=0 gives the lowest element; + * <b>n_elements</b>-1 gives the highest; and (<b>n_elements</b>-1) / 2 gives + * the median. As a side effect, the elements of <b>array</b> are sorted. */ +int find_nth_int(int *array, int n_elements, int nth); +time_t find_nth_time(time_t *array, int n_elements, int nth); +double find_nth_double(double *array, int n_elements, int nth); +int32_t find_nth_int32(int32_t *array, int n_elements, int nth); +uint32_t find_nth_uint32(uint32_t *array, int n_elements, int nth); +long find_nth_long(long *array, int n_elements, int nth); +static inline int +median_int(int *array, int n_elements) +{ + return find_nth_int(array, n_elements, (n_elements-1)/2); +} +static inline time_t +median_time(time_t *array, int n_elements) +{ + return find_nth_time(array, n_elements, (n_elements-1)/2); +} +static inline double +median_double(double *array, int n_elements) +{ + return find_nth_double(array, n_elements, (n_elements-1)/2); +} +static inline uint32_t +median_uint32(uint32_t *array, int n_elements) +{ + return find_nth_uint32(array, n_elements, (n_elements-1)/2); +} +static inline int32_t +median_int32(int32_t *array, int n_elements) +{ + return find_nth_int32(array, n_elements, (n_elements-1)/2); +} + +static inline uint32_t +third_quartile_uint32(uint32_t *array, int n_elements) +{ + return find_nth_uint32(array, n_elements, (n_elements*3)/4); +} + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/container/smartlist.c b/src/lib/container/smartlist.c new file mode 100644 index 0000000000..c3abbff513 --- /dev/null +++ b/src/lib/container/smartlist.c @@ -0,0 +1,839 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file smartlist.c + * + * \brief Higher-level functions for the "smartlist" resizeable array + * abstraction. + * + * The functions declared here use higher-level functionality than those in + * smartlist_core.c, and handle things like smartlists of different types, + * sorting, searching, heap-structured smartlists, and other convenience + * functions. + **/ + +#include "lib/container/smartlist.h" +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" +#include "lib/defs/digest_sizes.h" +#include "lib/ctime/di_ops.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/string/util_string.h" +#include "lib/string/printf.h" + +#include "lib/log/util_bug.h" + +#include <stdlib.h> +#include <string.h> + +/** Append the string produced by tor_asprintf(<b>pattern</b>, <b>...</b>) + * to <b>sl</b>. */ +void +smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) +{ + va_list ap; + va_start(ap, pattern); + smartlist_add_vasprintf(sl, pattern, ap); + va_end(ap); +} + +/** va_list-based backend of smartlist_add_asprintf. */ +void +smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, + va_list args) +{ + char *str = NULL; + + tor_vasprintf(&str, pattern, args); + tor_assert(str != NULL); + + smartlist_add(sl, str); +} + +/** Reverse the order of the items in <b>sl</b>. */ +void +smartlist_reverse(smartlist_t *sl) +{ + int i, j; + void *tmp; + tor_assert(sl); + for (i = 0, j = sl->num_used-1; i < j; ++i, --j) { + tmp = sl->list[i]; + sl->list[i] = sl->list[j]; + sl->list[j] = tmp; + } +} + +/** If there are any strings in sl equal to element, remove and free them. + * Does not preserve order. */ +void +smartlist_string_remove(smartlist_t *sl, const char *element) +{ + int i; + tor_assert(sl); + tor_assert(element); + for (i = 0; i < sl->num_used; ++i) { + if (!strcmp(element, sl->list[i])) { + tor_free(sl->list[i]); + sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + sl->list[sl->num_used] = NULL; + } + } +} + +/** Return true iff <b>sl</b> has some element E such that + * !strcmp(E,<b>element</b>) + */ +int +smartlist_contains_string(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (strcmp((const char*)sl->list[i],element)==0) + return 1; + return 0; +} + +/** If <b>element</b> is equal to an element of <b>sl</b>, return that + * element's index. Otherwise, return -1. */ +int +smartlist_string_pos(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return -1; + for (i=0; i < sl->num_used; i++) + if (strcmp((const char*)sl->list[i],element)==0) + return i; + return -1; +} + +/** If <b>element</b> is the same pointer as an element of <b>sl</b>, return + * that element's index. Otherwise, return -1. */ +int +smartlist_pos(const smartlist_t *sl, const void *element) +{ + int i; + if (!sl) return -1; + for (i=0; i < sl->num_used; i++) + if (element == sl->list[i]) + return i; + return -1; +} + +/** Return true iff <b>sl</b> has some element E such that + * !strcasecmp(E,<b>element</b>) + */ +int +smartlist_contains_string_case(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (strcasecmp((const char*)sl->list[i],element)==0) + return 1; + return 0; +} + +/** Return true iff <b>sl</b> has some element E such that E is equal + * to the decimal encoding of <b>num</b>. + */ +int +smartlist_contains_int_as_string(const smartlist_t *sl, int num) +{ + char buf[32]; /* long enough for 64-bit int, and then some. */ + tor_snprintf(buf,sizeof(buf),"%d", num); + return smartlist_contains_string(sl, buf); +} + +/** Return true iff the two lists contain the same strings in the same + * order, or if they are both NULL. */ +int +smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, const char *, cp1, { + const char *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (strcmp(cp1, cp2)) + return 0; + }); + return 1; +} + +/** Return true iff the two lists contain the same int pointer values in + * the same order, or if they are both NULL. */ +int +smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2) +{ + if (sl1 == NULL) + return sl2 == NULL; + if (sl2 == NULL) + return 0; + if (smartlist_len(sl1) != smartlist_len(sl2)) + return 0; + SMARTLIST_FOREACH(sl1, int *, cp1, { + int *cp2 = smartlist_get(sl2, cp1_sl_idx); + if (*cp1 != *cp2) + return 0; + }); + return 1; +} + +/** Return true iff <b>sl</b> has some element E such that + * tor_memeq(E,<b>element</b>,DIGEST_LEN) + */ +int +smartlist_contains_digest(const smartlist_t *sl, const char *element) +{ + int i; + if (!sl) return 0; + for (i=0; i < sl->num_used; i++) + if (tor_memeq((const char*)sl->list[i],element,DIGEST_LEN)) + return 1; + return 0; +} + +/** Return true iff some element E of sl2 has smartlist_contains(sl1,E). + */ +int +smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl2->num_used; i++) + if (smartlist_contains(sl1, sl2->list[i])) + return 1; + return 0; +} + +/** Remove every element E of sl1 such that !smartlist_contains(sl2,E). + * Does not preserve the order of sl1. + */ +void +smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl1->num_used; i++) + if (!smartlist_contains(sl2, sl1->list[i])) { + sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + sl1->list[sl1->num_used] = NULL; + } +} + +/** Remove every element E of sl1 such that smartlist_contains(sl2,E). + * Does not preserve the order of sl1. + */ +void +smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2) +{ + int i; + for (i=0; i < sl2->num_used; i++) + smartlist_remove(sl1, sl2->list[i]); +} + +/** Allocate and return a new string containing the concatenation of + * the elements of <b>sl</b>, in order, separated by <b>join</b>. If + * <b>terminate</b> is true, also terminate the string with <b>join</b>. + * If <b>len_out</b> is not NULL, set <b>len_out</b> to the length of + * the returned string. Requires that every element of <b>sl</b> is + * NUL-terminated string. + */ +char * +smartlist_join_strings(smartlist_t *sl, const char *join, + int terminate, size_t *len_out) +{ + return smartlist_join_strings2(sl,join,strlen(join),terminate,len_out); +} + +/** As smartlist_join_strings, but instead of separating/terminated with a + * NUL-terminated string <b>join</b>, uses the <b>join_len</b>-byte sequence + * at <b>join</b>. (Useful for generating a sequence of NUL-terminated + * strings.) + */ +char * +smartlist_join_strings2(smartlist_t *sl, const char *join, + size_t join_len, int terminate, size_t *len_out) +{ + int i; + size_t n = 0; + char *r = NULL, *dst, *src; + + tor_assert(sl); + tor_assert(join); + + if (terminate) + n = join_len; + + for (i = 0; i < sl->num_used; ++i) { + n += strlen(sl->list[i]); + if (i+1 < sl->num_used) /* avoid double-counting the last one */ + n += join_len; + } + dst = r = tor_malloc(n+1); + for (i = 0; i < sl->num_used; ) { + for (src = sl->list[i]; *src; ) + *dst++ = *src++; + if (++i < sl->num_used) { + memcpy(dst, join, join_len); + dst += join_len; + } + } + if (terminate) { + memcpy(dst, join, join_len); + dst += join_len; + } + *dst = '\0'; + + if (len_out) + *len_out = dst-r; + return r; +} + +/** Sort the members of <b>sl</b> into an order defined by + * the ordering function <b>compare</b>, which returns less then 0 if a + * precedes b, greater than 0 if b precedes a, and 0 if a 'equals' b. + */ +void +smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b)) +{ + if (!sl->num_used) + return; + qsort(sl->list, sl->num_used, sizeof(void*), + (int (*)(const void *,const void*))compare); +} + +/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>, + * return the most frequent member in the list. Break ties in favor of + * later elements. If the list is empty, return NULL. If count_out is + * non-null, set it to the count of the most frequent member. + */ +void * +smartlist_get_most_frequent_(const smartlist_t *sl, + int (*compare)(const void **a, const void **b), + int *count_out) +{ + const void *most_frequent = NULL; + int most_frequent_count = 0; + + const void *cur = NULL; + int i, count=0; + + if (!sl->num_used) { + if (count_out) + *count_out = 0; + return NULL; + } + for (i = 0; i < sl->num_used; ++i) { + const void *item = sl->list[i]; + if (cur && 0 == compare(&cur, &item)) { + ++count; + } else { + if (cur && count >= most_frequent_count) { + most_frequent = cur; + most_frequent_count = count; + } + cur = item; + count = 1; + } + } + if (cur && count >= most_frequent_count) { + most_frequent = cur; + most_frequent_count = count; + } + if (count_out) + *count_out = most_frequent_count; + return (void*)most_frequent; +} + +/** Given a sorted smartlist <b>sl</b> and the comparison function used to + * sort it, remove all duplicate members. If free_fn is provided, calls + * free_fn on each duplicate. Otherwise, just removes them. Preserves order. + */ +void +smartlist_uniq(smartlist_t *sl, + int (*compare)(const void **a, const void **b), + void (*free_fn)(void *a)) +{ + int i; + for (i=1; i < sl->num_used; ++i) { + if (compare((const void **)&(sl->list[i-1]), + (const void **)&(sl->list[i])) == 0) { + if (free_fn) + free_fn(sl->list[i]); + smartlist_del_keeporder(sl, i--); + } + } +} + +/** Assuming the members of <b>sl</b> are in order, return a pointer to the + * member that matches <b>key</b>. Ordering and matching are defined by a + * <b>compare</b> function that returns 0 on a match; less than 0 if key is + * less than member, and greater than 0 if key is greater then member. + */ +void * +smartlist_bsearch(smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member)) +{ + int found, idx; + idx = smartlist_bsearch_idx(sl, key, compare, &found); + return found ? smartlist_get(sl, idx) : NULL; +} + +/** Assuming the members of <b>sl</b> are in order, return the index of the + * member that matches <b>key</b>. If no member matches, return the index of + * the first member greater than <b>key</b>, or smartlist_len(sl) if no member + * is greater than <b>key</b>. Set <b>found_out</b> to true on a match, to + * false otherwise. Ordering and matching are defined by a <b>compare</b> + * function that returns 0 on a match; less than 0 if key is less than member, + * and greater than 0 if key is greater then member. + */ +int +smartlist_bsearch_idx(const smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member), + int *found_out) +{ + int hi, lo, cmp, mid, len, diff; + + tor_assert(sl); + tor_assert(compare); + tor_assert(found_out); + + len = smartlist_len(sl); + + /* Check for the trivial case of a zero-length list */ + if (len == 0) { + *found_out = 0; + /* We already know smartlist_len(sl) is 0 in this case */ + return 0; + } + + /* Okay, we have a real search to do */ + tor_assert(len > 0); + lo = 0; + hi = len - 1; + + /* + * These invariants are always true: + * + * For all i such that 0 <= i < lo, sl[i] < key + * For all i such that hi < i <= len, sl[i] > key + */ + + while (lo <= hi) { + diff = hi - lo; + /* + * We want mid = (lo + hi) / 2, but that could lead to overflow, so + * instead diff = hi - lo (non-negative because of loop condition), and + * then hi = lo + diff, mid = (lo + lo + diff) / 2 = lo + (diff / 2). + */ + mid = lo + (diff / 2); + cmp = compare(key, (const void**) &(sl->list[mid])); + if (cmp == 0) { + /* sl[mid] == key; we found it */ + *found_out = 1; + return mid; + } else if (cmp > 0) { + /* + * key > sl[mid] and an index i such that sl[i] == key must + * have i > mid if it exists. + */ + + /* + * Since lo <= mid <= hi, hi can only decrease on each iteration (by + * being set to mid - 1) and hi is initially len - 1, mid < len should + * always hold, and this is not symmetric with the left end of list + * mid > 0 test below. A key greater than the right end of the list + * should eventually lead to lo == hi == mid == len - 1, and then + * we set lo to len below and fall out to the same exit we hit for + * a key in the middle of the list but not matching. Thus, we just + * assert for consistency here rather than handle a mid == len case. + */ + tor_assert(mid < len); + /* Move lo to the element immediately after sl[mid] */ + lo = mid + 1; + } else { + /* This should always be true in this case */ + tor_assert(cmp < 0); + + /* + * key < sl[mid] and an index i such that sl[i] == key must + * have i < mid if it exists. + */ + + if (mid > 0) { + /* Normal case, move hi to the element immediately before sl[mid] */ + hi = mid - 1; + } else { + /* These should always be true in this case */ + tor_assert(mid == lo); + tor_assert(mid == 0); + /* + * We were at the beginning of the list and concluded that every + * element e compares e > key. + */ + *found_out = 0; + return 0; + } + } + } + + /* + * lo > hi; we have no element matching key but we have elements falling + * on both sides of it. The lo index points to the first element > key. + */ + tor_assert(lo == hi + 1); /* All other cases should have been handled */ + tor_assert(lo >= 0); + tor_assert(lo <= len); + tor_assert(hi >= 0); + tor_assert(hi <= len); + + if (lo < len) { + cmp = compare(key, (const void **) &(sl->list[lo])); + tor_assert(cmp < 0); + } else { + cmp = compare(key, (const void **) &(sl->list[len-1])); + tor_assert(cmp > 0); + } + + *found_out = 0; + return lo; +} + +/** Helper: compare two const char **s. */ +static int +compare_string_ptrs_(const void **_a, const void **_b) +{ + return strcmp((const char*)*_a, (const char*)*_b); +} + +/** Sort a smartlist <b>sl</b> containing strings into lexically ascending + * order. */ +void +smartlist_sort_strings(smartlist_t *sl) +{ + smartlist_sort(sl, compare_string_ptrs_); +} + +/** Return the most frequent string in the sorted list <b>sl</b> */ +const char * +smartlist_get_most_frequent_string(smartlist_t *sl) +{ + return smartlist_get_most_frequent(sl, compare_string_ptrs_); +} + +/** Return the most frequent string in the sorted list <b>sl</b>. + * If <b>count_out</b> is provided, set <b>count_out</b> to the + * number of times that string appears. + */ +const char * +smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out) +{ + return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out); +} + +/** Remove duplicate strings from a sorted list, and free them with tor_free(). + */ +void +smartlist_uniq_strings(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_string_ptrs_, tor_free_); +} + +/** Helper: compare two pointers. */ +static int +compare_ptrs_(const void **_a, const void **_b) +{ + const void *a = *_a, *b = *_b; + if (a<b) + return -1; + else if (a==b) + return 0; + else + return 1; +} + +/** Sort <b>sl</b> in ascending order of the pointers it contains. */ +void +smartlist_sort_pointers(smartlist_t *sl) +{ + smartlist_sort(sl, compare_ptrs_); +} + +/* Heap-based priority queue implementation for O(lg N) insert and remove. + * Recall that the heap property is that, for every index I, h[I] < + * H[LEFT_CHILD[I]] and h[I] < H[RIGHT_CHILD[I]]. + * + * For us to remove items other than the topmost item, each item must store + * its own index within the heap. When calling the pqueue functions, tell + * them about the offset of the field that stores the index within the item. + * + * Example: + * + * typedef struct timer_t { + * struct timeval tv; + * int heap_index; + * } timer_t; + * + * static int compare(const void *p1, const void *p2) { + * const timer_t *t1 = p1, *t2 = p2; + * if (t1->tv.tv_sec < t2->tv.tv_sec) { + * return -1; + * } else if (t1->tv.tv_sec > t2->tv.tv_sec) { + * return 1; + * } else { + * return t1->tv.tv_usec - t2->tv_usec; + * } + * } + * + * void timer_heap_insert(smartlist_t *heap, timer_t *timer) { + * smartlist_pqueue_add(heap, compare, offsetof(timer_t, heap_index), + * timer); + * } + * + * void timer_heap_pop(smartlist_t *heap) { + * return smartlist_pqueue_pop(heap, compare, + * offsetof(timer_t, heap_index)); + * } + */ + +/** @{ */ +/** Functions to manipulate heap indices to find a node's parent and children. + * + * For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x] + * = 2*x + 1. But this is C, so we have to adjust a little. */ + +/* MAX_PARENT_IDX is the largest IDX in the smartlist which might have + * children whose indices fit inside an int. + * LEFT_CHILD(MAX_PARENT_IDX) == INT_MAX-2; + * RIGHT_CHILD(MAX_PARENT_IDX) == INT_MAX-1; + * LEFT_CHILD(MAX_PARENT_IDX + 1) == INT_MAX // impossible, see max list size. + */ +#define MAX_PARENT_IDX ((INT_MAX - 2) / 2) +/* If this is true, then i is small enough to potentially have children + * in the smartlist, and it is save to use LEFT_CHILD/RIGHT_CHILD on it. */ +#define IDX_MAY_HAVE_CHILDREN(i) ((i) <= MAX_PARENT_IDX) +#define LEFT_CHILD(i) ( 2*(i) + 1 ) +#define RIGHT_CHILD(i) ( 2*(i) + 2 ) +#define PARENT(i) ( ((i)-1) / 2 ) +/** }@ */ + +/** @{ */ +/** Helper macros for heaps: Given a local variable <b>idx_field_offset</b> + * set to the offset of an integer index within the heap element structure, + * IDX_OF_ITEM(p) gives you the index of p, and IDXP(p) gives you a pointer to + * where p's index is stored. Given additionally a local smartlist <b>sl</b>, + * UPDATE_IDX(i) sets the index of the element at <b>i</b> to the correct + * value (that is, to <b>i</b>). + */ +#define IDXP(p) ((int*)STRUCT_VAR_P(p, idx_field_offset)) + +#define UPDATE_IDX(i) do { \ + void *updated = sl->list[i]; \ + *IDXP(updated) = i; \ + } while (0) + +#define IDX_OF_ITEM(p) (*IDXP(p)) +/** @} */ + +/** Helper. <b>sl</b> may have at most one violation of the heap property: + * the item at <b>idx</b> may be greater than one or both of its children. + * Restore the heap property. */ +static inline void +smartlist_heapify(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + int idx) +{ + while (1) { + if (! IDX_MAY_HAVE_CHILDREN(idx)) { + /* idx is so large that it cannot have any children, since doing so + * would mean the smartlist was over-capacity. Therefore it cannot + * violate the heap property by being greater than a child (since it + * doesn't have any). */ + return; + } + + int left_idx = LEFT_CHILD(idx); + int best_idx; + + if (left_idx >= sl->num_used) + return; + if (compare(sl->list[idx],sl->list[left_idx]) < 0) + best_idx = idx; + else + best_idx = left_idx; + if (left_idx+1 < sl->num_used && + compare(sl->list[left_idx+1],sl->list[best_idx]) < 0) + best_idx = left_idx + 1; + + if (best_idx == idx) { + return; + } else { + void *tmp = sl->list[idx]; + sl->list[idx] = sl->list[best_idx]; + sl->list[best_idx] = tmp; + UPDATE_IDX(idx); + UPDATE_IDX(best_idx); + + idx = best_idx; + } + } +} + +/** Insert <b>item</b> into the heap stored in <b>sl</b>, where order is + * determined by <b>compare</b> and the offset of the item in the heap is + * stored in an int-typed field at position <b>idx_field_offset</b> within + * item. + */ +void +smartlist_pqueue_add(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item) +{ + int idx; + smartlist_add(sl,item); + UPDATE_IDX(sl->num_used-1); + + for (idx = sl->num_used - 1; idx; ) { + int parent = PARENT(idx); + if (compare(sl->list[idx], sl->list[parent]) < 0) { + void *tmp = sl->list[parent]; + sl->list[parent] = sl->list[idx]; + sl->list[idx] = tmp; + UPDATE_IDX(parent); + UPDATE_IDX(idx); + idx = parent; + } else { + return; + } + } +} + +/** Remove and return the top-priority item from the heap stored in <b>sl</b>, + * where order is determined by <b>compare</b> and the item's position is + * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must + * not be empty. */ +void * +smartlist_pqueue_pop(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset) +{ + void *top; + tor_assert(sl->num_used); + + top = sl->list[0]; + *IDXP(top)=-1; + if (--sl->num_used) { + sl->list[0] = sl->list[sl->num_used]; + sl->list[sl->num_used] = NULL; + UPDATE_IDX(0); + smartlist_heapify(sl, compare, idx_field_offset, 0); + } + sl->list[sl->num_used] = NULL; + return top; +} + +/** Remove the item <b>item</b> from the heap stored in <b>sl</b>, + * where order is determined by <b>compare</b> and the item's position is + * stored at position <b>idx_field_offset</b> within the item. <b>sl</b> must + * not be empty. */ +void +smartlist_pqueue_remove(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item) +{ + int idx = IDX_OF_ITEM(item); + tor_assert(idx >= 0); + tor_assert(sl->list[idx] == item); + --sl->num_used; + *IDXP(item) = -1; + if (idx == sl->num_used) { + sl->list[sl->num_used] = NULL; + return; + } else { + sl->list[idx] = sl->list[sl->num_used]; + sl->list[sl->num_used] = NULL; + UPDATE_IDX(idx); + smartlist_heapify(sl, compare, idx_field_offset, idx); + } +} + +/** Assert that the heap property is correctly maintained by the heap stored + * in <b>sl</b>, where order is determined by <b>compare</b>. */ +void +smartlist_pqueue_assert_ok(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset) +{ + int i; + for (i = sl->num_used - 1; i >= 0; --i) { + if (i>0) + tor_assert(compare(sl->list[PARENT(i)], sl->list[i]) <= 0); + tor_assert(IDX_OF_ITEM(sl->list[i]) == i); + } +} + +/** Helper: compare two DIGEST_LEN digests. */ +static int +compare_digests_(const void **_a, const void **_b) +{ + return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST_LEN); +} + +/** Sort the list of DIGEST_LEN-byte digests into ascending order. */ +void +smartlist_sort_digests(smartlist_t *sl) +{ + smartlist_sort(sl, compare_digests_); +} + +/** Remove duplicate digests from a sorted list, and free them with tor_free(). + */ +void +smartlist_uniq_digests(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_digests_, tor_free_); +} + +/** Helper: compare two DIGEST256_LEN digests. */ +static int +compare_digests256_(const void **_a, const void **_b) +{ + return tor_memcmp((const char*)*_a, (const char*)*_b, DIGEST256_LEN); +} + +/** Sort the list of DIGEST256_LEN-byte digests into ascending order. */ +void +smartlist_sort_digests256(smartlist_t *sl) +{ + smartlist_sort(sl, compare_digests256_); +} + +/** Return the most frequent member of the sorted list of DIGEST256_LEN + * digests in <b>sl</b> */ +const uint8_t * +smartlist_get_most_frequent_digest256(smartlist_t *sl) +{ + return smartlist_get_most_frequent(sl, compare_digests256_); +} + +/** Remove duplicate 256-bit digests from a sorted list, and free them with + * tor_free(). + */ +void +smartlist_uniq_digests256(smartlist_t *sl) +{ + smartlist_uniq(sl, compare_digests256_, tor_free_); +} diff --git a/src/lib/container/smartlist.h b/src/lib/container/smartlist.h new file mode 100644 index 0000000000..3b19cbfce4 --- /dev/null +++ b/src/lib/container/smartlist.h @@ -0,0 +1,165 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_H +#define TOR_SMARTLIST_H + +/** + * \file smartlist.h + * + * \brief Header for smartlist.c + **/ + +#include <stdarg.h> + +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_foreach.h" +#include "lib/smartlist_core/smartlist_split.h" + +void smartlist_add_asprintf(struct smartlist_t *sl, const char *pattern, ...) + CHECK_PRINTF(2, 3); +void smartlist_add_vasprintf(struct smartlist_t *sl, const char *pattern, + va_list args) + CHECK_PRINTF(2, 0); +void smartlist_reverse(smartlist_t *sl); +void smartlist_string_remove(smartlist_t *sl, const char *element); +int smartlist_contains_string(const smartlist_t *sl, const char *element); +int smartlist_pos(const smartlist_t *sl, const void *element); +int smartlist_string_pos(const smartlist_t *, const char *elt); +int smartlist_contains_string_case(const smartlist_t *sl, const char *element); +int smartlist_contains_int_as_string(const smartlist_t *sl, int num); +int smartlist_strings_eq(const smartlist_t *sl1, const smartlist_t *sl2); +int smartlist_contains_digest(const smartlist_t *sl, const char *element); +int smartlist_ints_eq(const smartlist_t *sl1, const smartlist_t *sl2); +int smartlist_overlap(const smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2); +void smartlist_subtract(smartlist_t *sl1, const smartlist_t *sl2); + +void smartlist_sort(smartlist_t *sl, + int (*compare)(const void **a, const void **b)); +void *smartlist_get_most_frequent_(const smartlist_t *sl, + int (*compare)(const void **a, const void **b), + int *count_out); +#define smartlist_get_most_frequent(sl, compare) \ + smartlist_get_most_frequent_((sl), (compare), NULL) +void smartlist_uniq(smartlist_t *sl, + int (*compare)(const void **a, const void **b), + void (*free_fn)(void *elt)); + +void smartlist_sort_strings(smartlist_t *sl); +void smartlist_sort_digests(smartlist_t *sl); +void smartlist_sort_digests256(smartlist_t *sl); +void smartlist_sort_pointers(smartlist_t *sl); + +const char *smartlist_get_most_frequent_string(smartlist_t *sl); +const char *smartlist_get_most_frequent_string_(smartlist_t *sl, + int *count_out); +const uint8_t *smartlist_get_most_frequent_digest256(smartlist_t *sl); + +void smartlist_uniq_strings(smartlist_t *sl); +void smartlist_uniq_digests(smartlist_t *sl); +void smartlist_uniq_digests256(smartlist_t *sl); +void *smartlist_bsearch(smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member)); +int smartlist_bsearch_idx(const smartlist_t *sl, const void *key, + int (*compare)(const void *key, const void **member), + int *found_out); + +void smartlist_pqueue_add(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item); +void *smartlist_pqueue_pop(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset); +void smartlist_pqueue_remove(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset, + void *item); +void smartlist_pqueue_assert_ok(smartlist_t *sl, + int (*compare)(const void *a, const void *b), + int idx_field_offset); + +char *smartlist_join_strings(smartlist_t *sl, const char *join, int terminate, + size_t *len_out) ATTR_MALLOC; +char *smartlist_join_strings2(smartlist_t *sl, const char *join, + size_t join_len, int terminate, size_t *len_out) + ATTR_MALLOC; + +/* Helper: Given two lists of items, possibly of different types, such that + * both lists are sorted on some common field (as determined by a comparison + * expression <b>cmpexpr</b>), and such that one list (<b>sl1</b>) has no + * duplicates on the common field, loop through the lists in lockstep, and + * execute <b>unmatched_var2</b> on items in var2 that do not appear in + * var1. + * + * WARNING: It isn't safe to add remove elements from either list while the + * loop is in progress. + * + * Example use: + * SMARTLIST_FOREACH_JOIN(routerstatus_list, routerstatus_t *, rs, + * routerinfo_list, routerinfo_t *, ri, + * tor_memcmp(rs->identity_digest, ri->identity_digest, 20), + * log_info(LD_GENERAL,"No match for %s", ri->nickname)) { + * log_info(LD_GENERAL, "%s matches routerstatus %p", ri->nickname, rs); + * } SMARTLIST_FOREACH_JOIN_END(rs, ri); + **/ +/* The example above unpacks (approximately) to: + * int rs_sl_idx = 0, rs_sl_len = smartlist_len(routerstatus_list); + * int ri_sl_idx, ri_sl_len = smartlist_len(routerinfo_list); + * int rs_ri_cmp; + * routerstatus_t *rs; + * routerinfo_t *ri; + * for (; ri_sl_idx < ri_sl_len; ++ri_sl_idx) { + * ri = smartlist_get(routerinfo_list, ri_sl_idx); + * while (rs_sl_idx < rs_sl_len) { + * rs = smartlist_get(routerstatus_list, rs_sl_idx); + * rs_ri_cmp = tor_memcmp(rs->identity_digest, ri->identity_digest, 20); + * if (rs_ri_cmp > 0) { + * break; + * } else if (rs_ri_cmp == 0) { + * goto matched_ri; + * } else { + * ++rs_sl_idx; + * } + * } + * log_info(LD_GENERAL,"No match for %s", ri->nickname); + * continue; + * matched_ri: { + * log_info(LD_GENERAL,"%s matches with routerstatus %p",ri->nickname,rs); + * } + * } + */ +#define SMARTLIST_FOREACH_JOIN(sl1, type1, var1, sl2, type2, var2, \ + cmpexpr, unmatched_var2) \ + STMT_BEGIN \ + int var1 ## _sl_idx = 0, var1 ## _sl_len=(sl1)->num_used; \ + int var2 ## _sl_idx = 0, var2 ## _sl_len=(sl2)->num_used; \ + int var1 ## _ ## var2 ## _cmp; \ + type1 var1; \ + type2 var2; \ + for (; var2##_sl_idx < var2##_sl_len; ++var2##_sl_idx) { \ + var2 = (sl2)->list[var2##_sl_idx]; \ + while (var1##_sl_idx < var1##_sl_len) { \ + var1 = (sl1)->list[var1##_sl_idx]; \ + var1##_##var2##_cmp = (cmpexpr); \ + if (var1##_##var2##_cmp > 0) { \ + break; \ + } else if (var1##_##var2##_cmp == 0) { \ + goto matched_##var2; \ + } else { \ + ++var1##_sl_idx; \ + } \ + } \ + /* Ran out of v1, or no match for var2. */ \ + unmatched_var2; \ + continue; \ + matched_##var2: ; \ + +#define SMARTLIST_FOREACH_JOIN_END(var1, var2) \ + } \ + STMT_END + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/crypt_ops/.may_include b/src/lib/crypt_ops/.may_include new file mode 100644 index 0000000000..a0fa4ec05c --- /dev/null +++ b/src/lib/crypt_ops/.may_include @@ -0,0 +1,24 @@ +orconfig.h +lib/arch/*.h +lib/cc/*.h +lib/container/*.h +lib/crypt_ops/*.h +lib/ctime/*.h +lib/defs/*.h +lib/encoding/*.h +lib/fs/*.h +lib/lock/*.h +lib/malloc/*.h +lib/intmath/*.h +lib/sandbox/*.h +lib/string/*.h +lib/testsupport/testsupport.h +lib/thread/*.h +lib/log/*.h + +trunnel/pwbox.h + +keccak-tiny/*.h +ed25519/*.h + +siphash.h diff --git a/src/common/aes.c b/src/lib/crypt_ops/aes.c index 86f3472bfd..a01b1e16b2 100644 --- a/src/common/aes.c +++ b/src/lib/crypt_ops/aes.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,15 +10,17 @@ **/ #include "orconfig.h" +#include "lib/crypt_ops/aes.h" +#include "lib/log/util_bug.h" #ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ #include <winsock2.h> #include <ws2tcpip.h> #endif -#include "compat_openssl.h" +#include "lib/crypt_ops/compat_openssl.h" #include <openssl/opensslv.h> -#include "crypto_openssl_mgt.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" #if OPENSSL_VERSION_NUMBER < OPENSSL_V_SERIES(1,0,0) #error "We require OpenSSL >= 1.0.0" @@ -26,7 +28,6 @@ DISABLE_GCC_WARNING(redundant-decls) -#include <assert.h> #include <stdlib.h> #include <string.h> #include <openssl/aes.h> @@ -36,11 +37,9 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) -#include "compat.h" -#include "aes.h" -#include "util.h" -#include "torlog.h" -#include "di_ops.h" +#include "lib/crypt_ops/aes.h" +#include "lib/log/torlog.h" +#include "lib/ctime/di_ops.h" #ifdef ANDROID /* Android's OpenSSL seems to have removed all of its Engine support. */ @@ -407,4 +406,3 @@ aes_set_iv(aes_cnt_cipher_t *cipher, const uint8_t *iv) } #endif /* defined(USE_EVP_AES_CTR) */ - diff --git a/src/common/aes.h b/src/lib/crypt_ops/aes.h index 0b17cd55a4..a57654159a 100644 --- a/src/common/aes.h +++ b/src/lib/crypt_ops/aes.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Implements a minimal interface to counter-mode AES. */ @@ -13,6 +13,9 @@ * \brief Headers for aes.c */ +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + typedef struct aes_cnt_cipher aes_cnt_cipher_t; aes_cnt_cipher_t* aes_new_cipher(const uint8_t *key, const uint8_t *iv, @@ -26,4 +29,3 @@ int evaluate_evp_for_aes(int force_value); int evaluate_ctr_for_aes(void); #endif /* !defined(TOR_AES_H) */ - diff --git a/src/common/compat_openssl.h b/src/lib/crypt_ops/compat_openssl.h index d1481fb46c..317c01134a 100644 --- a/src/common/compat_openssl.h +++ b/src/lib/crypt_ops/compat_openssl.h @@ -1,14 +1,14 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_COMPAT_OPENSSL_H #define TOR_COMPAT_OPENSSL_H #include <openssl/opensslv.h> -#include "crypto_openssl_mgt.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" /** * \file compat_openssl.h diff --git a/src/lib/crypt_ops/crypto.c b/src/lib/crypt_ops/crypto.c new file mode 100644 index 0000000000..48574016bf --- /dev/null +++ b/src/lib/crypt_ops/crypto.c @@ -0,0 +1,509 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto.c + * \brief Wrapper functions to present a consistent interface to + * public-key and symmetric cryptography operations from OpenSSL and + * other places. + **/ + +#include "orconfig.h" + +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#include <wincrypt.h> +/* Windows defines this; so does OpenSSL 0.9.8h and later. We don't actually + * use either definition. */ +#undef OCSP_RESPONSE +#endif /* defined(_WIN32) */ + +#define CRYPTO_PRIVATE +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_rsa.h" +#include "lib/crypt_ops/crypto_util.h" + +DISABLE_GCC_WARNING(redundant-decls) + +#include <openssl/err.h> +#include <openssl/evp.h> +#include <openssl/engine.h> +#include <openssl/bn.h> +#include <openssl/dh.h> +#include <openssl/conf.h> +#include <openssl/hmac.h> +#include <openssl/ssl.h> + +ENABLE_GCC_WARNING(redundant-decls) + +#if __GNUC__ && GCC_VERSION >= 402 +#if GCC_VERSION >= 406 +#pragma GCC diagnostic pop +#else +#pragma GCC diagnostic warning "-Wredundant-decls" +#endif +#endif /* __GNUC__ && GCC_VERSION >= 402 */ + +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/aes.h" +#include "lib/encoding/binascii.h" + +#include "keccak-tiny/keccak-tiny.h" + +#include "siphash.h" + +#include <string.h> + +/** Boolean: has OpenSSL's crypto been initialized? */ +static int crypto_early_initialized_ = 0; + +/** Boolean: has OpenSSL's crypto been initialized? */ +static int crypto_global_initialized_ = 0; + +#ifndef DISABLE_ENGINES +/** Log any OpenSSL engines we're using at NOTICE. */ +static void +log_engine(const char *fn, ENGINE *e) +{ + if (e) { + const char *name, *id; + name = ENGINE_get_name(e); + id = ENGINE_get_id(e); + log_notice(LD_CRYPTO, "Default OpenSSL engine for %s is %s [%s]", + fn, name?name:"?", id?id:"?"); + } else { + log_info(LD_CRYPTO, "Using default implementation for %s", fn); + } +} +#endif /* !defined(DISABLE_ENGINES) */ + +#ifndef DISABLE_ENGINES +/** Try to load an engine in a shared library via fully qualified path. + */ +static ENGINE * +try_load_engine(const char *path, const char *engine) +{ + ENGINE *e = ENGINE_by_id("dynamic"); + if (e) { + if (!ENGINE_ctrl_cmd_string(e, "ID", engine, 0) || + !ENGINE_ctrl_cmd_string(e, "DIR_LOAD", "2", 0) || + !ENGINE_ctrl_cmd_string(e, "DIR_ADD", path, 0) || + !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) { + ENGINE_free(e); + e = NULL; + } + } + return e; +} +#endif /* !defined(DISABLE_ENGINES) */ + +static int have_seeded_siphash = 0; + +/** Set up the siphash key if we haven't already done so. */ +int +crypto_init_siphash_key(void) +{ + struct sipkey key; + if (have_seeded_siphash) + return 0; + + crypto_rand((char*) &key, sizeof(key)); + siphash_set_global_key(&key); + have_seeded_siphash = 1; + return 0; +} + +/** Initialize the crypto library. Return 0 on success, -1 on failure. + */ +int +crypto_early_init(void) +{ + if (!crypto_early_initialized_) { + + crypto_early_initialized_ = 1; + +#ifdef OPENSSL_1_1_API + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS | + OPENSSL_INIT_LOAD_CRYPTO_STRINGS | + OPENSSL_INIT_ADD_ALL_CIPHERS | + OPENSSL_INIT_ADD_ALL_DIGESTS, NULL); +#else + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); +#endif + + setup_openssl_threading(); + + unsigned long version_num = OpenSSL_version_num(); + const char *version_str = OpenSSL_version(OPENSSL_VERSION); + if (version_num == OPENSSL_VERSION_NUMBER && + !strcmp(version_str, OPENSSL_VERSION_TEXT)) { + log_info(LD_CRYPTO, "OpenSSL version matches version from headers " + "(%lx: %s).", version_num, version_str); + } else { + log_warn(LD_CRYPTO, "OpenSSL version from headers does not match the " + "version we're running with. If you get weird crashes, that " + "might be why. (Compiled with %lx: %s; running with %lx: %s).", + (unsigned long)OPENSSL_VERSION_NUMBER, OPENSSL_VERSION_TEXT, + version_num, version_str); + } + + crypto_force_rand_ssleay(); + + if (crypto_seed_rng() < 0) + return -1; + if (crypto_init_siphash_key() < 0) + return -1; + + curve25519_init(); + ed25519_init(); + } + return 0; +} + +/** Initialize the crypto library. Return 0 on success, -1 on failure. + */ +int +crypto_global_init(int useAccel, const char *accelName, const char *accelDir) +{ + if (!crypto_global_initialized_) { + if (crypto_early_init() < 0) + return -1; + + crypto_global_initialized_ = 1; + + if (useAccel > 0) { +#ifdef DISABLE_ENGINES + (void)accelName; + (void)accelDir; + log_warn(LD_CRYPTO, "No OpenSSL hardware acceleration support enabled."); +#else + ENGINE *e = NULL; + + log_info(LD_CRYPTO, "Initializing OpenSSL engine support."); + ENGINE_load_builtin_engines(); + ENGINE_register_all_complete(); + + if (accelName) { + if (accelDir) { + log_info(LD_CRYPTO, "Trying to load dynamic OpenSSL engine \"%s\"" + " via path \"%s\".", accelName, accelDir); + e = try_load_engine(accelName, accelDir); + } else { + log_info(LD_CRYPTO, "Initializing dynamic OpenSSL engine \"%s\"" + " acceleration support.", accelName); + e = ENGINE_by_id(accelName); + } + if (!e) { + log_warn(LD_CRYPTO, "Unable to load dynamic OpenSSL engine \"%s\".", + accelName); + } else { + log_info(LD_CRYPTO, "Loaded dynamic OpenSSL engine \"%s\".", + accelName); + } + } + if (e) { + log_info(LD_CRYPTO, "Loaded OpenSSL hardware acceleration engine," + " setting default ciphers."); + ENGINE_set_default(e, ENGINE_METHOD_ALL); + } + /* Log, if available, the intersection of the set of algorithms + used by Tor and the set of algorithms available in the engine */ + log_engine("RSA", ENGINE_get_default_RSA()); + log_engine("DH", ENGINE_get_default_DH()); +#ifdef OPENSSL_1_1_API + log_engine("EC", ENGINE_get_default_EC()); +#else + log_engine("ECDH", ENGINE_get_default_ECDH()); + log_engine("ECDSA", ENGINE_get_default_ECDSA()); +#endif /* defined(OPENSSL_1_1_API) */ + log_engine("RAND", ENGINE_get_default_RAND()); + log_engine("RAND (which we will not use)", ENGINE_get_default_RAND()); + log_engine("SHA1", ENGINE_get_digest_engine(NID_sha1)); + log_engine("3DES-CBC", ENGINE_get_cipher_engine(NID_des_ede3_cbc)); + log_engine("AES-128-ECB", ENGINE_get_cipher_engine(NID_aes_128_ecb)); + log_engine("AES-128-CBC", ENGINE_get_cipher_engine(NID_aes_128_cbc)); +#ifdef NID_aes_128_ctr + log_engine("AES-128-CTR", ENGINE_get_cipher_engine(NID_aes_128_ctr)); +#endif +#ifdef NID_aes_128_gcm + log_engine("AES-128-GCM", ENGINE_get_cipher_engine(NID_aes_128_gcm)); +#endif + log_engine("AES-256-CBC", ENGINE_get_cipher_engine(NID_aes_256_cbc)); +#ifdef NID_aes_256_gcm + log_engine("AES-256-GCM", ENGINE_get_cipher_engine(NID_aes_256_gcm)); +#endif + +#endif /* defined(DISABLE_ENGINES) */ + } else { + log_info(LD_CRYPTO, "NOT using OpenSSL engine support."); + } + + if (crypto_force_rand_ssleay()) { + if (crypto_seed_rng() < 0) + return -1; + } + + evaluate_evp_for_aes(-1); + evaluate_ctr_for_aes(); + } + return 0; +} + +/** Free crypto resources held by this thread. */ +void +crypto_thread_cleanup(void) +{ +#ifndef NEW_THREAD_API + ERR_remove_thread_state(NULL); +#endif +} + +/** Allocate and return a new symmetric cipher using the provided key and iv. + * The key is <b>bits</b> bits long; the IV is CIPHER_IV_LEN bytes. Both + * must be provided. Key length must be 128, 192, or 256 */ +crypto_cipher_t * +crypto_cipher_new_with_iv_and_bits(const uint8_t *key, + const uint8_t *iv, + int bits) +{ + tor_assert(key); + tor_assert(iv); + + return aes_new_cipher((const uint8_t*)key, (const uint8_t*)iv, bits); +} + +/** Allocate and return a new symmetric cipher using the provided key and iv. + * The key is CIPHER_KEY_LEN bytes; the IV is CIPHER_IV_LEN bytes. Both + * must be provided. + */ +crypto_cipher_t * +crypto_cipher_new_with_iv(const char *key, const char *iv) +{ + return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)iv, + 128); +} + +/** Return a new crypto_cipher_t with the provided <b>key</b> and an IV of all + * zero bytes and key length <b>bits</b>. Key length must be 128, 192, or + * 256. */ +crypto_cipher_t * +crypto_cipher_new_with_bits(const char *key, int bits) +{ + char zeroiv[CIPHER_IV_LEN]; + memset(zeroiv, 0, sizeof(zeroiv)); + return crypto_cipher_new_with_iv_and_bits((uint8_t*)key, (uint8_t*)zeroiv, + bits); +} + +/** Return a new crypto_cipher_t with the provided <b>key</b> (of + * CIPHER_KEY_LEN bytes) and an IV of all zero bytes. */ +crypto_cipher_t * +crypto_cipher_new(const char *key) +{ + return crypto_cipher_new_with_bits(key, 128); +} + +/** Free a symmetric cipher. + */ +void +crypto_cipher_free_(crypto_cipher_t *env) +{ + if (!env) + return; + + aes_cipher_free(env); +} + +/** Copy <b>in</b> to the <b>outlen</b>-byte buffer <b>out</b>, adding spaces + * every four characters. */ +void +crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in) +{ + int n = 0; + char *end = out+outlen; + tor_assert(outlen < SIZE_T_CEILING); + + while (*in && out<end) { + *out++ = *in++; + if (++n == 4 && *in && out<end) { + n = 0; + *out++ = ' '; + } + } + tor_assert(out<end); + *out = '\0'; +} + +/* symmetric crypto */ + +/** Encrypt <b>fromlen</b> bytes from <b>from</b> using the cipher + * <b>env</b>; on success, store the result to <b>to</b> and return 0. + * Does not check for failure. + */ +int +crypto_cipher_encrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen) +{ + tor_assert(env); + tor_assert(env); + tor_assert(from); + tor_assert(fromlen); + tor_assert(to); + tor_assert(fromlen < SIZE_T_CEILING); + + memcpy(to, from, fromlen); + aes_crypt_inplace(env, to, fromlen); + return 0; +} + +/** Decrypt <b>fromlen</b> bytes from <b>from</b> using the cipher + * <b>env</b>; on success, store the result to <b>to</b> and return 0. + * Does not check for failure. + */ +int +crypto_cipher_decrypt(crypto_cipher_t *env, char *to, + const char *from, size_t fromlen) +{ + tor_assert(env); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < SIZE_T_CEILING); + + memcpy(to, from, fromlen); + aes_crypt_inplace(env, to, fromlen); + return 0; +} + +/** Encrypt <b>len</b> bytes on <b>from</b> using the cipher in <b>env</b>; + * on success. Does not check for failure. + */ +void +crypto_cipher_crypt_inplace(crypto_cipher_t *env, char *buf, size_t len) +{ + tor_assert(len < SIZE_T_CEILING); + aes_crypt_inplace(env, buf, len); +} + +/** Encrypt <b>fromlen</b> bytes (at least 1) from <b>from</b> with the key in + * <b>key</b> to the buffer in <b>to</b> of length + * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> plus + * CIPHER_IV_LEN bytes for the initialization vector. On success, return the + * number of bytes written, on failure, return -1. + */ +int +crypto_cipher_encrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen) +{ + crypto_cipher_t *cipher; + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + + if (fromlen < 1) + return -1; + if (tolen < fromlen + CIPHER_IV_LEN) + return -1; + + char iv[CIPHER_IV_LEN]; + crypto_rand(iv, sizeof(iv)); + cipher = crypto_cipher_new_with_iv(key, iv); + + memcpy(to, iv, CIPHER_IV_LEN); + crypto_cipher_encrypt(cipher, to+CIPHER_IV_LEN, from, fromlen); + crypto_cipher_free(cipher); + memwipe(iv, 0, sizeof(iv)); + return (int)(fromlen + CIPHER_IV_LEN); +} + +/** Decrypt <b>fromlen</b> bytes (at least 1+CIPHER_IV_LEN) from <b>from</b> + * with the key in <b>key</b> to the buffer in <b>to</b> of length + * <b>tolen</b>. <b>tolen</b> must be at least <b>fromlen</b> minus + * CIPHER_IV_LEN bytes for the initialization vector. On success, return the + * number of bytes written, on failure, return -1. + */ +int +crypto_cipher_decrypt_with_iv(const char *key, + char *to, size_t tolen, + const char *from, size_t fromlen) +{ + crypto_cipher_t *cipher; + tor_assert(key); + tor_assert(from); + tor_assert(to); + tor_assert(fromlen < INT_MAX); + + if (fromlen <= CIPHER_IV_LEN) + return -1; + if (tolen < fromlen - CIPHER_IV_LEN) + return -1; + + cipher = crypto_cipher_new_with_iv(key, from); + + crypto_cipher_encrypt(cipher, to, from+CIPHER_IV_LEN, fromlen-CIPHER_IV_LEN); + crypto_cipher_free(cipher); + return (int)(fromlen - CIPHER_IV_LEN); +} + +/** @{ */ +/** Uninitialize the crypto library. Return 0 on success. Does not detect + * failure. + */ +int +crypto_global_cleanup(void) +{ +#ifndef OPENSSL_1_1_API + EVP_cleanup(); +#endif +#ifndef NEW_THREAD_API + ERR_remove_thread_state(NULL); +#endif +#ifndef OPENSSL_1_1_API + ERR_free_strings(); +#endif + + crypto_dh_free_all(); + +#ifndef DISABLE_ENGINES +#ifndef OPENSSL_1_1_API + ENGINE_cleanup(); +#endif +#endif + + CONF_modules_unload(1); +#ifndef OPENSSL_1_1_API + CRYPTO_cleanup_all_ex_data(); +#endif + + crypto_openssl_free_all(); + + crypto_early_initialized_ = 0; + crypto_global_initialized_ = 0; + have_seeded_siphash = 0; + siphash_unset_global_key(); + + return 0; +} + +/** @} */ diff --git a/src/common/crypto.h b/src/lib/crypt_ops/crypto.h index c773557310..3a0b330be6 100644 --- a/src/common/crypto.h +++ b/src/lib/crypt_ops/crypto.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,10 +16,8 @@ #include "orconfig.h" #include <stdio.h> -#include "torint.h" -#include "compat.h" -#include "util.h" -#include "crypto_rsa.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_rsa.h" /** Length of our symmetric cipher's keys of 128-bit. */ #define CIPHER_KEY_LEN 16 @@ -27,15 +25,12 @@ #define CIPHER_IV_LEN 16 /** Length of our symmetric cipher's keys of 256-bit. */ #define CIPHER256_KEY_LEN 32 -/** Length of our DH keys. */ -#define DH_BYTES (1024/8) /** Length of encoded public key fingerprints, including space; but not * including terminating NUL. */ #define FINGERPRINT_LEN 49 typedef struct aes_cnt_cipher crypto_cipher_t; -typedef struct crypto_dh_t crypto_dh_t; /* global state */ int crypto_init_siphash_key(void); @@ -43,15 +38,11 @@ int crypto_early_init(void) ATTR_WUR; int crypto_global_init(int hardwareAccel, const char *accelName, const char *accelPath) ATTR_WUR; -#ifdef USE_DMALLOC -int crypto_use_tor_alloc_functions(void); -#endif void crypto_thread_cleanup(void); int crypto_global_cleanup(void); /* environment setup */ -void crypto_set_tls_dh_prime(void); crypto_cipher_t *crypto_cipher_new(const char *key); crypto_cipher_t *crypto_cipher_new_with_bits(const char *key, int bits); crypto_cipher_t *crypto_cipher_new_with_iv(const char *key, const char *iv); @@ -78,37 +69,6 @@ int crypto_cipher_decrypt_with_iv(const char *key, char *to, size_t tolen, const char *from, size_t fromlen); -/* Key negotiation */ -#define DH_TYPE_CIRCUIT 1 -#define DH_TYPE_REND 2 -#define DH_TYPE_TLS 3 -crypto_dh_t *crypto_dh_new(int dh_type); -crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh); -int crypto_dh_get_bytes(crypto_dh_t *dh); -int crypto_dh_generate_public(crypto_dh_t *dh); -int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, - size_t pubkey_out_len); -ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, - const char *pubkey, size_t pubkey_len, - char *secret_out, size_t secret_out_len); -void crypto_dh_free_(crypto_dh_t *dh); -#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh)) - -int crypto_expand_key_material_TAP(const uint8_t *key_in, - size_t key_in_len, - uint8_t *key_out, size_t key_out_len); -int crypto_expand_key_material_rfc5869_sha256( - const uint8_t *key_in, size_t key_in_len, - const uint8_t *salt_in, size_t salt_in_len, - const uint8_t *info_in, size_t info_in_len, - uint8_t *key_out, size_t key_out_len); - -/* Prototypes for private functions only used by tortls.c, crypto.c, and the - * unit tests. */ -struct dh_st; -struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); - void crypto_add_spaces_to_fp(char *out, size_t outlen, const char *in); #endif /* !defined(TOR_CRYPTO_H) */ - diff --git a/src/common/crypto_curve25519.c b/src/lib/crypt_ops/crypto_curve25519.c index 996d94c6e2..09f492e544 100644 --- a/src/common/crypto_curve25519.c +++ b/src/lib/crypt_ops/crypto_curve25519.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -20,17 +20,19 @@ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif -#include "container.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "util.h" -#include "torlog.h" +#include "lib/ctime/di_ops.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" #include "ed25519/donna/ed25519_donna_tor.h" +#include <string.h> + /* ============================== Part 1: wrap a suitable curve25519 implementation as curve25519_impl ============================== */ @@ -356,4 +358,3 @@ curve25519_init(void) { pick_curve25519_basepoint_impl(); } - diff --git a/src/common/crypto_curve25519.h b/src/lib/crypt_ops/crypto_curve25519.h index 4834fa0836..acb36fde3b 100644 --- a/src/common/crypto_curve25519.h +++ b/src/lib/crypt_ops/crypto_curve25519.h @@ -1,20 +1,14 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CRYPTO_CURVE25519_H #define TOR_CRYPTO_CURVE25519_H -#include "testsupport.h" -#include "torint.h" -#include "crypto_digest.h" -#include "crypto_openssl_mgt.h" - -/** Length of a curve25519 public key when encoded. */ -#define CURVE25519_PUBKEY_LEN 32 -/** Length of a curve25519 secret key when encoded. */ -#define CURVE25519_SECKEY_LEN 32 -/** Length of the result of a curve25519 handshake. */ -#define CURVE25519_OUTPUT_LEN 32 +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" +#include "lib/defs/x25519_sizes.h" /** Wrapper type for a curve25519 public key. * @@ -75,8 +69,6 @@ STATIC int curve25519_impl(uint8_t *output, const uint8_t *secret, STATIC int curve25519_basepoint_impl(uint8_t *output, const uint8_t *secret); #endif /* defined(CRYPTO_CURVE25519_PRIVATE) */ -#define CURVE25519_BASE64_PADDED_LEN 44 - int curve25519_public_from_base64(curve25519_public_key_t *pkey, const char *input); int curve25519_public_to_base64(char *output, @@ -86,4 +78,3 @@ void curve25519_set_impl_params(int use_ed); void curve25519_init(void); #endif /* !defined(TOR_CRYPTO_CURVE25519_H) */ - diff --git a/src/lib/crypt_ops/crypto_dh.c b/src/lib/crypt_ops/crypto_dh.c new file mode 100644 index 0000000000..c37e286daf --- /dev/null +++ b/src/lib/crypt_ops/crypto_dh.c @@ -0,0 +1,511 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_dh.c + * \brief Block of functions related with DH utilities and operations. + **/ + +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +DISABLE_GCC_WARNING(redundant-decls) + +#include <openssl/dh.h> + +ENABLE_GCC_WARNING(redundant-decls) + +#include <openssl/bn.h> +#include <string.h> + +/** A structure to hold the first half (x, g^x) of a Diffie-Hellman handshake + * while we're waiting for the second.*/ +struct crypto_dh_t { + DH *dh; /**< The openssl DH object */ +}; + +static int tor_check_dh_key(int severity, const BIGNUM *bn); + +/** Used by tortls.c: Get the DH* from a crypto_dh_t. + */ +DH * +crypto_dh_get_dh_(crypto_dh_t *dh) +{ + return dh->dh; +} + +/** Our DH 'g' parameter */ +#define DH_GENERATOR 2 + +/** Shared P parameter for our circuit-crypto DH key exchanges. */ +static BIGNUM *dh_param_p = NULL; +/** Shared P parameter for our TLS DH key exchanges. */ +static BIGNUM *dh_param_p_tls = NULL; +/** Shared G parameter for our DH key exchanges. */ +static BIGNUM *dh_param_g = NULL; + +/** Validate a given set of Diffie-Hellman parameters. This is moderately + * computationally expensive (milliseconds), so should only be called when + * the DH parameters change. Returns 0 on success, * -1 on failure. + */ +static int +crypto_validate_dh_params(const BIGNUM *p, const BIGNUM *g) +{ + DH *dh = NULL; + int ret = -1; + + /* Copy into a temporary DH object, just so that DH_check() can be called. */ + if (!(dh = DH_new())) + goto out; +#ifdef OPENSSL_1_1_API + BIGNUM *dh_p, *dh_g; + if (!(dh_p = BN_dup(p))) + goto out; + if (!(dh_g = BN_dup(g))) + goto out; + if (!DH_set0_pqg(dh, dh_p, NULL, dh_g)) + goto out; +#else /* !(defined(OPENSSL_1_1_API)) */ + if (!(dh->p = BN_dup(p))) + goto out; + if (!(dh->g = BN_dup(g))) + goto out; +#endif /* defined(OPENSSL_1_1_API) */ + + /* Perform the validation. */ + int codes = 0; + if (!DH_check(dh, &codes)) + goto out; + if (BN_is_word(g, DH_GENERATOR_2)) { + /* Per https://wiki.openssl.org/index.php/Diffie-Hellman_parameters + * + * OpenSSL checks the prime is congruent to 11 when g = 2; while the + * IETF's primes are congruent to 23 when g = 2. + */ + BN_ULONG residue = BN_mod_word(p, 24); + if (residue == 11 || residue == 23) + codes &= ~DH_NOT_SUITABLE_GENERATOR; + } + if (codes != 0) /* Specifics on why the params suck is irrelevant. */ + goto out; + + /* Things are probably not evil. */ + ret = 0; + + out: + if (dh) + DH_free(dh); + return ret; +} + +/** Set the global Diffie-Hellman generator, used for both TLS and internal + * DH stuff. + */ +static void +crypto_set_dh_generator(void) +{ + BIGNUM *generator; + int r; + + if (dh_param_g) + return; + + generator = BN_new(); + tor_assert(generator); + + r = BN_set_word(generator, DH_GENERATOR); + tor_assert(r); + + dh_param_g = generator; +} + +/** Set the global TLS Diffie-Hellman modulus. Use the Apache mod_ssl DH + * modulus. */ +void +crypto_set_tls_dh_prime(void) +{ + BIGNUM *tls_prime = NULL; + int r; + + /* If the space is occupied, free the previous TLS DH prime */ + if (BUG(dh_param_p_tls)) { + /* LCOV_EXCL_START + * + * We shouldn't be calling this twice. + */ + BN_clear_free(dh_param_p_tls); + dh_param_p_tls = NULL; + /* LCOV_EXCL_STOP */ + } + + tls_prime = BN_new(); + tor_assert(tls_prime); + + /* This is the 1024-bit safe prime that Apache uses for its DH stuff; see + * modules/ssl/ssl_engine_dh.c; Apache also uses a generator of 2 with this + * prime. + */ + r = BN_hex2bn(&tls_prime, + "D67DE440CBBBDC1936D693D34AFD0AD50C84D239A45F520BB88174CB98" + "BCE951849F912E639C72FB13B4B4D7177E16D55AC179BA420B2A29FE324A" + "467A635E81FF5901377BEDDCFD33168A461AAD3B72DAE8860078045B07A7" + "DBCA7874087D1510EA9FCC9DDD330507DD62DB88AEAA747DE0F4D6E2BD68" + "B0E7393E0F24218EB3"); + tor_assert(r); + + tor_assert(tls_prime); + + dh_param_p_tls = tls_prime; + crypto_set_dh_generator(); + tor_assert(0 == crypto_validate_dh_params(dh_param_p_tls, dh_param_g)); +} + +/** Initialize dh_param_p and dh_param_g if they are not already + * set. */ +static void +init_dh_param(void) +{ + BIGNUM *circuit_dh_prime; + int r; + if (BUG(dh_param_p && dh_param_g)) + return; // LCOV_EXCL_LINE This function isn't supposed to be called twice. + + circuit_dh_prime = BN_new(); + tor_assert(circuit_dh_prime); + + /* This is from rfc2409, section 6.2. It's a safe prime, and + supposedly it equals: + 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }. + */ + r = BN_hex2bn(&circuit_dh_prime, + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" + "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" + "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" + "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" + "49286651ECE65381FFFFFFFFFFFFFFFF"); + tor_assert(r); + + /* Set the new values as the global DH parameters. */ + dh_param_p = circuit_dh_prime; + crypto_set_dh_generator(); + tor_assert(0 == crypto_validate_dh_params(dh_param_p, dh_param_g)); + + if (!dh_param_p_tls) { + crypto_set_tls_dh_prime(); + } +} + +/** Number of bits to use when choosing the x or y value in a Diffie-Hellman + * handshake. Since we exponentiate by this value, choosing a smaller one + * lets our handhake go faster. + */ +#define DH_PRIVATE_KEY_BITS 320 + +/** Allocate and return a new DH object for a key exchange. Returns NULL on + * failure. + */ +crypto_dh_t * +crypto_dh_new(int dh_type) +{ + crypto_dh_t *res = tor_malloc_zero(sizeof(crypto_dh_t)); + + tor_assert(dh_type == DH_TYPE_CIRCUIT || dh_type == DH_TYPE_TLS || + dh_type == DH_TYPE_REND); + + if (!dh_param_p) + init_dh_param(); + + if (!(res->dh = DH_new())) + goto err; + +#ifdef OPENSSL_1_1_API + BIGNUM *dh_p = NULL, *dh_g = NULL; + + if (dh_type == DH_TYPE_TLS) { + dh_p = BN_dup(dh_param_p_tls); + } else { + dh_p = BN_dup(dh_param_p); + } + if (!dh_p) + goto err; + + dh_g = BN_dup(dh_param_g); + if (!dh_g) { + BN_free(dh_p); + goto err; + } + + if (!DH_set0_pqg(res->dh, dh_p, NULL, dh_g)) { + goto err; + } + + if (!DH_set_length(res->dh, DH_PRIVATE_KEY_BITS)) + goto err; +#else /* !(defined(OPENSSL_1_1_API)) */ + if (dh_type == DH_TYPE_TLS) { + if (!(res->dh->p = BN_dup(dh_param_p_tls))) + goto err; + } else { + if (!(res->dh->p = BN_dup(dh_param_p))) + goto err; + } + + if (!(res->dh->g = BN_dup(dh_param_g))) + goto err; + + res->dh->length = DH_PRIVATE_KEY_BITS; +#endif /* defined(OPENSSL_1_1_API) */ + + return res; + + /* LCOV_EXCL_START + * This error condition is only reached when an allocation fails */ + err: + crypto_log_errors(LOG_WARN, "creating DH object"); + if (res->dh) DH_free(res->dh); /* frees p and g too */ + tor_free(res); + return NULL; + /* LCOV_EXCL_STOP */ +} + +/** Return a copy of <b>dh</b>, sharing its internal state. */ +crypto_dh_t * +crypto_dh_dup(const crypto_dh_t *dh) +{ + crypto_dh_t *dh_new = tor_malloc_zero(sizeof(crypto_dh_t)); + tor_assert(dh); + tor_assert(dh->dh); + dh_new->dh = dh->dh; + DH_up_ref(dh->dh); + return dh_new; +} + +/** Return the length of the DH key in <b>dh</b>, in bytes. + */ +int +crypto_dh_get_bytes(crypto_dh_t *dh) +{ + tor_assert(dh); + return DH_size(dh->dh); +} + +/** Generate \<x,g^x\> for our part of the key exchange. Return 0 on + * success, -1 on failure. + */ +int +crypto_dh_generate_public(crypto_dh_t *dh) +{ +#ifndef OPENSSL_1_1_API + again: +#endif + if (!DH_generate_key(dh->dh)) { + /* LCOV_EXCL_START + * To test this we would need some way to tell openssl to break DH. */ + crypto_log_errors(LOG_WARN, "generating DH key"); + return -1; + /* LCOV_EXCL_STOP */ + } +#ifdef OPENSSL_1_1_API + /* OpenSSL 1.1.x doesn't appear to let you regenerate a DH key, without + * recreating the DH object. I have no idea what sort of aliasing madness + * can occur here, so do the check, and just bail on failure. + */ + const BIGNUM *pub_key, *priv_key; + DH_get0_key(dh->dh, &pub_key, &priv_key); + if (tor_check_dh_key(LOG_WARN, pub_key)<0) { + log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" + "the-universe chances really do happen. Treating as a failure."); + return -1; + } +#else /* !(defined(OPENSSL_1_1_API)) */ + if (tor_check_dh_key(LOG_WARN, dh->dh->pub_key)<0) { + /* LCOV_EXCL_START + * If this happens, then openssl's DH implementation is busted. */ + log_warn(LD_CRYPTO, "Weird! Our own DH key was invalid. I guess once-in-" + "the-universe chances really do happen. Trying again."); + /* Free and clear the keys, so OpenSSL will actually try again. */ + BN_clear_free(dh->dh->pub_key); + BN_clear_free(dh->dh->priv_key); + dh->dh->pub_key = dh->dh->priv_key = NULL; + goto again; + /* LCOV_EXCL_STOP */ + } +#endif /* defined(OPENSSL_1_1_API) */ + return 0; +} + +/** Generate g^x as necessary, and write the g^x for the key exchange + * as a <b>pubkey_len</b>-byte value into <b>pubkey</b>. Return 0 on + * success, -1 on failure. <b>pubkey_len</b> must be \>= DH1024_KEY_LEN. + */ +int +crypto_dh_get_public(crypto_dh_t *dh, char *pubkey, size_t pubkey_len) +{ + int bytes; + tor_assert(dh); + + const BIGNUM *dh_pub; + +#ifdef OPENSSL_1_1_API + const BIGNUM *dh_priv; + DH_get0_key(dh->dh, &dh_pub, &dh_priv); +#else + dh_pub = dh->dh->pub_key; +#endif /* defined(OPENSSL_1_1_API) */ + + if (!dh_pub) { + if (crypto_dh_generate_public(dh)<0) + return -1; + else { +#ifdef OPENSSL_1_1_API + DH_get0_key(dh->dh, &dh_pub, &dh_priv); +#else + dh_pub = dh->dh->pub_key; +#endif + } + } + + tor_assert(dh_pub); + bytes = BN_num_bytes(dh_pub); + tor_assert(bytes >= 0); + if (pubkey_len < (size_t)bytes) { + log_warn(LD_CRYPTO, + "Weird! pubkey_len (%d) was smaller than DH1024_KEY_LEN (%d)", + (int) pubkey_len, bytes); + return -1; + } + + memset(pubkey, 0, pubkey_len); + BN_bn2bin(dh_pub, (unsigned char*)(pubkey+(pubkey_len-bytes))); + + return 0; +} + +/** Check for bad Diffie-Hellman public keys (g^x). Return 0 if the key is + * okay (in the subgroup [2,p-2]), or -1 if it's bad. + * See http://www.cl.cam.ac.uk/ftp/users/rja14/psandqs.ps.gz for some tips. + */ +static int +tor_check_dh_key(int severity, const BIGNUM *bn) +{ + BIGNUM *x; + char *s; + tor_assert(bn); + x = BN_new(); + tor_assert(x); + if (BUG(!dh_param_p)) + init_dh_param(); //LCOV_EXCL_LINE we already checked whether we did this. + BN_set_word(x, 1); + if (BN_cmp(bn,x)<=0) { + log_fn(severity, LD_CRYPTO, "DH key must be at least 2."); + goto err; + } + BN_copy(x,dh_param_p); + BN_sub_word(x, 1); + if (BN_cmp(bn,x)>=0) { + log_fn(severity, LD_CRYPTO, "DH key must be at most p-2."); + goto err; + } + BN_clear_free(x); + return 0; + err: + BN_clear_free(x); + s = BN_bn2hex(bn); + log_fn(severity, LD_CRYPTO, "Rejecting insecure DH key [%s]", s); + OPENSSL_free(s); + return -1; +} + +/** Given a DH key exchange object, and our peer's value of g^y (as a + * <b>pubkey_len</b>-byte value in <b>pubkey</b>) generate + * <b>secret_bytes_out</b> bytes of shared key material and write them + * to <b>secret_out</b>. Return the number of bytes generated on success, + * or -1 on failure. + * + * (We generate key material by computing + * SHA1( g^xy || "\x00" ) || SHA1( g^xy || "\x01" ) || ... + * where || is concatenation.) + */ +ssize_t +crypto_dh_compute_secret(int severity, crypto_dh_t *dh, + const char *pubkey, size_t pubkey_len, + char *secret_out, size_t secret_bytes_out) +{ + char *secret_tmp = NULL; + BIGNUM *pubkey_bn = NULL; + size_t secret_len=0, secret_tmp_len=0; + int result=0; + tor_assert(dh); + tor_assert(secret_bytes_out/DIGEST_LEN <= 255); + tor_assert(pubkey_len < INT_MAX); + + if (!(pubkey_bn = BN_bin2bn((const unsigned char*)pubkey, + (int)pubkey_len, NULL))) + goto error; + if (tor_check_dh_key(severity, pubkey_bn)<0) { + /* Check for invalid public keys. */ + log_fn(severity, LD_CRYPTO,"Rejected invalid g^x"); + goto error; + } + secret_tmp_len = crypto_dh_get_bytes(dh); + secret_tmp = tor_malloc(secret_tmp_len); + result = DH_compute_key((unsigned char*)secret_tmp, pubkey_bn, dh->dh); + if (result < 0) { + log_warn(LD_CRYPTO,"DH_compute_key() failed."); + goto error; + } + secret_len = result; + if (crypto_expand_key_material_TAP((uint8_t*)secret_tmp, secret_len, + (uint8_t*)secret_out, secret_bytes_out)<0) + goto error; + secret_len = secret_bytes_out; + + goto done; + error: + result = -1; + done: + crypto_log_errors(LOG_WARN, "completing DH handshake"); + if (pubkey_bn) + BN_clear_free(pubkey_bn); + if (secret_tmp) { + memwipe(secret_tmp, 0, secret_tmp_len); + tor_free(secret_tmp); + } + if (result < 0) + return result; + else + return secret_len; +} + +/** Free a DH key exchange object. + */ +void +crypto_dh_free_(crypto_dh_t *dh) +{ + if (!dh) + return; + tor_assert(dh->dh); + DH_free(dh->dh); + tor_free(dh); +} + +void +crypto_dh_free_all(void) +{ + if (dh_param_p) + BN_clear_free(dh_param_p); + if (dh_param_p_tls) + BN_clear_free(dh_param_p_tls); + if (dh_param_g) + BN_clear_free(dh_param_g); + + dh_param_p = dh_param_p_tls = dh_param_g = NULL; +} diff --git a/src/lib/crypt_ops/crypto_dh.h b/src/lib/crypt_ops/crypto_dh.h new file mode 100644 index 0000000000..88e8a919a8 --- /dev/null +++ b/src/lib/crypt_ops/crypto_dh.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_dh.h + * + * \brief Headers for crypto_dh.c + **/ + +#ifndef TOR_CRYPTO_DH_H +#define TOR_CRYPTO_DH_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/defs/dh_sizes.h" + +typedef struct crypto_dh_t crypto_dh_t; + +/* Key negotiation */ +#define DH_TYPE_CIRCUIT 1 +#define DH_TYPE_REND 2 +#define DH_TYPE_TLS 3 +void crypto_set_tls_dh_prime(void); +crypto_dh_t *crypto_dh_new(int dh_type); +crypto_dh_t *crypto_dh_dup(const crypto_dh_t *dh); +int crypto_dh_get_bytes(crypto_dh_t *dh); +int crypto_dh_generate_public(crypto_dh_t *dh); +int crypto_dh_get_public(crypto_dh_t *dh, char *pubkey_out, + size_t pubkey_out_len); +ssize_t crypto_dh_compute_secret(int severity, crypto_dh_t *dh, + const char *pubkey, size_t pubkey_len, + char *secret_out, size_t secret_out_len); +void crypto_dh_free_(crypto_dh_t *dh); +#define crypto_dh_free(dh) FREE_AND_NULL(crypto_dh_t, crypto_dh_free_, (dh)) + +/* Crypto DH free */ +void crypto_dh_free_all(void); + +/* Prototypes for private functions only used by tortls.c, crypto.c, and the + * unit tests. */ +struct dh_st; +struct dh_st *crypto_dh_get_dh_(crypto_dh_t *dh); + +#endif /* !defined(TOR_CRYPTO_DH_H) */ diff --git a/src/common/crypto_digest.c b/src/lib/crypt_ops/crypto_digest.c index 9f9a1a1e2c..949e694053 100644 --- a/src/common/crypto_digest.c +++ b/src/lib/crypt_ops/crypto_digest.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,14 +10,20 @@ * operations. **/ -#include "container.h" -#include "crypto_digest.h" -#include "crypto_openssl_mgt.h" -#include "crypto_util.h" -#include "torlog.h" +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" #include "keccak-tiny/keccak-tiny.h" +#include <stdlib.h> +#include <string.h> + +#include "lib/arch/bytes.h" + DISABLE_GCC_WARNING(redundant-decls) #include <openssl/hmac.h> @@ -580,4 +586,3 @@ crypto_xof_free_(crypto_xof_t *xof) memwipe(xof, 0, sizeof(crypto_xof_t)); tor_free(xof); } - diff --git a/src/common/crypto_digest.h b/src/lib/crypt_ops/crypto_digest.h index 3bd74acdfa..15bc5ad5b9 100644 --- a/src/common/crypto_digest.h +++ b/src/lib/crypt_ops/crypto_digest.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,18 +13,9 @@ #ifndef TOR_CRYPTO_DIGEST_H #define TOR_CRYPTO_DIGEST_H -#include <stdio.h> - -#include "container.h" -#include "torint.h" - -/** Length of the output of our message digest. */ -#define DIGEST_LEN 20 -/** Length of the output of our second (improved) message digests. (For now - * this is just sha256, but it could be any other 256-bit digest.) */ -#define DIGEST256_LEN 32 -/** Length of the output of our 64-bit optimized message digests (SHA512). */ -#define DIGEST512_LEN 64 +#include "lib/cc/torint.h" +#include "lib/defs/digest_sizes.h" +#include "lib/malloc/util_malloc.h" /** Length of a sha1 message digest when encoded in base32 with trailing = * signs removed. */ @@ -78,6 +69,8 @@ typedef struct { typedef struct crypto_digest_t crypto_digest_t; typedef struct crypto_xof_t crypto_xof_t; +struct smartlist_t; + /* SHA-1 and other digests */ int crypto_digest(char *digest, const char *m, size_t len); int crypto_digest256(char *digest, const char *m, size_t len, @@ -133,4 +126,3 @@ digest_algorithm_t crypto_digest_get_algorithm(crypto_digest_t *digest); #endif #endif /* !defined(TOR_CRYPTO_DIGEST_H) */ - diff --git a/src/common/crypto_ed25519.c b/src/lib/crypt_ops/crypto_ed25519.c index 9c13e3bdf0..985652ecba 100644 --- a/src/common/crypto_ed25519.c +++ b/src/lib/crypt_ops/crypto_ed25519.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -21,19 +21,23 @@ #include <sys/stat.h> #endif -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" +#include "lib/ctime/di_ops.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/encoding/binascii.h" +#include "lib/string/util_string.h" #include "ed25519/ref10/ed25519_ref10.h" #include "ed25519/donna/ed25519_donna_tor.h" +#include <string.h> + static void pick_ed25519_impl(void); /** An Ed25519 implementation, as a set of function pointers. */ @@ -814,4 +818,3 @@ ed25519_validate_pubkey(const ed25519_public_key_t *pubkey) return 0; } - diff --git a/src/common/crypto_ed25519.h b/src/lib/crypt_ops/crypto_ed25519.h index 74269ccffd..5ecd4530d8 100644 --- a/src/common/crypto_ed25519.h +++ b/src/lib/crypt_ops/crypto_ed25519.h @@ -1,31 +1,26 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CRYPTO_ED25519_H #define TOR_CRYPTO_ED25519_H -#include "testsupport.h" -#include "torint.h" -#include "crypto_curve25519.h" -#include "util.h" - -#define ED25519_PUBKEY_LEN 32 -#define ED25519_SECKEY_LEN 64 -#define ED25519_SECKEY_SEED_LEN 32 -#define ED25519_SIG_LEN 64 +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/defs/x25519_sizes.h" /** An Ed25519 signature. */ -typedef struct { +typedef struct ed25519_signature_t { uint8_t sig[ED25519_SIG_LEN]; } ed25519_signature_t; /** An Ed25519 public key */ -typedef struct { +typedef struct ed25519_public_key_t { uint8_t pubkey[ED25519_PUBKEY_LEN]; } ed25519_public_key_t; /** An Ed25519 secret key */ -typedef struct { +typedef struct ed25519_secret_key_t { /** Note that we store secret keys in an expanded format that doesn't match * the format from standard ed25519. Ed25519 stores a 32-byte value k and * expands it into a 64-byte H(k), using the first 32 bytes for a multiplier @@ -36,7 +31,7 @@ typedef struct { } ed25519_secret_key_t; /** An Ed25519 keypair. */ -typedef struct { +typedef struct ed25519_keypair_t { ed25519_public_key_t pubkey; ed25519_secret_key_t seckey; } ed25519_keypair_t; @@ -142,4 +137,3 @@ MOCK_DECL(STATIC int, ed25519_impl_spot_check, (void)); #endif #endif /* !defined(TOR_CRYPTO_ED25519_H) */ - diff --git a/src/common/crypto_format.c b/src/lib/crypt_ops/crypto_format.c index 460e85bac1..8c71b265bf 100644 --- a/src/common/crypto_format.c +++ b/src/lib/crypt_ops/crypto_format.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,15 +14,21 @@ #ifdef HAVE_SYS_STAT_H #include <sys/stat.h> #endif -#include "container.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_ed25519.h" -#include "crypto_format.h" -#include "crypto_util.h" -#include "util.h" -#include "util_format.h" -#include "torlog.h" +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/string/compat_string.h" +#include "lib/string/util_string.h" +#include "lib/string/printf.h" +#include "lib/encoding/binascii.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/fs/files.h" + +#include <string.h> /** Write the <b>datalen</b> bytes from <b>data</b> to the file named * <b>fname</b> in the tagged-data format. This format contains a @@ -296,4 +302,3 @@ digest256_from_base64(char *digest, const char *d64) else return -1; } - diff --git a/src/common/crypto_format.h b/src/lib/crypt_ops/crypto_format.h index bbd85dc720..4a29b07b3b 100644 --- a/src/common/crypto_format.h +++ b/src/lib/crypt_ops/crypto_format.h @@ -1,15 +1,18 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_CRYPTO_FORMAT_H #define TOR_CRYPTO_FORMAT_H -#include "testsupport.h" -#include "torint.h" -#include "crypto_ed25519.h" +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" +#include "lib/defs/x25519_sizes.h" + +struct ed25519_public_key_t; +struct ed25519_signature_t; int crypto_write_tagged_contents_to_file(const char *fname, const char *typestring, @@ -23,20 +26,16 @@ ssize_t crypto_read_tagged_contents_from_file(const char *fname, uint8_t *data_out, ssize_t data_out_len); -#define ED25519_BASE64_LEN 43 -int ed25519_public_from_base64(ed25519_public_key_t *pkey, +int ed25519_public_from_base64(struct ed25519_public_key_t *pkey, const char *input); int ed25519_public_to_base64(char *output, - const ed25519_public_key_t *pkey); -const char *ed25519_fmt(const ed25519_public_key_t *pkey); - -/* XXXX move these to crypto_format.h */ -#define ED25519_SIG_BASE64_LEN 86 + const struct ed25519_public_key_t *pkey); +const char *ed25519_fmt(const struct ed25519_public_key_t *pkey); -int ed25519_signature_from_base64(ed25519_signature_t *sig, +int ed25519_signature_from_base64(struct ed25519_signature_t *sig, const char *input); int ed25519_signature_to_base64(char *output, - const ed25519_signature_t *sig); + const struct ed25519_signature_t *sig); int digest_to_base64(char *d64, const char *digest); int digest_from_base64(char *digest, const char *d64); @@ -44,4 +43,3 @@ int digest256_to_base64(char *d64, const char *digest); int digest256_from_base64(char *digest, const char *d64); #endif /* !defined(TOR_CRYPTO_FORMAT_H) */ - diff --git a/src/lib/crypt_ops/crypto_hkdf.c b/src/lib/crypt_ops/crypto_hkdf.c new file mode 100644 index 0000000000..0200d0fe9c --- /dev/null +++ b/src/lib/crypt_ops/crypto_hkdf.c @@ -0,0 +1,198 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_hkdf.c + * \brief Block of functions related with HKDF utilities and operations. + **/ + +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_digest.h" + +#include "lib/crypt_ops/crypto_openssl_mgt.h" +#include "lib/intmath/cmp.h" +#include "lib/log/util_bug.h" + +#include <openssl/opensslv.h> + +#if OPENSSL_VERSION_NUMBER >= OPENSSL_V_SERIES(1,1,0) +#define HAVE_OPENSSL_HKDF 1 +#include <openssl/kdf.h> +#endif + +#include <string.h> + +/** Given <b>key_in_len</b> bytes of negotiated randomness in <b>key_in</b> + * ("K"), expand it into <b>key_out_len</b> bytes of negotiated key material in + * <b>key_out</b> by taking the first <b>key_out_len</b> bytes of + * H(K | [00]) | H(K | [01]) | .... + * + * This is the key expansion algorithm used in the "TAP" circuit extension + * mechanism; it shouldn't be used for new protocols. + * + * Return 0 on success, -1 on failure. + */ +int +crypto_expand_key_material_TAP(const uint8_t *key_in, size_t key_in_len, + uint8_t *key_out, size_t key_out_len) +{ + int i, r = -1; + uint8_t *cp, *tmp = tor_malloc(key_in_len+1); + uint8_t digest[DIGEST_LEN]; + + /* If we try to get more than this amount of key data, we'll repeat blocks.*/ + tor_assert(key_out_len <= DIGEST_LEN*256); + + memcpy(tmp, key_in, key_in_len); + for (cp = key_out, i=0; cp < key_out+key_out_len; + ++i, cp += DIGEST_LEN) { + tmp[key_in_len] = i; + if (crypto_digest((char*)digest, (const char *)tmp, key_in_len+1) < 0) + goto exit; + memcpy(cp, digest, MIN(DIGEST_LEN, key_out_len-(cp-key_out))); + } + + r = 0; + exit: + memwipe(tmp, 0, key_in_len+1); + tor_free(tmp); + memwipe(digest, 0, sizeof(digest)); + return r; +} + +#ifdef HAVE_OPENSSL_HKDF +/** + * Perform RFC5869 HKDF computation using OpenSSL (only to be called from + * crypto_expand_key_material_rfc5869_sha256_openssl). Note that OpenSSL + * requires input key to be nonempty and salt length to be equal or less + * than 1024. + */ +static int +crypto_expand_key_material_rfc5869_sha256_openssl( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len) +{ + int r; + EVP_PKEY_CTX *evp_pkey_ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); + tor_assert(evp_pkey_ctx); + tor_assert(key_in_len != 0); + tor_assert(salt_in_len <= 1024); + + r = EVP_PKEY_derive_init(evp_pkey_ctx); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_set_hkdf_md(evp_pkey_ctx, EVP_sha256()); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_set1_hkdf_salt(evp_pkey_ctx, salt_in, (int)salt_in_len); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_set1_hkdf_key(evp_pkey_ctx, key_in, (int)key_in_len); + tor_assert(r == 1); + + r = EVP_PKEY_CTX_add1_hkdf_info(evp_pkey_ctx, info_in, (int)info_in_len); + tor_assert(r == 1); + + r = EVP_PKEY_derive(evp_pkey_ctx, key_out, &key_out_len); + tor_assert(r == 1); + + EVP_PKEY_CTX_free(evp_pkey_ctx); + return 0; +} + +#else + +/** + * Perform RFC5869 HKDF computation using our own legacy implementation. + * Only to be called from crypto_expand_key_material_rfc5869_sha256_openssl. + */ +static int +crypto_expand_key_material_rfc5869_sha256_legacy( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len) +{ + uint8_t prk[DIGEST256_LEN]; + uint8_t tmp[DIGEST256_LEN + 128 + 1]; + uint8_t mac[DIGEST256_LEN]; + int i; + uint8_t *outp; + size_t tmp_len; + + crypto_hmac_sha256((char*)prk, + (const char*)salt_in, salt_in_len, + (const char*)key_in, key_in_len); + + /* If we try to get more than this amount of key data, we'll repeat blocks.*/ + tor_assert(key_out_len <= DIGEST256_LEN * 256); + tor_assert(info_in_len <= 128); + memset(tmp, 0, sizeof(tmp)); + outp = key_out; + i = 1; + + while (key_out_len) { + size_t n; + if (i > 1) { + memcpy(tmp, mac, DIGEST256_LEN); + memcpy(tmp+DIGEST256_LEN, info_in, info_in_len); + tmp[DIGEST256_LEN+info_in_len] = i; + tmp_len = DIGEST256_LEN + info_in_len + 1; + } else { + memcpy(tmp, info_in, info_in_len); + tmp[info_in_len] = i; + tmp_len = info_in_len + 1; + } + crypto_hmac_sha256((char*)mac, + (const char*)prk, DIGEST256_LEN, + (const char*)tmp, tmp_len); + n = key_out_len < DIGEST256_LEN ? key_out_len : DIGEST256_LEN; + memcpy(outp, mac, n); + key_out_len -= n; + outp += n; + ++i; + } + + memwipe(tmp, 0, sizeof(tmp)); + memwipe(mac, 0, sizeof(mac)); + return 0; +} +#endif + +/** Expand some secret key material according to RFC5869, using SHA256 as the + * underlying hash. The <b>key_in_len</b> bytes at <b>key_in</b> are the + * secret key material; the <b>salt_in_len</b> bytes at <b>salt_in</b> and the + * <b>info_in_len</b> bytes in <b>info_in_len</b> are the algorithm's "salt" + * and "info" parameters respectively. On success, write <b>key_out_len</b> + * bytes to <b>key_out</b> and return 0. Assert on failure. + */ +int +crypto_expand_key_material_rfc5869_sha256( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len) +{ + tor_assert(key_in); + tor_assert(key_in_len > 0); + +#ifdef HAVE_OPENSSL_HKDF + return crypto_expand_key_material_rfc5869_sha256_openssl(key_in, + key_in_len, salt_in, + salt_in_len, info_in, + info_in_len, + key_out, key_out_len); +#else + return crypto_expand_key_material_rfc5869_sha256_legacy(key_in, + key_in_len, salt_in, + salt_in_len, info_in, + info_in_len, + key_out, key_out_len); +#endif +} diff --git a/src/lib/crypt_ops/crypto_hkdf.h b/src/lib/crypt_ops/crypto_hkdf.h new file mode 100644 index 0000000000..4c42584277 --- /dev/null +++ b/src/lib/crypt_ops/crypto_hkdf.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file crypto_hkdf.h + * + * \brief Headers for crypto_hkdf.h + **/ + +#ifndef TOR_CRYPTO_HKDF_H +#define TOR_CRYPTO_HKDF_H + +#include "lib/cc/torint.h" + +int crypto_expand_key_material_TAP(const uint8_t *key_in, + size_t key_in_len, + uint8_t *key_out, size_t key_out_len); +int crypto_expand_key_material_rfc5869_sha256( + const uint8_t *key_in, size_t key_in_len, + const uint8_t *salt_in, size_t salt_in_len, + const uint8_t *info_in, size_t info_in_len, + uint8_t *key_out, size_t key_out_len); + +#endif /* !defined(TOR_CRYPTO_HKDF_H) */ diff --git a/src/common/crypto_openssl_mgt.c b/src/lib/crypt_ops/crypto_openssl_mgt.c index ea3519efa2..d1affa7258 100644 --- a/src/common/crypto_openssl_mgt.c +++ b/src/lib/crypt_ops/crypto_openssl_mgt.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,8 +10,12 @@ * \brief Block of functions related to operations from OpenSSL. **/ -#include "compat_openssl.h" -#include "crypto_openssl_mgt.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_openssl_mgt.h" +#include "lib/string/util_string.h" +#include "lib/lock/compat_mutex.h" +#include "lib/testsupport/testsupport.h" +#include "lib/thread/threads.h" DISABLE_GCC_WARNING(redundant-decls) @@ -29,6 +33,8 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) +#include <string.h> + #ifndef NEW_THREAD_API /** A number of preallocated mutexes for use by OpenSSL. */ static tor_mutex_t **openssl_mutexes_ = NULL; @@ -158,4 +164,3 @@ crypto_openssl_free_all(void) } #endif /* !defined(NEW_THREAD_API) */ } - diff --git a/src/common/crypto_openssl_mgt.h b/src/lib/crypt_ops/crypto_openssl_mgt.h index 09b6737962..8251f65ecf 100644 --- a/src/common/crypto_openssl_mgt.h +++ b/src/lib/crypt_ops/crypto_openssl_mgt.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,9 +13,7 @@ #ifndef TOR_CRYPTO_OPENSSL_H #define TOR_CRYPTO_OPENSSL_H -#include <stdio.h> -#include "util.h" - +#include "orconfig.h" #include <openssl/engine.h> /* @@ -82,4 +80,3 @@ int setup_openssl_threading(void); void crypto_openssl_free_all(void); #endif /* !defined(TOR_CRYPTO_OPENSSL_H) */ - diff --git a/src/common/crypto_pwbox.c b/src/lib/crypt_ops/crypto_pwbox.c index c2bd1d26cb..c001e295da 100644 --- a/src/common/crypto_pwbox.c +++ b/src/lib/crypt_ops/crypto_pwbox.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,15 +8,19 @@ * them to disk. */ -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_pwbox.h" -#include "crypto_rand.h" -#include "crypto_s2k.h" -#include "crypto_util.h" -#include "di_ops.h" -#include "util.h" -#include "pwbox.h" +#include <string.h> + +#include "lib/arch/bytes.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_pwbox.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/intmath/muldiv.h" +#include "trunnel/pwbox.h" +#include "lib/log/util_bug.h" /* 8 bytes "TORBOX00" 1 byte: header len (H) @@ -74,7 +78,7 @@ crypto_pwbox(uint8_t **out, size_t *outlen_out, pwbox_encoded_setlen_data(enc, encrypted_len); encrypted_portion = pwbox_encoded_getarray_data(enc); - set_uint32(encrypted_portion, htonl((uint32_t)input_len)); + set_uint32(encrypted_portion, tor_htonl((uint32_t)input_len)); memcpy(encrypted_portion+4, input, input_len); /* Now that all the data is in position, derive some keys, encrypt, and @@ -189,7 +193,7 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out, cipher = crypto_cipher_new_with_iv((char*)keys, (char*)enc->iv); crypto_cipher_decrypt(cipher, (char*)&result_len, (char*)encrypted, 4); - result_len = ntohl(result_len); + result_len = tor_ntohl(result_len); if (encrypted_len < result_len + 4) goto err; @@ -212,4 +216,3 @@ crypto_unpwbox(uint8_t **out, size_t *outlen_out, memwipe(keys, 0, sizeof(keys)); return rv; } - diff --git a/src/common/crypto_pwbox.h b/src/lib/crypt_ops/crypto_pwbox.h index a26b6d2c17..00fabd0913 100644 --- a/src/common/crypto_pwbox.h +++ b/src/lib/crypt_ops/crypto_pwbox.h @@ -1,10 +1,16 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * \file crypto_pwbox.h + * + * \brief Header for crypto_pwbox.c + **/ + #ifndef CRYPTO_PWBOX_H_INCLUDED_ #define CRYPTO_PWBOX_H_INCLUDED_ -#include "torint.h" +#include "lib/cc/torint.h" #define UNPWBOX_OKAY 0 #define UNPWBOX_BAD_SECRET -1 @@ -20,4 +26,3 @@ int crypto_unpwbox(uint8_t **out, size_t *outlen_out, const char *secret, size_t secret_len); #endif /* !defined(CRYPTO_PWBOX_H_INCLUDED_) */ - diff --git a/src/common/crypto_rand.c b/src/lib/crypt_ops/crypto_rand.c index df2e2f65d3..6f479b013b 100644 --- a/src/common/crypto_rand.c +++ b/src/lib/crypt_ops/crypto_rand.c @@ -14,22 +14,26 @@ #ifndef CRYPTO_RAND_PRIVATE #define CRYPTO_RAND_PRIVATE -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #ifdef _WIN32 #include <windows.h> #include <wincrypt.h> #endif /* defined(_WIN32) */ -#include "container.h" -#include "compat.h" -#include "compat_openssl.h" -#include "crypto_util.h" -#include "sandbox.h" -#include "testsupport.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" +#include "lib/container/smartlist.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/encoding/binascii.h" +#include "lib/intmath/weakrng.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/compat_string.h" +#include "lib/string/util_string.h" +#include "lib/testsupport/testsupport.h" +#include "lib/fs/files.h" DISABLE_GCC_WARNING(redundant-decls) #include <openssl/rand.h> @@ -62,6 +66,8 @@ ENABLE_GCC_WARNING(redundant-decls) #include <sys/random.h> #endif +#include <string.h> + /** * How many bytes of entropy we add at once. * @@ -237,7 +243,7 @@ crypto_strongest_rand_fallback(uint8_t *out, size_t out_len) fd = open(sandbox_intern_string(filenames[i]), O_RDONLY, 0); if (fd<0) continue; log_info(LD_CRYPTO, "Reading entropy from \"%s\"", filenames[i]); - n = read_all(fd, (char*)out, out_len, 0); + n = read_all_from_fd(fd, (char*)out, out_len); close(fd); if (n != out_len) { /* LCOV_EXCL_START @@ -612,4 +618,3 @@ crypto_force_rand_ssleay(void) } #endif /* !defined(CRYPTO_RAND_PRIVATE) */ - diff --git a/src/common/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index bb02e51001..938f11909e 100644 --- a/src/common/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -13,8 +13,9 @@ #ifndef TOR_CRYPTO_RAND_H #define TOR_CRYPTO_RAND_H -#include "torint.h" -#include "util.h" +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" /* random numbers */ int crypto_seed_rng(void) ATTR_WUR; @@ -49,4 +50,3 @@ extern int break_strongest_rng_fallback; #endif /* defined(CRYPTO_RAND_PRIVATE) */ #endif /* !defined(TOR_CRYPTO_RAND_H) */ - diff --git a/src/common/crypto_rsa.c b/src/lib/crypt_ops/crypto_rsa.c index f66cdef3c5..9290414de0 100644 --- a/src/common/crypto_rsa.c +++ b/src/lib/crypt_ops/crypto_rsa.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,14 +9,17 @@ * \brief Block of functions related with RSA utilities and operations. **/ -#include "crypto.h" -#include "crypto_curve25519.h" -#include "crypto_digest.h" -#include "crypto_format.h" -#include "compat_openssl.h" -#include "crypto_rand.h" -#include "crypto_rsa.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_rsa.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/util_bug.h" +#include "lib/fs/files.h" DISABLE_GCC_WARNING(redundant-decls) @@ -33,9 +36,10 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) -#include "torlog.h" -#include "util.h" -#include "util_format.h" +#include "lib/log/torlog.h" +#include "lib/encoding/binascii.h" + +#include <string.h> /** Declaration for crypto_pk_t structure. */ struct crypto_pk_t @@ -44,27 +48,6 @@ struct crypto_pk_t RSA *key; /**< The key itself */ }; -/** Log all pending crypto errors at level <b>severity</b>. Use - * <b>doing</b> to describe our current activities. - */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - while ((err = ERR_get_error()) != 0) { - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (BUG(!doing)) doing = "(null)"; - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } -} - /** Return the number of bytes added by padding method <b>padding</b>. */ int @@ -1180,4 +1163,3 @@ crypto_pk_base64_decode(const char *str, size_t len) tor_free(der); return pk; } - diff --git a/src/common/crypto_rsa.h b/src/lib/crypt_ops/crypto_rsa.h index e952089318..093f2cec6c 100644 --- a/src/common/crypto_rsa.h +++ b/src/lib/crypt_ops/crypto_rsa.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,13 +15,10 @@ #include "orconfig.h" -#include "crypto_digest.h" -#include <stdio.h> -#include "torint.h" -#include "testsupport.h" -#include "compat.h" -#include "util.h" -#include "torlog.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#include "lib/log/torlog.h" /** Length of our public keys. */ #define PK_BYTES (1024/8) @@ -116,4 +113,3 @@ void crypto_pk_assign_(crypto_pk_t *dest, const crypto_pk_t *src); #endif #endif - diff --git a/src/common/crypto_s2k.c b/src/lib/crypt_ops/crypto_s2k.c index 8543760ec5..ab91d92f0e 100644 --- a/src/common/crypto_s2k.c +++ b/src/lib/crypt_ops/crypto_s2k.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,13 +12,14 @@ #define CRYPTO_S2K_PRIVATE -#include "compat.h" -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_rand.h" -#include "crypto_s2k.h" -#include "crypto_util.h" -#include "util.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/util_bug.h" #include <openssl/evp.h> @@ -27,6 +28,8 @@ #include <libscrypt.h> #endif +#include <string.h> + /* Encoded secrets take the form: u8 type; @@ -472,4 +475,3 @@ secret_to_key_check(const uint8_t *spec_and_key, size_t spec_and_key_len, memwipe(buf, 0, sizeof(buf)); return rv; } - diff --git a/src/common/crypto_s2k.h b/src/lib/crypt_ops/crypto_s2k.h index 849ff59ce8..2429185b52 100644 --- a/src/common/crypto_s2k.h +++ b/src/lib/crypt_ops/crypto_s2k.h @@ -1,14 +1,20 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * \file crypto_s2k.h + * + * \brief Header for crypto_s2k.c + **/ + #ifndef TOR_CRYPTO_S2K_H_INCLUDED #define TOR_CRYPTO_S2K_H_INCLUDED #include <stdio.h> -#include "torint.h" +#include "lib/cc/torint.h" /** Length of RFC2440-style S2K specifier: the first 8 bytes are a salt, the * 9th describes how much iteration to do. */ @@ -70,4 +76,3 @@ STATIC int secret_to_key_compute_key(uint8_t *key_out, size_t key_out_len, #endif /* defined(CRYPTO_S2K_PRIVATE) */ #endif /* !defined(TOR_CRYPTO_S2K_H_INCLUDED) */ - diff --git a/src/common/crypto_util.c b/src/lib/crypt_ops/crypto_util.c index b0d5b6b2f7..19b0885256 100644 --- a/src/common/crypto_util.c +++ b/src/lib/crypt_ops/crypto_util.c @@ -13,7 +13,8 @@ #ifndef CRYPTO_UTIL_PRIVATE #define CRYPTO_UTIL_PRIVATE -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/cc/compat_compiler.h" #include <string.h> @@ -23,14 +24,16 @@ #include <wincrypt.h> #endif /* defined(_WIN32) */ -#include "util.h" - DISABLE_GCC_WARNING(redundant-decls) +#include <openssl/err.h> #include <openssl/crypto.h> ENABLE_GCC_WARNING(redundant-decls) +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + /** * Destroy the <b>sz</b> bytes of data stored at <b>mem</b>, setting them to * the value <b>byte</b>. @@ -103,5 +106,24 @@ memwipe(void *mem, uint8_t byte, size_t sz) memset(mem, byte, sz); } +/** Log all pending crypto errors at level <b>severity</b>. Use + * <b>doing</b> to describe our current activities. + */ +void +crypto_log_errors(int severity, const char *doing) +{ + unsigned long err; + const char *msg, *lib, *func; + while ((err = ERR_get_error()) != 0) { + msg = (const char*)ERR_reason_error_string(err); + lib = (const char*)ERR_lib_error_string(err); + func = (const char*)ERR_func_error_string(err); + if (!msg) msg = "(null)"; + if (!lib) lib = "(null)"; + if (!func) func = "(null)"; + if (BUG(!doing)) doing = "(null)"; + tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", + doing, msg, lib, func); + } +} #endif /* !defined(CRYPTO_UTIL_PRIVATE) */ - diff --git a/src/common/crypto_util.h b/src/lib/crypt_ops/crypto_util.h index 922942b371..3ce34e6f23 100644 --- a/src/common/crypto_util.h +++ b/src/lib/crypt_ops/crypto_util.h @@ -13,11 +13,14 @@ #ifndef TOR_CRYPTO_UTIL_H #define TOR_CRYPTO_UTIL_H -#include "torint.h" +#include "lib/cc/torint.h" /** OpenSSL-based utility functions. */ void memwipe(void *mem, uint8_t byte, size_t sz); +/** Log utility function */ +void crypto_log_errors(int severity, const char *doing); + #ifdef CRYPTO_UTIL_PRIVATE #ifdef TOR_UNIT_TESTS #endif /* defined(TOR_UNIT_TESTS) */ diff --git a/src/lib/crypt_ops/digestset.c b/src/lib/crypt_ops/digestset.c new file mode 100644 index 0000000000..89dd377a9c --- /dev/null +++ b/src/lib/crypt_ops/digestset.c @@ -0,0 +1,58 @@ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file digestset.c + * \brief Implementation for a set of digests + **/ + +#include "orconfig.h" +#include "lib/container/bloomfilt.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/defs/digest_sizes.h" +#include "lib/crypt_ops/digestset.h" +#include "siphash.h" + +/* Wrap our hash function to have the signature that the bloom filter + * needs. */ +static uint64_t +bloomfilt_digest_hash(const struct sipkey *key, + const void *item) +{ + return siphash24(item, DIGEST_LEN, key); +} + +/** + * Allocate and return an digestset, suitable for holding up to + * <b>max_guess</b> distinct values. + */ +digestset_t * +digestset_new(int max_guess) +{ + uint8_t k[BLOOMFILT_KEY_LEN]; + crypto_rand((void*)k, sizeof(k)); + return bloomfilt_new(max_guess, bloomfilt_digest_hash, k); +} + +/** + * Add <b>digest</b> to <b>set</b>. + * + * All future queries for <b>digest</b> in set will return true. Removing + * items is not possible. + */ +void +digestset_add(digestset_t *set, const char *digest) +{ + bloomfilt_add(set, digest); +} + +/** + * Return true if <b>digest</b> is a member of <b>set</b>. (And probably, + * return false if <b>digest</b> is not a member of set.) + */ +int +digestset_probably_contains(const digestset_t *set, + const char *digest) +{ + return bloomfilt_probably_contains(set, digest); +} diff --git a/src/lib/crypt_ops/digestset.h b/src/lib/crypt_ops/digestset.h new file mode 100644 index 0000000000..328979ae0d --- /dev/null +++ b/src/lib/crypt_ops/digestset.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file digestset.h + * \brief Types to handle sets of digests, based on bloom filters. + **/ + +#ifndef TOR_DIGESTSET_H +#define TOR_DIGESTSET_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/container/bloomfilt.h" + +/** + * An digestset_t represents a set of 20-byte digest values. The + * implementation is probabilistic: false negatives cannot occur but false + * positives are possible. + */ +typedef struct bloomfilt_t digestset_t; + +digestset_t *digestset_new(int max_addresses_guess); +#define digestset_free(set) bloomfilt_free(set) +void digestset_add(digestset_t *set, const char *addr); +int digestset_probably_contains(const digestset_t *set, + const char *addr); + +#endif diff --git a/src/lib/crypt_ops/include.am b/src/lib/crypt_ops/include.am new file mode 100644 index 0000000000..1b88b880d0 --- /dev/null +++ b/src/lib/crypt_ops/include.am @@ -0,0 +1,46 @@ + +noinst_LIBRARIES += src/lib/libtor-crypt-ops.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-crypt-ops-testing.a +endif + +src_lib_libtor_crypt_ops_a_SOURCES = \ + src/lib/crypt_ops/aes.c \ + src/lib/crypt_ops/crypto.c \ + src/lib/crypt_ops/crypto_curve25519.c \ + src/lib/crypt_ops/crypto_dh.c \ + src/lib/crypt_ops/crypto_digest.c \ + src/lib/crypt_ops/crypto_ed25519.c \ + src/lib/crypt_ops/crypto_format.c \ + src/lib/crypt_ops/crypto_hkdf.c \ + src/lib/crypt_ops/crypto_openssl_mgt.c \ + src/lib/crypt_ops/crypto_pwbox.c \ + src/lib/crypt_ops/crypto_rand.c \ + src/lib/crypt_ops/crypto_rsa.c \ + src/lib/crypt_ops/crypto_s2k.c \ + src/lib/crypt_ops/crypto_util.c \ + src/lib/crypt_ops/digestset.c + +src_lib_libtor_crypt_ops_testing_a_SOURCES = \ + $(src_lib_libtor_crypt_ops_a_SOURCES) +src_lib_libtor_crypt_ops_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_crypt_ops_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/crypt_ops/aes.h \ + src/lib/crypt_ops/compat_openssl.h \ + src/lib/crypt_ops/crypto_curve25519.h \ + src/lib/crypt_ops/crypto_dh.h \ + src/lib/crypt_ops/crypto_digest.h \ + src/lib/crypt_ops/crypto_ed25519.h \ + src/lib/crypt_ops/crypto_format.h \ + src/lib/crypt_ops/crypto.h \ + src/lib/crypt_ops/crypto_hkdf.h \ + src/lib/crypt_ops/crypto_openssl_mgt.h \ + src/lib/crypt_ops/crypto_pwbox.h \ + src/lib/crypt_ops/crypto_rand.h \ + src/lib/crypt_ops/crypto_rsa.h \ + src/lib/crypt_ops/crypto_s2k.h \ + src/lib/crypt_ops/crypto_util.h \ + src/lib/crypt_ops/digestset.h diff --git a/src/lib/ctime/.may_include b/src/lib/ctime/.may_include new file mode 100644 index 0000000000..e74669bce1 --- /dev/null +++ b/src/lib/ctime/.may_include @@ -0,0 +1,5 @@ +orconfig.h +lib/cc/*.h +lib/ctime/*.h +lib/err/*.h +lib/malloc/*.h diff --git a/src/common/di_ops.c b/src/lib/ctime/di_ops.c index 90e9357c8e..287ff6080a 100644 --- a/src/common/di_ops.c +++ b/src/lib/ctime/di_ops.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,9 +7,11 @@ **/ #include "orconfig.h" -#include "di_ops.h" -#include "torlog.h" -#include "util.h" +#include "lib/ctime/di_ops.h" +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" + +#include <string.h> /** * Timing-safe version of memcmp. As memcmp, compare the <b>sz</b> bytes at @@ -171,8 +173,8 @@ dimap_add_entry(di_digest256_map_t **map, di_digest256_map_t *new_ent; { void *old_val = dimap_search(*map, key, NULL); - tor_assert(! old_val); - tor_assert(val); + raw_assert(! old_val); + raw_assert(val); } new_ent = tor_malloc_zero(sizeof(di_digest256_map_t)); new_ent->next = *map; @@ -264,11 +266,10 @@ select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, rand_val = INT64_MAX; } } - tor_assert(total_so_far == total); - tor_assert(n_chosen == 1); - tor_assert(i_chosen >= 0); - tor_assert(i_chosen < n_entries); + raw_assert(total_so_far == total); + raw_assert(n_chosen == 1); + raw_assert(i_chosen >= 0); + raw_assert(i_chosen < n_entries); return i_chosen; } - diff --git a/src/common/di_ops.h b/src/lib/ctime/di_ops.h index 67d9c9f0df..92af7ae278 100644 --- a/src/common/di_ops.h +++ b/src/lib/ctime/di_ops.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,7 +12,7 @@ #define TOR_DI_OPS_H #include "orconfig.h" -#include "torint.h" +#include "lib/cc/torint.h" int tor_memcmp(const void *a, const void *b, size_t sz); int tor_memeq(const void *a, const void *b, size_t sz); diff --git a/src/lib/ctime/include.am b/src/lib/ctime/include.am new file mode 100644 index 0000000000..b46c43ba0c --- /dev/null +++ b/src/lib/ctime/include.am @@ -0,0 +1,25 @@ + +noinst_LIBRARIES += src/lib/libtor-ctime.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-ctime-testing.a +endif + +if ADD_MULODI4 +mulodi4_source=src/ext/mulodi/mulodi4.c +else +mulodi4_source= +endif + +src_lib_libtor_ctime_a_SOURCES = \ + $(mulodi4_source) \ + src/ext/csiphash.c \ + src/lib/ctime/di_ops.c + +src_lib_libtor_ctime_testing_a_SOURCES = \ + $(src_lib_libtor_ctime_a_SOURCES) +src_lib_libtor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ +src_lib_libtor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/ctime/di_ops.h diff --git a/src/lib/defs/.may_include b/src/lib/defs/.may_include new file mode 100644 index 0000000000..2b06e8519c --- /dev/null +++ b/src/lib/defs/.may_include @@ -0,0 +1 @@ +orconfig.h diff --git a/src/lib/defs/dh_sizes.h b/src/lib/defs/dh_sizes.h new file mode 100644 index 0000000000..b60957281c --- /dev/null +++ b/src/lib/defs/dh_sizes.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DH_SIZES_H +#define TOR_DH_SIZES_H + +/** Length of our legacy DH keys. */ +#define DH1024_KEY_LEN (1024/8) + +#endif diff --git a/src/lib/defs/digest_sizes.h b/src/lib/defs/digest_sizes.h new file mode 100644 index 0000000000..dd772cae07 --- /dev/null +++ b/src/lib/defs/digest_sizes.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DIGEST_SIZES_H +#define TOR_DIGEST_SIZES_H + +/** + * \file digest_sizes.h + * + * \brief Definitions for common sizes of cryptographic digests. + * + * Tor uses digests throughout its codebase, even in parts that don't actually + * calculate the digests. + **/ + +/** Length of the output of our message digest. */ +#define DIGEST_LEN 20 +/** Length of the output of our second (improved) message digests. (For now + * this is just sha256, but it could be any other 256-bit digest.) */ +#define DIGEST256_LEN 32 +/** Length of the output of our 64-bit optimized message digests (SHA512). */ +#define DIGEST512_LEN 64 + +#endif diff --git a/src/lib/defs/include.am b/src/lib/defs/include.am new file mode 100644 index 0000000000..48ee7f29fc --- /dev/null +++ b/src/lib/defs/include.am @@ -0,0 +1,5 @@ + +noinst_HEADERS += \ + src/lib/defs/dh_sizes.h \ + src/lib/defs/digest_sizes.h \ + src/lib/defs/x25519_sizes.h diff --git a/src/lib/defs/x25519_sizes.h b/src/lib/defs/x25519_sizes.h new file mode 100644 index 0000000000..adaaab8c4d --- /dev/null +++ b/src/lib/defs/x25519_sizes.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_X25519_SIZES_H +#define TOR_X25519_SIZES_H + +/** Length of a curve25519 public key when encoded. */ +#define CURVE25519_PUBKEY_LEN 32 +/** Length of a curve25519 secret key when encoded. */ +#define CURVE25519_SECKEY_LEN 32 +/** Length of the result of a curve25519 handshake. */ +#define CURVE25519_OUTPUT_LEN 32 + +#define ED25519_PUBKEY_LEN 32 +#define ED25519_SECKEY_LEN 64 +#define ED25519_SECKEY_SEED_LEN 32 +#define ED25519_SIG_LEN 64 + +#define CURVE25519_BASE64_PADDED_LEN 44 + +#define ED25519_BASE64_LEN 43 +#define ED25519_SIG_BASE64_LEN 86 + +#endif diff --git a/src/lib/encoding/.may_include b/src/lib/encoding/.may_include new file mode 100644 index 0000000000..92231b5133 --- /dev/null +++ b/src/lib/encoding/.may_include @@ -0,0 +1,9 @@ +orconfig.h +lib/cc/*.h +lib/encoding/*.h +lib/intmath/*.h +lib/log/*.h +lib/malloc/*.h +lib/string/*.h +lib/testsupport/*.h +lib/wallclock/*.h diff --git a/src/common/util_format.c b/src/lib/encoding/binascii.c index e51757a4e8..df9bb4a813 100644 --- a/src/common/util_format.c +++ b/src/lib/encoding/binascii.c @@ -1,26 +1,45 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file util_format.c + * \file binascii.c * * \brief Miscellaneous functions for encoding and decoding various things * in base{16,32,64}. */ #include "orconfig.h" -#include "torlog.h" -#include "util.h" -#include "util_format.h" -#include "torint.h" + +#include "lib/encoding/binascii.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/cc/torint.h" +#include "lib/string/compat_ctype.h" +#include "lib/intmath/muldiv.h" +#include "lib/malloc/util_malloc.h" #include <stddef.h> #include <string.h> #include <stdlib.h> +/** Return a pointer to a NUL-terminated hexadecimal string encoding + * the first <b>fromlen</b> bytes of <b>from</b>. (fromlen must be \<= 32.) The + * result does not need to be deallocated, but repeated calls to + * hex_str will trash old results. + */ +const char * +hex_str(const char *from, size_t fromlen) +{ + static char buf[65]; + if (fromlen>(sizeof(buf)-1)/2) + fromlen = (sizeof(buf)-1)/2; + base16_encode(buf,sizeof(buf),from,fromlen); + return buf; +} + /* Return the base32 encoded size in bytes using the source length srclen. * * (WATCH OUT: This API counts the terminating NUL byte, but @@ -464,39 +483,6 @@ base16_encode(char *dest, size_t destlen, const char *src, size_t srclen) *cp = '\0'; } -/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ -static inline int -hex_decode_digit_(char c) -{ - switch (c) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'A': case 'a': return 10; - case 'B': case 'b': return 11; - case 'C': case 'c': return 12; - case 'D': case 'd': return 13; - case 'E': case 'e': return 14; - case 'F': case 'f': return 15; - default: - return -1; - } -} - -/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ -int -hex_decode_digit(char c) -{ - return hex_decode_digit_(c); -} - /** Given a hexadecimal string of <b>srclen</b> bytes in <b>src</b>, decode * it and store the result in the <b>destlen</b>-byte buffer at <b>dest</b>. * Return the number of bytes decoded on success, -1 on failure. If @@ -519,8 +505,8 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) end = src+srclen; while (src<end) { - v1 = hex_decode_digit_(*src); - v2 = hex_decode_digit_(*(src+1)); + v1 = hex_decode_digit(*src); + v2 = hex_decode_digit(*(src+1)); if (v1<0||v2<0) return -1; *(uint8_t*)dest = (v1<<4)|v2; @@ -532,4 +518,3 @@ base16_decode(char *dest, size_t destlen, const char *src, size_t srclen) return (int) (dest-dest_orig); } - diff --git a/src/common/util_format.h b/src/lib/encoding/binascii.h index 0aefe3a44e..23cbaa7070 100644 --- a/src/common/util_format.h +++ b/src/lib/encoding/binascii.h @@ -1,14 +1,24 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#ifndef TOR_UTIL_FORMAT_H -#define TOR_UTIL_FORMAT_H +/** + * \file binascii.h + * + * \brief Header for binascii.c + **/ -#include "testsupport.h" -#include "torint.h" +#ifndef TOR_BINASCII_H +#define TOR_BINASCII_H + +#include "orconfig.h" +#include <stddef.h> +#include "lib/testsupport/testsupport.h" +#include "lib/cc/torint.h" + +const char *hex_str(const char *from, size_t fromlen); /** @{ */ /** These macros don't check for overflow. Use them only for constant inputs @@ -44,9 +54,7 @@ void base32_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base32_decode(char *dest, size_t destlen, const char *src, size_t srclen); size_t base32_encoded_size(size_t srclen); -int hex_decode_digit(char c); void base16_encode(char *dest, size_t destlen, const char *src, size_t srclen); int base16_decode(char *dest, size_t destlen, const char *src, size_t srclen); #endif /* !defined(TOR_UTIL_FORMAT_H) */ - diff --git a/src/common/confline.c b/src/lib/encoding/confline.c index bf613ab742..3486b6a82b 100644 --- a/src/common/confline.c +++ b/src/lib/encoding/confline.c @@ -1,29 +1,30 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "compat.h" -#include "confline.h" -#include "torlog.h" -#include "util.h" -#include "container.h" - -static int config_get_lines_aux(const char *string, config_line_t **result, - int extended, int allow_include, - int *has_include, smartlist_t *opened_lst, - int recursion_level, config_line_t **last); -static smartlist_t *config_get_file_list(const char *path, - smartlist_t *opened_files); -static int config_get_included_config(const char *path, int recursion_level, - int extended, config_line_t **config, - config_line_t **config_last, - smartlist_t *opened_lst); -static int config_process_include(const char *path, int recursion_level, - int extended, config_line_t **list, - config_line_t **list_last, - smartlist_t *opened_lst); +/** + * \file confline.c + * + * \brief Functions to manipulate a linked list of key-value pairs, of the + * type used in Tor's configuration files. + * + * Tor uses the config_line_t type and its associated serialized format for + * human-readable key-value pairs in many places, including its configuration, + * its state files, its consensus cache, and so on. + **/ + +#include "lib/encoding/confline.h" +#include "lib/encoding/cstring.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/string/util_string.h" + +#include <string.h> /** Helper: allocate a new configuration option mapping 'key' to 'val', * append it to *<b>lst</b>. */ @@ -86,11 +87,12 @@ config_line_find(const config_line_t *lines, * <b>opened_lst</b> will have a list of opened files if provided. * Returns the a pointer to the last element of the <b>result</b> in * <b>last</b>. */ -static int +int config_get_lines_aux(const char *string, config_line_t **result, int extended, int allow_include, int *has_include, - smartlist_t *opened_lst, int recursion_level, - config_line_t **last) + struct smartlist_t *opened_lst, int recursion_level, + config_line_t **last, + include_handler_fn handle_include) { config_line_t *list = NULL, **next, *list_last = NULL; char *k, *v; @@ -133,13 +135,13 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended, } } - if (allow_include && !strcmp(k, "%include")) { + if (allow_include && !strcmp(k, "%include") && handle_include) { tor_free(k); include_used = 1; config_line_t *include_list; - if (config_process_include(v, recursion_level, extended, &include_list, - &list_last, opened_lst) < 0) { + if (handle_include(v, recursion_level, extended, &include_list, + &list_last, opened_lst) < 0) { log_warn(LD_CONFIG, "Error reading included configuration " "file or directory: \"%s\".", v); config_free_lines(list); @@ -178,152 +180,12 @@ config_get_lines_aux(const char *string, config_line_t **result, int extended, return 0; } -/** Helper: parse the config string and strdup into key/value - * strings. Set *result to the list, or NULL if parsing the string - * failed. Set *has_include to 1 if <b>result</b> has values from - * %included files. <b>opened_lst</b> will have a list of opened files if - * provided. Return 0 on success, -1 on failure. Warn and ignore any - * misformatted lines. - * - * If <b>extended</b> is set, then treat keys beginning with / and with + as - * indicating "clear" and "append" respectively. */ -int -config_get_lines_include(const char *string, config_line_t **result, - int extended, int *has_include, - smartlist_t *opened_lst) -{ - return config_get_lines_aux(string, result, extended, 1, has_include, - opened_lst, 1, NULL); -} - /** Same as config_get_lines_include but does not allow %include */ int config_get_lines(const char *string, config_line_t **result, int extended) { return config_get_lines_aux(string, result, extended, 0, NULL, NULL, 1, - NULL); -} - -/** Adds a list of configuration files present on <b>path</b> to - * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file, - * only that file will be added to <b>file_list</b>. If it is a directory, - * all paths for files on that directory root (no recursion) except for files - * whose name starts with a dot will be added to <b>file_list</b>. - * <b>opened_files</b> will have a list of files opened by this function - * if provided. Return 0 on success, -1 on failure. Ignores empty files. - */ -static smartlist_t * -config_get_file_list(const char *path, smartlist_t *opened_files) -{ - smartlist_t *file_list = smartlist_new(); - - if (opened_files) { - smartlist_add_strdup(opened_files, path); - } - - file_status_t file_type = file_status(path); - if (file_type == FN_FILE) { - smartlist_add_strdup(file_list, path); - return file_list; - } else if (file_type == FN_DIR) { - smartlist_t *all_files = tor_listdir(path); - if (!all_files) { - smartlist_free(file_list); - return NULL; - } - smartlist_sort_strings(all_files); - SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { - if (f[0] == '.') { - tor_free(f); - continue; - } - - char *fullname; - tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); - tor_free(f); - - if (opened_files) { - smartlist_add_strdup(opened_files, fullname); - } - - if (file_status(fullname) != FN_FILE) { - tor_free(fullname); - continue; - } - smartlist_add(file_list, fullname); - } SMARTLIST_FOREACH_END(f); - smartlist_free(all_files); - return file_list; - } else if (file_type == FN_EMPTY) { - return file_list; - } else { - smartlist_free(file_list); - return NULL; - } -} - -/** Creates a list of config lines present on included <b>path</b>. - * Set <b>config</b> to the list and <b>config_last</b> to the last element of - * <b>config</b>. <b>opened_lst</b> will have a list of opened files if - * provided. Return 0 on success, -1 on failure. */ -static int -config_get_included_config(const char *path, int recursion_level, int extended, - config_line_t **config, config_line_t **config_last, - smartlist_t *opened_lst) -{ - char *included_conf = read_file_to_str(path, 0, NULL); - if (!included_conf) { - return -1; - } - - if (config_get_lines_aux(included_conf, config, extended, 1, NULL, - opened_lst, recursion_level+1, config_last) < 0) { - tor_free(included_conf); - return -1; - } - - tor_free(included_conf); - return 0; -} - -/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the - * list of configuration settings obtained and <b>list_last</b> to the last - * element of the same list. <b>opened_lst</b> will have a list of opened - * files if provided. Return 0 on success, -1 on failure. */ -static int -config_process_include(const char *path, int recursion_level, int extended, - config_line_t **list, config_line_t **list_last, - smartlist_t *opened_lst) -{ - config_line_t *ret_list = NULL; - config_line_t **next = &ret_list; - - smartlist_t *config_files = config_get_file_list(path, opened_lst); - if (!config_files) { - return -1; - } - - int rv = -1; - SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { - config_line_t *included_config = NULL; - if (config_get_included_config(config_file, recursion_level, extended, - &included_config, list_last, - opened_lst) < 0) { - goto done; - } - - *next = included_config; - if (*list_last) - next = &(*list_last)->next; - - } SMARTLIST_FOREACH_END(config_file); - *list = ret_list; - rv = 0; - - done: - SMARTLIST_FOREACH(config_files, char *, f, tor_free(f)); - smartlist_free(config_files); - return rv; + NULL, NULL); } /** @@ -535,4 +397,3 @@ parse_config_line_from_str_verbose(const char *line, char **key_out, return line; } - diff --git a/src/common/confline.h b/src/lib/encoding/confline.h index 772a9bbbdc..41f1200947 100644 --- a/src/common/confline.h +++ b/src/lib/encoding/confline.h @@ -1,13 +1,19 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * \file confline.h + * + * \brief Header for confline.c + **/ + #ifndef TOR_CONFLINE_H #define TOR_CONFLINE_H -#include "container.h" +struct smartlist_t; /** Ordinary configuration line. */ #define CONFIG_LINE_NORMAL 0 @@ -44,10 +50,6 @@ const config_line_t *config_line_find(const config_line_t *lines, const char *key); int config_lines_eq(config_line_t *a, config_line_t *b); int config_count_key(const config_line_t *a, const char *key); -int config_get_lines(const char *string, config_line_t **result, int extended); -int config_get_lines_include(const char *string, config_line_t **result, - int extended, int *has_include, - smartlist_t *opened_lst); void config_free_lines_(config_line_t *front); #define config_free_lines(front) \ do { \ @@ -57,5 +59,20 @@ void config_free_lines_(config_line_t *front); const char *parse_config_line_from_str_verbose(const char *line, char **key_out, char **value_out, const char **err_out); -#endif /* !defined(TOR_CONFLINE_H) */ +int config_get_lines(const char *string, struct config_line_t **result, + int extended); + +typedef int (*include_handler_fn)(const char *, int, int, + struct config_line_t **, + struct config_line_t **, + struct smartlist_t *); + +int config_get_lines_aux(const char *string, struct config_line_t **result, + int extended, + int allow_include, int *has_include, + struct smartlist_t *opened_lst, int recursion_level, + config_line_t **last, + include_handler_fn handle_include); + +#endif /* !defined(TOR_CONFLINE_H) */ diff --git a/src/lib/encoding/cstring.c b/src/lib/encoding/cstring.c new file mode 100644 index 0000000000..994a52e70c --- /dev/null +++ b/src/lib/encoding/cstring.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file cstring.c + * + * \brief Decode data that has been written as a C literal. + **/ + +#include "lib/encoding/cstring.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/compat_ctype.h" + +#include <string.h> + +#define TOR_ISODIGIT(c) ('0' <= (c) && (c) <= '7') + +/** Given a c-style double-quoted escaped string in <b>s</b>, extract and + * decode its contents into a newly allocated string. On success, assign this + * string to *<b>result</b>, assign its length to <b>size_out</b> (if + * provided), and return a pointer to the position in <b>s</b> immediately + * after the string. On failure, return NULL. + */ +const char * +unescape_string(const char *s, char **result, size_t *size_out) +{ + const char *cp; + char *out; + if (s[0] != '\"') + return NULL; + cp = s+1; + while (1) { + switch (*cp) { + case '\0': + case '\n': + return NULL; + case '\"': + goto end_of_loop; + case '\\': + if (cp[1] == 'x' || cp[1] == 'X') { + if (!(TOR_ISXDIGIT(cp[2]) && TOR_ISXDIGIT(cp[3]))) + return NULL; + cp += 4; + } else if (TOR_ISODIGIT(cp[1])) { + cp += 2; + if (TOR_ISODIGIT(*cp)) ++cp; + if (TOR_ISODIGIT(*cp)) ++cp; + } else if (cp[1] == 'n' || cp[1] == 'r' || cp[1] == 't' || cp[1] == '"' + || cp[1] == '\\' || cp[1] == '\'') { + cp += 2; + } else { + return NULL; + } + break; + default: + ++cp; + break; + } + } + end_of_loop: + out = *result = tor_malloc(cp-s + 1); + cp = s+1; + while (1) { + switch (*cp) + { + case '\"': + *out = '\0'; + if (size_out) *size_out = out - *result; + return cp+1; + + /* LCOV_EXCL_START -- we caught this in parse_config_from_line. */ + case '\0': + tor_fragile_assert(); + tor_free(*result); + return NULL; + /* LCOV_EXCL_STOP */ + case '\\': + switch (cp[1]) + { + case 'n': *out++ = '\n'; cp += 2; break; + case 'r': *out++ = '\r'; cp += 2; break; + case 't': *out++ = '\t'; cp += 2; break; + case 'x': case 'X': + { + int x1, x2; + + x1 = hex_decode_digit(cp[2]); + x2 = hex_decode_digit(cp[3]); + if (x1 == -1 || x2 == -1) { + /* LCOV_EXCL_START */ + /* we caught this above in the initial loop. */ + tor_assert_nonfatal_unreached(); + tor_free(*result); + return NULL; + /* LCOV_EXCL_STOP */ + } + + *out++ = ((x1<<4) + x2); + cp += 4; + } + break; + case '0': case '1': case '2': case '3': case '4': case '5': + case '6': case '7': + { + int n = cp[1]-'0'; + cp += 2; + if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } + if (TOR_ISODIGIT(*cp)) { n = n*8 + *cp-'0'; cp++; } + if (n > 255) { tor_free(*result); return NULL; } + *out++ = (char)n; + } + break; + case '\'': + case '\"': + case '\\': + case '\?': + *out++ = cp[1]; + cp += 2; + break; + + /* LCOV_EXCL_START */ + default: + /* we caught this above in the initial loop. */ + tor_assert_nonfatal_unreached(); + tor_free(*result); return NULL; + /* LCOV_EXCL_STOP */ + } + break; + default: + *out++ = *cp++; + } + } +} diff --git a/src/lib/encoding/cstring.h b/src/lib/encoding/cstring.h new file mode 100644 index 0000000000..2da109d958 --- /dev/null +++ b/src/lib/encoding/cstring.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file cstring.h + * + * \brief Header for cstring.c + **/ + +#ifndef TOR_CSTRING_H +#define TOR_CSTRING_H + +#include <stddef.h> +const char *unescape_string(const char *s, char **result, size_t *size_out); + +#endif /* !defined(TOR_CSTRING_H) */ diff --git a/src/lib/encoding/include.am b/src/lib/encoding/include.am new file mode 100644 index 0000000000..868e531b6b --- /dev/null +++ b/src/lib/encoding/include.am @@ -0,0 +1,24 @@ +noinst_LIBRARIES += src/lib/libtor-encoding.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-encoding-testing.a +endif + +src_lib_libtor_encoding_a_SOURCES = \ + src/lib/encoding/binascii.c \ + src/lib/encoding/confline.c \ + src/lib/encoding/cstring.c \ + src/lib/encoding/keyval.c \ + src/lib/encoding/time_fmt.c + +src_lib_libtor_encoding_testing_a_SOURCES = \ + $(src_lib_libtor_encoding_a_SOURCES) +src_lib_libtor_encoding_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_encoding_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/encoding/binascii.h \ + src/lib/encoding/confline.h \ + src/lib/encoding/cstring.h \ + src/lib/encoding/keyval.h \ + src/lib/encoding/time_fmt.h diff --git a/src/lib/encoding/keyval.c b/src/lib/encoding/keyval.c new file mode 100644 index 0000000000..53ee776fe7 --- /dev/null +++ b/src/lib/encoding/keyval.c @@ -0,0 +1,52 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file keyval.c + * + * \brief Handle data encoded as a key=value pair. + **/ + +#include "orconfig.h" +#include "lib/encoding/keyval.h" +#include "lib/log/escape.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <stdlib.h> +#include <string.h> + +/** Return true if <b>string</b> is a valid 'key=[value]' string. + * "value" is optional, to indicate the empty string. Log at logging + * <b>severity</b> if something ugly happens. */ +int +string_is_key_value(int severity, const char *string) +{ + /* position of equal sign in string */ + const char *equal_sign_pos = NULL; + + tor_assert(string); + + if (strlen(string) < 2) { /* "x=" is shortest args string */ + tor_log(severity, LD_GENERAL, "'%s' is too short to be a k=v value.", + escaped(string)); + return 0; + } + + equal_sign_pos = strchr(string, '='); + if (!equal_sign_pos) { + tor_log(severity, LD_GENERAL, "'%s' is not a k=v value.", escaped(string)); + return 0; + } + + /* validate that the '=' is not in the beginning of the string. */ + if (equal_sign_pos == string) { + tor_log(severity, LD_GENERAL, "'%s' is not a valid k=v value.", + escaped(string)); + return 0; + } + + return 1; +} diff --git a/src/lib/encoding/keyval.h b/src/lib/encoding/keyval.h new file mode 100644 index 0000000000..8bf0797627 --- /dev/null +++ b/src/lib/encoding/keyval.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file keyval.h + * + * \brief Header for keyval.c + **/ + +#ifndef TOR_KEYVAL_H +#define TOR_KEYVAL_H + +int string_is_key_value(int severity, const char *string); + +#endif diff --git a/src/lib/encoding/time_fmt.c b/src/lib/encoding/time_fmt.c new file mode 100644 index 0000000000..ea9c8e9fd1 --- /dev/null +++ b/src/lib/encoding/time_fmt.c @@ -0,0 +1,503 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file time_fmt.c + * + * \brief Encode and decode time in various formats. + * + * This module is higher-level than the conversion functions in "wallclock", + * and handles a larger variety of types. It converts between different time + * formats, and encodes and decodes them from strings. + **/ + +#include "lib/encoding/time_fmt.h" +#include "lib/log/torlog.h" +#include "lib/log/escape.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" +#include "lib/wallclock/tm_cvt.h" + +#include <string.h> +#include <time.h> + +/** As localtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in local time, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +struct tm * +tor_localtime_r(const time_t *timep, struct tm *result) +{ + char *err = NULL; + struct tm *r = tor_localtime_r_msg(timep, result, &err); + if (err) { + log_warn(LD_BUG, "%s", err); + tor_free(err); + } + return r; +} + +/** As gmtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in UTC, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +struct tm * +tor_gmtime_r(const time_t *timep, struct tm *result) +{ + char *err = NULL; + struct tm *r = tor_gmtime_r_msg(timep, result, &err); + if (err) { + log_warn(LD_BUG, "%s", err); + tor_free(err); + } + return r; +} + +/** Yield true iff <b>y</b> is a leap-year. */ +#define IS_LEAPYEAR(y) (!(y % 4) && ((y % 100) || !(y % 400))) +/** Helper: Return the number of leap-days between Jan 1, y1 and Jan 1, y2. */ +static int +n_leapdays(int year1, int year2) +{ + --year1; + --year2; + return (year2/4 - year1/4) - (year2/100 - year1/100) + + (year2/400 - year1/400); +} +/** Number of days per month in non-leap year; used by tor_timegm and + * parse_rfc1123_time. */ +static const int days_per_month[] = + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/** Compute a time_t given a struct tm. The result is given in UTC, and + * does not account for leap seconds. Return 0 on success, -1 on failure. + */ +int +tor_timegm(const struct tm *tm, time_t *time_out) +{ + /* This is a pretty ironclad timegm implementation, snarfed from Python2.2. + * It's way more brute-force than fiddling with tzset(). + * + * We use int64_t rather than time_t to avoid overflow on multiplication on + * platforms with 32-bit time_t. Since year is clipped to INT32_MAX, and + * since 365 * 24 * 60 * 60 is approximately 31 million, it's not possible + * for INT32_MAX years to overflow int64_t when converted to seconds. */ + int64_t year, days, hours, minutes, seconds; + int i, invalid_year, dpm; + + /* Initialize time_out to 0 for now, to avoid bad usage in case this function + fails and the caller ignores the return value. */ + tor_assert(time_out); + *time_out = 0; + + /* avoid int overflow on addition */ + if (tm->tm_year < INT32_MAX-1900) { + year = tm->tm_year + 1900; + } else { + /* clamp year */ + year = INT32_MAX; + } + invalid_year = (year < 1970 || tm->tm_year >= INT32_MAX-1900); + + if (tm->tm_mon >= 0 && tm->tm_mon <= 11) { + dpm = days_per_month[tm->tm_mon]; + if (tm->tm_mon == 1 && !invalid_year && IS_LEAPYEAR(tm->tm_year)) { + dpm = 29; + } + } else { + /* invalid month - default to 0 days per month */ + dpm = 0; + } + + if (invalid_year || + tm->tm_mon < 0 || tm->tm_mon > 11 || + tm->tm_mday < 1 || tm->tm_mday > dpm || + tm->tm_hour < 0 || tm->tm_hour > 23 || + tm->tm_min < 0 || tm->tm_min > 59 || + tm->tm_sec < 0 || tm->tm_sec > 60) { + log_warn(LD_BUG, "Out-of-range argument to tor_timegm"); + return -1; + } + days = 365 * (year-1970) + n_leapdays(1970,(int)year); + for (i = 0; i < tm->tm_mon; ++i) + days += days_per_month[i]; + if (tm->tm_mon > 1 && IS_LEAPYEAR(year)) + ++days; + days += tm->tm_mday - 1; + hours = days*24 + tm->tm_hour; + + minutes = hours*60 + tm->tm_min; + seconds = minutes*60 + tm->tm_sec; + /* Check that "seconds" will fit in a time_t. On platforms where time_t is + * 32-bit, this check will fail for dates in and after 2038. + * + * We already know that "seconds" can't be negative because "year" >= 1970 */ +#if SIZEOF_TIME_T < 8 + if (seconds < TIME_MIN || seconds > TIME_MAX) { + log_warn(LD_BUG, "Result does not fit in tor_timegm"); + return -1; + } +#endif /* SIZEOF_TIME_T < 8 */ + *time_out = (time_t)seconds; + return 0; +} + +/* strftime is locale-specific, so we need to replace those parts */ + +/** A c-locale array of 3-letter names of weekdays, starting with Sun. */ +static const char *WEEKDAY_NAMES[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +/** A c-locale array of 3-letter names of months, starting with Jan. */ +static const char *MONTH_NAMES[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +/** Set <b>buf</b> to the RFC1123 encoding of the UTC value of <b>t</b>. + * The buffer must be at least RFC1123_TIME_LEN+1 bytes long. + * + * (RFC1123 format is "Fri, 29 Sep 2006 15:54:20 GMT". Note the "GMT" + * rather than "UTC".) + */ +void +format_rfc1123_time(char *buf, time_t t) +{ + struct tm tm; + + tor_gmtime_r(&t, &tm); + + strftime(buf, RFC1123_TIME_LEN+1, "___, %d ___ %Y %H:%M:%S GMT", &tm); + tor_assert(tm.tm_wday >= 0); + tor_assert(tm.tm_wday <= 6); + memcpy(buf, WEEKDAY_NAMES[tm.tm_wday], 3); + tor_assert(tm.tm_mon >= 0); + tor_assert(tm.tm_mon <= 11); + memcpy(buf+8, MONTH_NAMES[tm.tm_mon], 3); +} + +/** Parse the (a subset of) the RFC1123 encoding of some time (in UTC) from + * <b>buf</b>, and store the result in *<b>t</b>. + * + * Note that we only accept the subset generated by format_rfc1123_time above, + * not the full range of formats suggested by RFC 1123. + * + * Return 0 on success, -1 on failure. +*/ +int +parse_rfc1123_time(const char *buf, time_t *t) +{ + struct tm tm; + char month[4]; + char weekday[4]; + int i, m, invalid_year; + unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; + unsigned dpm; + + if (strlen(buf) != RFC1123_TIME_LEN) + return -1; + memset(&tm, 0, sizeof(tm)); + if (tor_sscanf(buf, "%3s, %2u %3s %u %2u:%2u:%2u GMT", weekday, + &tm_mday, month, &tm_year, &tm_hour, + &tm_min, &tm_sec) < 7) { + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); + tor_free(esc); + return -1; + } + + m = -1; + for (i = 0; i < 12; ++i) { + if (!strcmp(month, MONTH_NAMES[i])) { + m = i; + break; + } + } + if (m<0) { + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, "Got invalid RFC1123 time %s: No such month", esc); + tor_free(esc); + return -1; + } + tm.tm_mon = m; + + invalid_year = (tm_year >= INT32_MAX || tm_year < 1970); + tor_assert(m >= 0 && m <= 11); + dpm = days_per_month[m]; + if (m == 1 && !invalid_year && IS_LEAPYEAR(tm_year)) { + dpm = 29; + } + + if (invalid_year || tm_mday < 1 || tm_mday > dpm || + tm_hour > 23 || tm_min > 59 || tm_sec > 60) { + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, "Got invalid RFC1123 time %s", esc); + tor_free(esc); + return -1; + } + tm.tm_mday = (int)tm_mday; + tm.tm_year = (int)tm_year; + tm.tm_hour = (int)tm_hour; + tm.tm_min = (int)tm_min; + tm.tm_sec = (int)tm_sec; + + if (tm.tm_year < 1970) { + /* LCOV_EXCL_START + * XXXX I think this is dead code; we already checked for + * invalid_year above. */ + tor_assert_nonfatal_unreached(); + char *esc = esc_for_log(buf); + log_warn(LD_GENERAL, + "Got invalid RFC1123 time %s. (Before 1970)", esc); + tor_free(esc); + return -1; + /* LCOV_EXCL_STOP */ + } + tm.tm_year -= 1900; + + return tor_timegm(&tm, t); +} + +/** Set <b>buf</b> to the ISO8601 encoding of the local value of <b>t</b>. + * The buffer must be at least ISO_TIME_LEN+1 bytes long. + * + * (ISO8601 format is 2006-10-29 10:57:20) + */ +void +format_local_iso_time(char *buf, time_t t) +{ + struct tm tm; + strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_localtime_r(&t, &tm)); +} + +/** Set <b>buf</b> to the ISO8601 encoding of the GMT value of <b>t</b>. + * The buffer must be at least ISO_TIME_LEN+1 bytes long. + */ +void +format_iso_time(char *buf, time_t t) +{ + struct tm tm; + strftime(buf, ISO_TIME_LEN+1, "%Y-%m-%d %H:%M:%S", tor_gmtime_r(&t, &tm)); +} + +/** As format_local_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid + * embedding an internal space. */ +void +format_local_iso_time_nospace(char *buf, time_t t) +{ + format_local_iso_time(buf, t); + buf[10] = 'T'; +} + +/** As format_iso_time, but use the yyyy-mm-ddThh:mm:ss format to avoid + * embedding an internal space. */ +void +format_iso_time_nospace(char *buf, time_t t) +{ + format_iso_time(buf, t); + buf[10] = 'T'; +} + +/** As format_iso_time_nospace, but include microseconds in decimal + * fixed-point format. Requires that buf be at least ISO_TIME_USEC_LEN+1 + * bytes long. */ +void +format_iso_time_nospace_usec(char *buf, const struct timeval *tv) +{ + tor_assert(tv); + format_iso_time_nospace(buf, (time_t)tv->tv_sec); + tor_snprintf(buf+ISO_TIME_LEN, 8, ".%06d", (int)tv->tv_usec); +} + +/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, + * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on + * failure. Ignore extraneous stuff in <b>cp</b> after the end of the time + * string, unless <b>strict</b> is set. If <b>nospace</b> is set, + * expect the YYYY-MM-DDTHH:MM:SS format. */ +int +parse_iso_time_(const char *cp, time_t *t, int strict, int nospace) +{ + struct tm st_tm; + unsigned int year=0, month=0, day=0, hour=0, minute=0, second=0; + int n_fields; + char extra_char, separator_char; + n_fields = tor_sscanf(cp, "%u-%2u-%2u%c%2u:%2u:%2u%c", + &year, &month, &day, + &separator_char, + &hour, &minute, &second, &extra_char); + if (strict ? (n_fields != 7) : (n_fields < 7)) { + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); + tor_free(esc); + return -1; + } + if (separator_char != (nospace ? 'T' : ' ')) { + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "ISO time %s was unparseable", esc); + tor_free(esc); + return -1; + } + if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 || + hour > 23 || minute > 59 || second > 60 || year >= INT32_MAX) { + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "ISO time %s was nonsensical", esc); + tor_free(esc); + return -1; + } + st_tm.tm_year = (int)year-1900; + st_tm.tm_mon = month-1; + st_tm.tm_mday = day; + st_tm.tm_hour = hour; + st_tm.tm_min = minute; + st_tm.tm_sec = second; + st_tm.tm_wday = 0; /* Should be ignored. */ + + if (st_tm.tm_year < 70) { + /* LCOV_EXCL_START + * XXXX I think this is dead code; we already checked for + * year < 1970 above. */ + tor_assert_nonfatal_unreached(); + char *esc = esc_for_log(cp); + log_warn(LD_GENERAL, "Got invalid ISO time %s. (Before 1970)", esc); + tor_free(esc); + return -1; + /* LCOV_EXCL_STOP */ + } + return tor_timegm(&st_tm, t); +} + +/** Given an ISO-formatted UTC time value (after the epoch) in <b>cp</b>, + * parse it and store its value in *<b>t</b>. Return 0 on success, -1 on + * failure. Reject the string if any characters are present after the time. + */ +int +parse_iso_time(const char *cp, time_t *t) +{ + return parse_iso_time_(cp, t, 1, 0); +} + +/** + * As parse_iso_time, but parses a time encoded by format_iso_time_nospace(). + */ +int +parse_iso_time_nospace(const char *cp, time_t *t) +{ + return parse_iso_time_(cp, t, 1, 1); +} + +/** Given a <b>date</b> in one of the three formats allowed by HTTP (ugh), + * parse it into <b>tm</b>. Return 0 on success, negative on failure. */ +int +parse_http_time(const char *date, struct tm *tm) +{ + const char *cp; + char month[4]; + char wkday[4]; + int i; + unsigned tm_mday, tm_year, tm_hour, tm_min, tm_sec; + + tor_assert(tm); + memset(tm, 0, sizeof(*tm)); + + /* First, try RFC1123 or RFC850 format: skip the weekday. */ + if ((cp = strchr(date, ','))) { + ++cp; + if (*cp != ' ') + return -1; + ++cp; + if (tor_sscanf(cp, "%2u %3s %4u %2u:%2u:%2u GMT", + &tm_mday, month, &tm_year, + &tm_hour, &tm_min, &tm_sec) == 6) { + /* rfc1123-date */ + tm_year -= 1900; + } else if (tor_sscanf(cp, "%2u-%3s-%2u %2u:%2u:%2u GMT", + &tm_mday, month, &tm_year, + &tm_hour, &tm_min, &tm_sec) == 6) { + /* rfc850-date */ + } else { + return -1; + } + } else { + /* No comma; possibly asctime() format. */ + if (tor_sscanf(date, "%3s %3s %2u %2u:%2u:%2u %4u", + wkday, month, &tm_mday, + &tm_hour, &tm_min, &tm_sec, &tm_year) == 7) { + tm_year -= 1900; + } else { + return -1; + } + } + tm->tm_mday = (int)tm_mday; + tm->tm_year = (int)tm_year; + tm->tm_hour = (int)tm_hour; + tm->tm_min = (int)tm_min; + tm->tm_sec = (int)tm_sec; + tm->tm_wday = 0; /* Leave this unset. */ + + month[3] = '\0'; + /* Okay, now decode the month. */ + /* set tm->tm_mon to dummy value so the check below fails. */ + tm->tm_mon = -1; + for (i = 0; i < 12; ++i) { + if (!strcasecmp(MONTH_NAMES[i], month)) { + tm->tm_mon = i; + } + } + + if (tm->tm_year < 0 || + tm->tm_mon < 0 || tm->tm_mon > 11 || + tm->tm_mday < 1 || tm->tm_mday > 31 || + tm->tm_hour < 0 || tm->tm_hour > 23 || + tm->tm_min < 0 || tm->tm_min > 59 || + tm->tm_sec < 0 || tm->tm_sec > 60) + return -1; /* Out of range, or bad month. */ + + return 0; +} + +/** Given an <b>interval</b> in seconds, try to write it to the + * <b>out_len</b>-byte buffer in <b>out</b> in a human-readable form. + * Returns a non-negative integer on success, -1 on failure. + */ +int +format_time_interval(char *out, size_t out_len, long interval) +{ + /* We only report seconds if there's no hours. */ + long sec = 0, min = 0, hour = 0, day = 0; + + /* -LONG_MIN is LONG_MAX + 1, which causes signed overflow */ + if (interval < -LONG_MAX) + interval = LONG_MAX; + else if (interval < 0) + interval = -interval; + + if (interval >= 86400) { + day = interval / 86400; + interval %= 86400; + } + if (interval >= 3600) { + hour = interval / 3600; + interval %= 3600; + } + if (interval >= 60) { + min = interval / 60; + interval %= 60; + } + sec = interval; + + if (day) { + return tor_snprintf(out, out_len, "%ld days, %ld hours, %ld minutes", + day, hour, min); + } else if (hour) { + return tor_snprintf(out, out_len, "%ld hours, %ld minutes", hour, min); + } else if (min) { + return tor_snprintf(out, out_len, "%ld minutes, %ld seconds", min, sec); + } else { + return tor_snprintf(out, out_len, "%ld seconds", sec); + } +} diff --git a/src/lib/encoding/time_fmt.h b/src/lib/encoding/time_fmt.h new file mode 100644 index 0000000000..2892442adf --- /dev/null +++ b/src/lib/encoding/time_fmt.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file time_fmt.h + * + * \brief Header for time_fmt.c + **/ + +#ifndef TOR_TIME_FMT_H +#define TOR_TIME_FMT_H + +#include "orconfig.h" +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +struct tm; +struct timeval; + +struct tm *tor_localtime_r(const time_t *timep, struct tm *result); +struct tm *tor_gmtime_r(const time_t *timep, struct tm *result); +int tor_timegm(const struct tm *tm, time_t *time_out); + +#define RFC1123_TIME_LEN 29 +void format_rfc1123_time(char *buf, time_t t); +int parse_rfc1123_time(const char *buf, time_t *t); +#define ISO_TIME_LEN 19 +#define ISO_TIME_USEC_LEN (ISO_TIME_LEN+7) +void format_local_iso_time(char *buf, time_t t); +void format_iso_time(char *buf, time_t t); +void format_local_iso_time_nospace(char *buf, time_t t); +void format_iso_time_nospace(char *buf, time_t t); +void format_iso_time_nospace_usec(char *buf, const struct timeval *tv); +int parse_iso_time_(const char *cp, time_t *t, int strict, int nospace); +int parse_iso_time(const char *buf, time_t *t); +int parse_iso_time_nospace(const char *cp, time_t *t); +int parse_http_time(const char *buf, struct tm *tm); +int format_time_interval(char *out, size_t out_len, long interval); + +#endif diff --git a/src/lib/err/.may_include b/src/lib/err/.may_include new file mode 100644 index 0000000000..48cc0ef088 --- /dev/null +++ b/src/lib/err/.may_include @@ -0,0 +1,3 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h diff --git a/src/common/backtrace.c b/src/lib/err/backtrace.c index f2498b2aa6..d18a595c34 100644 --- a/src/common/backtrace.c +++ b/src/lib/err/backtrace.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,12 +11,14 @@ * family of functions, which are sometimes provided by libc and sometimes * provided by libexecinfo. We tie into the sigaction() backend in order to * detect crashes. + * + * This is one of the lowest-level modules, since nearly everything needs to + * be able to log an error. As such, it doesn't call the log module or any + * other higher-level modules directly. */ #include "orconfig.h" -#include "compat.h" -#include "util.h" -#include "torlog.h" +#include "lib/err/torerr.h" #ifdef HAVE_EXECINFO_H #include <execinfo.h> @@ -30,6 +32,10 @@ #ifdef HAVE_SIGNAL_H #include <signal.h> #endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> #ifdef HAVE_CYGWIN_SIGNAL_H #include <cygwin/signal.h> @@ -39,8 +45,13 @@ #include <ucontext.h> #endif /* defined(HAVE_CYGWIN_SIGNAL_H) || ... */ +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#endif + #define EXPOSE_CLEAN_BACKTRACE -#include "backtrace.h" +#include "lib/err/backtrace.h" +#include "lib/err/torerr.h" #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) @@ -51,17 +62,21 @@ #define NO_BACKTRACE_IMPL #endif -/** Version of Tor to report in backtrace messages. */ -static char *bt_version = NULL; +// Redundant with util.h, but doing it here so we can avoid that dependency. +#define raw_free free #ifdef USE_BACKTRACE +/** Version of Tor to report in backtrace messages. */ +static char bt_version[128] = ""; + /** Largest stack depth to try to dump. */ #define MAX_DEPTH 256 /** Static allocation of stack to dump. This is static so we avoid stack * pressure. */ static void *cb_buf[MAX_DEPTH]; -/** Protects cb_buf from concurrent access */ -static tor_mutex_t cb_buf_mutex; +/** Protects cb_buf from concurrent access. Pthreads, since this code + * is Unix-only, and since this code needs to be lowest-level. */ +static pthread_mutex_t cb_buf_mutex = PTHREAD_MUTEX_INITIALIZER; /** Change a stacktrace in <b>stack</b> of depth <b>depth</b> so that it will * log the correct function from which a signal was received with context @@ -94,33 +109,35 @@ clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx) } /** Log a message <b>msg</b> at <b>severity</b> in <b>domain</b>, and follow - * that with a backtrace log. */ + * that with a backtrace log. Send messages via the tor_log function at + * logger". */ void -log_backtrace(int severity, int domain, const char *msg) +log_backtrace_impl(int severity, int domain, const char *msg, + tor_log_fn logger) { size_t depth; char **symbols; size_t i; - tor_mutex_acquire(&cb_buf_mutex); + pthread_mutex_lock(&cb_buf_mutex); depth = backtrace(cb_buf, MAX_DEPTH); symbols = backtrace_symbols(cb_buf, (int)depth); - tor_log(severity, domain, "%s. Stack trace:", msg); + logger(severity, domain, "%s. Stack trace:", msg); if (!symbols) { /* LCOV_EXCL_START -- we can't provoke this. */ - tor_log(severity, domain, " Unable to generate backtrace."); + logger(severity, domain, " Unable to generate backtrace."); goto done; /* LCOV_EXCL_STOP */ } for (i=0; i < depth; ++i) { - tor_log(severity, domain, " %s", symbols[i]); + logger(severity, domain, " %s", symbols[i]); } raw_free(symbols); done: - tor_mutex_release(&cb_buf_mutex); + pthread_mutex_unlock(&cb_buf_mutex); } static void crash_handler(int sig, siginfo_t *si, void *ctx_) @@ -155,18 +172,34 @@ crash_handler(int sig, siginfo_t *si, void *ctx_) abort(); } +/** Write a backtrace to all of the emergency-error fds. */ +void +dump_stack_symbols_to_error_fds(void) +{ + int n_fds, i; + const int *fds = NULL; + size_t depth; + + depth = backtrace(cb_buf, MAX_DEPTH); + + n_fds = tor_log_get_sigsafe_err_fds(&fds); + for (i=0; i < n_fds; ++i) + backtrace_symbols_fd(cb_buf, (int)depth, fds[i]); +} + /** Install signal handlers as needed so that when we crash, we produce a - * useful stack trace. Return 0 on success, -1 on failure. */ + * useful stack trace. Return 0 on success, -errno on failure. */ static int -install_bt_handler(void) +install_bt_handler(const char *software) { int trap_signals[] = { SIGSEGV, SIGILL, SIGFPE, SIGBUS, SIGSYS, SIGIO, -1 }; int i, rv=0; - struct sigaction sa; + strncpy(bt_version, software, sizeof(bt_version) - 1); + bt_version[sizeof(bt_version) - 1] = 0; - tor_mutex_init(&cb_buf_mutex); + struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_sigaction = crash_handler; @@ -176,8 +209,7 @@ install_bt_handler(void) for (i = 0; trap_signals[i] >= 0; ++i) { if (sigaction(trap_signals[i], &sa, NULL) == -1) { /* LCOV_EXCL_START */ - log_warn(LD_BUG, "Sigaction failed: %s", strerror(errno)); - rv = -1; + rv = -errno; /* LCOV_EXCL_STOP */ } } @@ -200,20 +232,21 @@ install_bt_handler(void) static void remove_bt_handler(void) { - tor_mutex_uninit(&cb_buf_mutex); } #endif /* defined(USE_BACKTRACE) */ #ifdef NO_BACKTRACE_IMPL void -log_backtrace(int severity, int domain, const char *msg) +log_backtrace_impl(int severity, int domain, const char *msg, + tor_log_fn logger) { - tor_log(severity, domain, "%s. (Stack trace not available)", msg); + logger(severity, domain, "%s. (Stack trace not available)", msg); } static int -install_bt_handler(void) +install_bt_handler(const char *software) { + (void) software; return 0; } @@ -221,19 +254,24 @@ static void remove_bt_handler(void) { } + +void +dump_stack_symbols_to_error_fds(void) +{ +} #endif /* defined(NO_BACKTRACE_IMPL) */ /** Set up code to handle generating error messages on crashes. */ int configure_backtrace_handler(const char *tor_version) { - tor_free(bt_version); - if (tor_version) - tor_asprintf(&bt_version, "Tor %s", tor_version); - else - tor_asprintf(&bt_version, "Tor"); + char version[128] = "Tor\0"; - return install_bt_handler(); + if (tor_version) { + snprintf(version, sizeof(version), "Tor %s", tor_version); + } + + return install_bt_handler(version); } /** Perform end-of-process cleanup for code that generates error messages on @@ -242,7 +280,4 @@ void clean_up_backtrace_handler(void) { remove_bt_handler(); - - tor_free(bt_version); } - diff --git a/src/common/backtrace.h b/src/lib/err/backtrace.h index 3d0ab8a90a..70c43484f5 100644 --- a/src/common/backtrace.h +++ b/src/lib/err/backtrace.h @@ -1,14 +1,29 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BACKTRACE_H #define TOR_BACKTRACE_H +/** + * \file backtrace.h + * + * \brief Header for backtrace.c + **/ + #include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +typedef void (*tor_log_fn)(int, unsigned, const char *fmt, ...) + CHECK_PRINTF(3,4); -void log_backtrace(int severity, int domain, const char *msg); +void log_backtrace_impl(int severity, int domain, const char *msg, + tor_log_fn logger); int configure_backtrace_handler(const char *tor_version); void clean_up_backtrace_handler(void); +void dump_stack_symbols_to_error_fds(void); + +#define log_backtrace(sev, dom, msg) \ + log_backtrace_impl((sev), (dom), (msg), tor_log) #ifdef EXPOSE_CLEAN_BACKTRACE #if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && \ @@ -18,4 +33,3 @@ void clean_backtrace(void **stack, size_t depth, const ucontext_t *ctx); #endif /* defined(EXPOSE_CLEAN_BACKTRACE) */ #endif /* !defined(TOR_BACKTRACE_H) */ - diff --git a/src/lib/err/include.am b/src/lib/err/include.am new file mode 100644 index 0000000000..f2a409c51e --- /dev/null +++ b/src/lib/err/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-err.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-err-testing.a +endif + +src_lib_libtor_err_a_SOURCES = \ + src/lib/err/backtrace.c \ + src/lib/err/torerr.c + +src_lib_libtor_err_testing_a_SOURCES = \ + $(src_lib_libtor_err_a_SOURCES) +src_lib_libtor_err_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_err_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/err/backtrace.h \ + src/lib/err/torerr.h diff --git a/src/lib/err/torerr.c b/src/lib/err/torerr.c new file mode 100644 index 0000000000..f9e139f967 --- /dev/null +++ b/src/lib/err/torerr.c @@ -0,0 +1,238 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file torerr.c + * + * \brief Handling code for unrecoverable emergencies, at a lower level + * than the logging code. + * + * There are plenty of places that things can go wrong in Tor's backend + * libraries: the allocator can fail, the locking subsystem can fail, and so + * on. But since these subsystems are used themselves by the logging module, + * they can't use the logging code directly to report their errors. + * + * As a workaround, the logging code provides this module with a set of raw + * fds to be used for reporting errors in the lowest-level Tor code. + */ + +#include "orconfig.h" +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_TIME_H +#include <time.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#include "lib/err/torerr.h" +#include "lib/err/backtrace.h" + +/** Array of fds to log crash-style warnings to. */ +static int sigsafe_log_fds[TOR_SIGSAFE_LOG_MAX_FDS] = { STDERR_FILENO }; +/** The number of elements used in sigsafe_log_fds */ +static int n_sigsafe_log_fds = 1; +/** Log granularity in milliseconds. */ +static int log_granularity = 1000; + +/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1 + * on failure. */ +static int +tor_log_err_sigsafe_write(const char *s) +{ + int i; + ssize_t r; + size_t len = strlen(s); + int err = 0; + for (i=0; i < n_sigsafe_log_fds; ++i) { + r = write(sigsafe_log_fds[i], s, len); + err += (r != (ssize_t)len); + } + return err ? -1 : 0; +} + +/** Given a list of string arguments ending with a NULL, writes them + * to our logs and to stderr (if possible). This function is safe to call + * from within a signal handler. */ +void +tor_log_err_sigsafe(const char *m, ...) +{ + va_list ap; + const char *x; + char timebuf[33]; + time_t now = time(NULL); + + if (!m) + return; + if (log_granularity >= 2000) { + int g = log_granularity / 1000; + now -= now % g; + } + timebuf[0] = now < 0 ? '-' : ' '; + if (now < 0) now = -now; + timebuf[1] = '\0'; + format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1); + tor_log_err_sigsafe_write("\n==========================================" + "================== T="); + tor_log_err_sigsafe_write(timebuf); + tor_log_err_sigsafe_write("\n"); + tor_log_err_sigsafe_write(m); + va_start(ap, m); + while ((x = va_arg(ap, const char*))) { + tor_log_err_sigsafe_write(x); + } + va_end(ap); +} + +/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from + * inside a signal handler or other emergency condition. Return the number of + * elements in the array. */ +int +tor_log_get_sigsafe_err_fds(const int **out) +{ + *out = sigsafe_log_fds; + return n_sigsafe_log_fds; +} + +/** + * Update the list of fds that get errors from inside a signal handler or + * other emergency condition. Ignore any beyond the first + * TOR_SIGSAFE_LOG_MAX_FDS. + */ +void +tor_log_set_sigsafe_err_fds(const int *fds, int n) +{ + if (n > TOR_SIGSAFE_LOG_MAX_FDS) { + n = TOR_SIGSAFE_LOG_MAX_FDS; + } + + memcpy(sigsafe_log_fds, fds, n * sizeof(int)); + n_sigsafe_log_fds = n; +} + +/** + * Set the granularity (in ms) to use when reporting fatal errors outside + * the logging system. + */ +void +tor_log_sigsafe_err_set_granularity(int ms) +{ + log_granularity = ms; +} + +/** + * Log an emergency assertion failure message. + * + * This kind of message is safe to send from within a log handler, + * a signal handler, or other emergency situation. + */ +void +tor_raw_assertion_failed_msg_(const char *file, int line, const char *expr, + const char *msg) +{ + char linebuf[16]; + format_dec_number_sigsafe(line, linebuf, sizeof(linebuf)); + tor_log_err_sigsafe("INTERNAL ERROR: Raw assertion failed at ", + file, ":", linebuf, ": ", expr, NULL); + if (msg) { + tor_log_err_sigsafe_write(msg); + tor_log_err_sigsafe_write("\n"); + } + + dump_stack_symbols_to_error_fds(); +} + +/* As format_{hex,dex}_number_sigsafe, but takes a <b>radix</b> argument + * in range 2..16 inclusive. */ +static int +format_number_sigsafe(unsigned long x, char *buf, int buf_len, + unsigned int radix) +{ + unsigned long tmp; + int len; + char *cp; + + /* NOT tor_assert. This needs to be safe to run from within a signal + * handler, and from within the 'tor_assert() has failed' code. Not even + * raw_assert(), since raw_assert() calls this function on failure. */ + if (radix < 2 || radix > 16) + return 0; + + /* Count how many digits we need. */ + tmp = x; + len = 1; + while (tmp >= radix) { + tmp /= radix; + ++len; + } + + /* Not long enough */ + if (!buf || len >= buf_len) + return 0; + + cp = buf + len; + *cp = '\0'; + do { + unsigned digit = (unsigned) (x % radix); + if (cp <= buf) { + /* Not tor_assert(); see above. */ + abort(); + } + --cp; + *cp = "0123456789ABCDEF"[digit]; + x /= radix; + } while (x); + + /* NOT tor_assert; see above. */ + if (cp != buf) { + abort(); // LCOV_EXCL_LINE + } + + return len; +} + +/** + * Helper function to output hex numbers from within a signal handler. + * + * Writes the nul-terminated hexadecimal digits of <b>x</b> into a buffer + * <b>buf</b> of size <b>buf_len</b>, and return the actual number of digits + * written, not counting the terminal NUL. + * + * If there is insufficient space, write nothing and return 0. + * + * This accepts an unsigned int because format_helper_exit_status() needs to + * call it with a signed int and an unsigned char, and since the C standard + * does not guarantee that an int is wider than a char (an int must be at + * least 16 bits but it is permitted for a char to be that wide as well), we + * can't assume a signed int is sufficient to accommodate an unsigned char. + * Thus, format_helper_exit_status() will still need to emit any require '-' + * on its own. + * + * For most purposes, you'd want to use tor_snprintf("%x") instead of this + * function; it's designed to be used in code paths where you can't call + * arbitrary C functions. + */ +int +format_hex_number_sigsafe(unsigned long x, char *buf, int buf_len) +{ + return format_number_sigsafe(x, buf, buf_len, 16); +} + +/** As format_hex_number_sigsafe, but format the number in base 10. */ +int +format_dec_number_sigsafe(unsigned long x, char *buf, int buf_len) +{ + return format_number_sigsafe(x, buf, buf_len, 10); +} diff --git a/src/lib/err/torerr.h b/src/lib/err/torerr.h new file mode 100644 index 0000000000..d4bba6916f --- /dev/null +++ b/src/lib/err/torerr.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file torerr.h + * + * \brief Headers for torerr.c. + **/ + +#ifndef TOR_TORERR_H +#define TOR_TORERR_H + +#include "lib/cc/compat_compiler.h" + +/* The raw_assert...() variants are for use within code that can't call + * tor_assertion_failed_() because of call circularity issues. */ +#define raw_assert(expr) STMT_BEGIN \ + if (!(expr)) { \ + tor_raw_assertion_failed_msg_(__FILE__, __LINE__, #expr, NULL); \ + abort(); \ + } \ + STMT_END +#define raw_assert_unreached(expr) raw_assert(0) +#define raw_assert_unreached_msg(msg) STMT_BEGIN \ + tor_raw_assertion_failed_msg_(__FILE__, __LINE__, "0", (msg)); \ + abort(); \ + STMT_END + +void tor_raw_assertion_failed_msg_(const char *file, int line, + const char *expr, + const char *msg); + +/** Maximum number of fds that will get notifications if we crash */ +#define TOR_SIGSAFE_LOG_MAX_FDS 8 + +void tor_log_err_sigsafe(const char *m, ...); +int tor_log_get_sigsafe_err_fds(const int **out); +void tor_log_set_sigsafe_err_fds(const int *fds, int n); +void tor_log_sigsafe_err_set_granularity(int ms); + +int format_hex_number_sigsafe(unsigned long x, char *buf, int max_len); +int format_dec_number_sigsafe(unsigned long x, char *buf, int max_len); + +#endif /* !defined(TOR_TORLOG_H) */ diff --git a/src/lib/evloop/.may_include b/src/lib/evloop/.may_include new file mode 100644 index 0000000000..30af508914 --- /dev/null +++ b/src/lib/evloop/.may_include @@ -0,0 +1,16 @@ +orconfig.h + +lib/cc/*.h +lib/crypt_ops/*.h +lib/evloop/*.h +lib/intmath/*.h +lib/log/*.h +lib/malloc/*.h +lib/net/*.h +lib/string/*.h +lib/testsupport/*.h +lib/thread/*.h +lib/time/*.h + +src/ext/timeouts/timeout.c +tor_queue.h
\ No newline at end of file diff --git a/src/common/compat_libevent.c b/src/lib/evloop/compat_libevent.c index e60eb148d8..5e5faf163c 100644 --- a/src/common/compat_libevent.c +++ b/src/lib/evloop/compat_libevent.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ +/* Copyright (c) 2009-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,17 +7,17 @@ */ #include "orconfig.h" -#include "compat.h" #define COMPAT_LIBEVENT_PRIVATE -#include "compat_libevent.h" +#include "lib/evloop/compat_libevent.h" -#include "crypto_rand.h" - -#include "util.h" -#include "torlog.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/string/compat_string.h" #include <event2/event.h> #include <event2/thread.h> +#include <string.h> /** A string which, if it appears in a libevent log, should be ignored. */ static const char *suppress_msg = NULL; @@ -533,4 +533,3 @@ tor_libevent_postfork(void) tor_assert(r == 0); } #endif /* defined(TOR_UNIT_TESTS) */ - diff --git a/src/common/compat_libevent.h b/src/lib/evloop/compat_libevent.h index 286a268122..0a50cfa667 100644 --- a/src/common/compat_libevent.h +++ b/src/lib/evloop/compat_libevent.h @@ -1,11 +1,12 @@ -/* Copyright (c) 2009-2017, The Tor Project, Inc. */ +/* Copyright (c) 2009-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_COMPAT_LIBEVENT_H #define TOR_COMPAT_LIBEVENT_H #include "orconfig.h" -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" +#include "lib/malloc/util_malloc.h" void configure_libevent_logging(void); void suppress_libevent_log_msg(const char *msg); @@ -19,6 +20,7 @@ void suppress_libevent_log_msg(const char *msg); struct event; struct event_base; +struct timeval; void tor_event_free_(struct event *ev); #define tor_event_free(ev) \ @@ -95,4 +97,3 @@ libevent_logging_callback(int severity, const char *msg); #endif /* defined(COMPAT_LIBEVENT_PRIVATE) */ #endif /* !defined(TOR_COMPAT_LIBEVENT_H) */ - diff --git a/src/lib/evloop/include.am b/src/lib/evloop/include.am new file mode 100644 index 0000000000..6b0076272a --- /dev/null +++ b/src/lib/evloop/include.am @@ -0,0 +1,26 @@ + +noinst_LIBRARIES += src/lib/libtor-evloop.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-evloop-testing.a +endif + +src_lib_libtor_evloop_a_SOURCES = \ + src/lib/evloop/compat_libevent.c \ + src/lib/evloop/procmon.c \ + src/lib/evloop/timers.c \ + src/lib/evloop/token_bucket.c \ + src/lib/evloop/workqueue.c + + +src_lib_libtor_evloop_testing_a_SOURCES = \ + $(src_lib_libtor_evloop_a_SOURCES) +src_lib_libtor_evloop_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_evloop_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/evloop/compat_libevent.h \ + src/lib/evloop/procmon.h \ + src/lib/evloop/timers.h \ + src/lib/evloop/token_bucket.h \ + src/lib/evloop/workqueue.h diff --git a/src/common/procmon.c b/src/lib/evloop/procmon.c index 73c14cd584..a923fbad74 100644 --- a/src/common/procmon.c +++ b/src/lib/evloop/procmon.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,9 +6,13 @@ * \brief Process-termination monitor functions **/ -#include "procmon.h" +#include "lib/evloop/procmon.h" -#include "util.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/parse_int.h" #ifdef HAVE_SIGNAL_H #include <signal.h> @@ -18,6 +22,7 @@ #endif #ifdef _WIN32 +#include <winsock2.h> #include <windows.h> #endif @@ -30,8 +35,8 @@ typedef int pid_t; #define PID_T_FORMAT "%d" #elif (SIZEOF_PID_T == SIZEOF_LONG) #define PID_T_FORMAT "%ld" -#elif (SIZEOF_PID_T == SIZEOF_INT64_T) -#define PID_T_FORMAT I64_FORMAT +#elif (SIZEOF_PID_T == 8) +#define PID_T_FORMAT "%"PRId64 #else #error Unknown: SIZEOF_PID_T #endif /* (0 == SIZEOF_PID_T) && defined(_WIN32) || ... */ @@ -329,4 +334,3 @@ tor_process_monitor_free_(tor_process_monitor_t *procmon) tor_free(procmon); } - diff --git a/src/common/procmon.h b/src/lib/evloop/procmon.h index 63777e4111..b596e5cc6d 100644 --- a/src/common/procmon.h +++ b/src/lib/evloop/procmon.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,10 +9,9 @@ #ifndef TOR_PROCMON_H #define TOR_PROCMON_H -#include "compat.h" -#include "compat_libevent.h" +#include "lib/evloop/compat_libevent.h" -#include "torlog.h" +#include "lib/log/torlog.h" typedef struct tor_process_monitor_t tor_process_monitor_t; diff --git a/src/common/timers.c b/src/lib/evloop/timers.c index 6f6236ed3b..c07bd2e726 100644 --- a/src/common/timers.c +++ b/src/lib/evloop/timers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,11 +31,18 @@ #define TOR_TIMERS_PRIVATE -#include "compat.h" -#include "compat_libevent.h" -#include "timers.h" -#include "torlog.h" -#include "util.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/evloop/timers.h" +#include "lib/intmath/muldiv.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/time/compat_time.h" + +#ifdef _WIN32 +// For struct timeval. +#include <winsock2.h> +#endif struct timeout_cb { timer_cb_fn_t cb; @@ -315,4 +322,3 @@ timer_disable(tor_timer_t *t) /* We don't reschedule the libevent timer here, since it's okay if it fires * early. */ } - diff --git a/src/common/timers.h b/src/lib/evloop/timers.h index 6d27f3e01e..2348c7b7c1 100644 --- a/src/common/timers.h +++ b/src/lib/evloop/timers.h @@ -1,11 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TIMERS_H #define TOR_TIMERS_H #include "orconfig.h" -#include "testsupport.h" +#include "lib/testsupport/testsupport.h" struct monotime_t; typedef struct timeout tor_timer_t; diff --git a/src/common/token_bucket.c b/src/lib/evloop/token_bucket.c index f2396ec58a..f7cd05c6c5 100644 --- a/src/common/token_bucket.c +++ b/src/lib/evloop/token_bucket.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -18,8 +18,12 @@ #define TOKEN_BUCKET_PRIVATE -#include "token_bucket.h" -#include "util_bug.h" +#include "lib/evloop/token_bucket.h" +#include "lib/log/util_bug.h" +#include "lib/intmath/cmp.h" +#include "lib/time/compat_time.h" + +#include <string.h> /** * Set the <b>rate</b> and <b>burst</b> value in a token_bucket_cfg. @@ -252,4 +256,3 @@ token_bucket_rw_dec(token_bucket_rw_t *bucket, flags |= TB_WRITE; return flags; } - diff --git a/src/common/token_bucket.h b/src/lib/evloop/token_bucket.h index 0e7832e838..787317fa1f 100644 --- a/src/common/token_bucket.h +++ b/src/lib/evloop/token_bucket.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2018, The Tor Project, Inc. */ +/* Copyright (c) 2018-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,8 +9,8 @@ #ifndef TOR_TOKEN_BUCKET_H #define TOR_TOKEN_BUCKET_H -#include "torint.h" -#include "testsupport.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" /** Largest allowable burst value for a token buffer. */ #define TOKEN_BUCKET_MAX_BURST INT32_MAX diff --git a/src/common/workqueue.c b/src/lib/evloop/workqueue.c index 563a98af96..4d36f352e3 100644 --- a/src/common/workqueue.c +++ b/src/lib/evloop/workqueue.c @@ -24,16 +24,21 @@ */ #include "orconfig.h" -#include "compat.h" -#include "compat_libevent.h" -#include "compat_threads.h" -#include "crypto_rand.h" -#include "util.h" -#include "workqueue.h" -#include "tor_queue.h" -#include "torlog.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/evloop/workqueue.h" + +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/intmath/weakrng.h" +#include "lib/log/ratelim.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/net/alertsock.h" +#include "lib/net/socket.h" +#include "lib/thread/threads.h" +#include "tor_queue.h" #include <event2/event.h> +#include <string.h> #define WORKQUEUE_PRIORITY_FIRST WQ_PRI_HIGH #define WORKQUEUE_PRIORITY_LAST WQ_PRI_LOW @@ -675,4 +680,3 @@ replyqueue_process(replyqueue_t *queue) tor_mutex_release(&queue->lock); } - diff --git a/src/common/workqueue.h b/src/lib/evloop/workqueue.h index e1fe612e2b..4e5c424be6 100644 --- a/src/common/workqueue.h +++ b/src/lib/evloop/workqueue.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_WORKQUEUE_H #define TOR_WORKQUEUE_H -#include "compat.h" +#include "lib/cc/torint.h" /** A replyqueue is used to tell the main thread about the outcome of * work that we queued for the workers. */ @@ -63,4 +63,3 @@ int threadpool_register_reply_event(threadpool_t *tp, void (*cb)(threadpool_t *tp)); #endif /* !defined(TOR_WORKQUEUE_H) */ - diff --git a/src/lib/fdio/.may_include b/src/lib/fdio/.may_include new file mode 100644 index 0000000000..30fd277b81 --- /dev/null +++ b/src/lib/fdio/.may_include @@ -0,0 +1,4 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/fdio/*.h diff --git a/src/lib/fdio/fdio.c b/src/lib/fdio/fdio.c new file mode 100644 index 0000000000..afb57e03dd --- /dev/null +++ b/src/lib/fdio/fdio.c @@ -0,0 +1,115 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file fdio.c + * + * \brief Low-level compatibility wrappers for fd-based IO. + **/ + +#include "orconfig.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "lib/fdio/fdio.h" +#include "lib/cc/torint.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +/** @{ */ +/** Some old versions of Unix didn't define constants for these values, + * and instead expect you to say 0, 1, or 2. */ +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif +#ifndef SEEK_END +#define SEEK_END 2 +#endif +/** @} */ + +/** Return the position of <b>fd</b> with respect to the start of the file. */ +off_t +tor_fd_getpos(int fd) +{ +#ifdef _WIN32 + return (off_t) _lseek(fd, 0, SEEK_CUR); +#else + return (off_t) lseek(fd, 0, SEEK_CUR); +#endif +} + +/** Move <b>fd</b> to the end of the file. Return -1 on error, 0 on success. + * If the file is a pipe, do nothing and succeed. + **/ +int +tor_fd_seekend(int fd) +{ +#ifdef _WIN32 + return _lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; +#else + off_t rc = lseek(fd, 0, SEEK_END) < 0 ? -1 : 0; +#ifdef ESPIPE + /* If we get an error and ESPIPE, then it's a pipe or a socket of a fifo: + * no need to worry. */ + if (rc < 0 && errno == ESPIPE) + rc = 0; +#endif /* defined(ESPIPE) */ + return (rc < 0) ? -1 : 0; +#endif /* defined(_WIN32) */ +} + +/** Move <b>fd</b> to position <b>pos</b> in the file. Return -1 on error, 0 + * on success. */ +int +tor_fd_setpos(int fd, off_t pos) +{ +#ifdef _WIN32 + return _lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; +#else + return lseek(fd, pos, SEEK_SET) < 0 ? -1 : 0; +#endif +} + +/** Replacement for ftruncate(fd, 0): move to the front of the file and remove + * all the rest of the file. Return -1 on error, 0 on success. */ +int +tor_ftruncate(int fd) +{ + /* Rumor has it that some versions of ftruncate do not move the file pointer. + */ + if (tor_fd_setpos(fd, 0) < 0) + return -1; + +#ifdef _WIN32 + return _chsize(fd, 0); +#else + return ftruncate(fd, 0); +#endif +} + +/** Minimal version of write_all, for use by logging. */ +int +write_all_to_fd_minimal(int fd, const char *buf, size_t count) +{ + size_t written = 0; + raw_assert(count < SSIZE_MAX); + + while (written < count) { + ssize_t result = write(fd, buf+written, count-written); + if (result<0) + return -1; + written += result; + } + return 0; +} diff --git a/src/lib/fdio/fdio.h b/src/lib/fdio/fdio.h new file mode 100644 index 0000000000..c8f05455b7 --- /dev/null +++ b/src/lib/fdio/fdio.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file fdio.h + * + * \brief Header for fdio.c + **/ + +#ifndef TOR_FDIO_H +#define TOR_FDIO_H + +#include <stddef.h> + +off_t tor_fd_getpos(int fd); +int tor_fd_setpos(int fd, off_t pos); +int tor_fd_seekend(int fd); +int tor_ftruncate(int fd); +int write_all_to_fd_minimal(int fd, const char *buf, size_t count); + +#endif /* !defined(TOR_FDIO_H) */ diff --git a/src/lib/fdio/include.am b/src/lib/fdio/include.am new file mode 100644 index 0000000000..6c18f00a0d --- /dev/null +++ b/src/lib/fdio/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-fdio.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-fdio-testing.a +endif + +src_lib_libtor_fdio_a_SOURCES = \ + src/lib/fdio/fdio.c + +src_lib_libtor_fdio_testing_a_SOURCES = \ + $(src_lib_libtor_fdio_a_SOURCES) +src_lib_libtor_fdio_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_fdio_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/fdio/fdio.h diff --git a/src/lib/fs/.may_include b/src/lib/fs/.may_include new file mode 100644 index 0000000000..6c9ce6ca04 --- /dev/null +++ b/src/lib/fs/.may_include @@ -0,0 +1,13 @@ +orconfig.h +lib/cc/*.h +lib/container/*.h +lib/encoding/*.h +lib/err/*.h +lib/fdio/*.h +lib/fs/*.h +lib/log/*.h +lib/malloc/*.h +lib/memarea/*.h +lib/sandbox/*.h +lib/string/*.h +lib/testsupport/testsupport.h diff --git a/src/lib/fs/conffile.c b/src/lib/fs/conffile.c new file mode 100644 index 0000000000..600c7f6b70 --- /dev/null +++ b/src/lib/fs/conffile.c @@ -0,0 +1,174 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file conffile.h + * + * \brief Read configuration files from disk, with full `%include` support. + **/ + +#include "lib/fs/conffile.h" + +#include "lib/container/smartlist.h" +#include "lib/encoding/confline.h" +#include "lib/fs/dir.h" +#include "lib/fs/files.h" +#include "lib/fs/path.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" + +static smartlist_t *config_get_file_list(const char *path, + smartlist_t *opened_files); +static int config_get_included_config(const char *path, int recursion_level, + int extended, config_line_t **config, + config_line_t **config_last, + smartlist_t *opened_lst); +static int config_process_include(const char *path, int recursion_level, + int extended, config_line_t **list, + config_line_t **list_last, + smartlist_t *opened_lst); + +/** Helper: parse the config string and strdup into key/value + * strings. Set *result to the list, or NULL if parsing the string + * failed. Set *has_include to 1 if <b>result</b> has values from + * %included files. <b>opened_lst</b> will have a list of opened files if + * provided. Return 0 on success, -1 on failure. Warn and ignore any + * misformatted lines. + * + * If <b>extended</b> is set, then treat keys beginning with / and with + as + * indicating "clear" and "append" respectively. */ +int +config_get_lines_include(const char *string, config_line_t **result, + int extended, int *has_include, + smartlist_t *opened_lst) +{ + return config_get_lines_aux(string, result, extended, 1, has_include, + opened_lst, 1, NULL, config_process_include); +} + +/** Adds a list of configuration files present on <b>path</b> to + * <b>file_list</b>. <b>path</b> can be a file or a directory. If it is a file, + * only that file will be added to <b>file_list</b>. If it is a directory, + * all paths for files on that directory root (no recursion) except for files + * whose name starts with a dot will be added to <b>file_list</b>. + * <b>opened_files</b> will have a list of files opened by this function + * if provided. Return 0 on success, -1 on failure. Ignores empty files. + */ +static smartlist_t * +config_get_file_list(const char *path, smartlist_t *opened_files) +{ + smartlist_t *file_list = smartlist_new(); + + if (opened_files) { + smartlist_add_strdup(opened_files, path); + } + + file_status_t file_type = file_status(path); + if (file_type == FN_FILE) { + smartlist_add_strdup(file_list, path); + return file_list; + } else if (file_type == FN_DIR) { + smartlist_t *all_files = tor_listdir(path); + if (!all_files) { + smartlist_free(file_list); + return NULL; + } + smartlist_sort_strings(all_files); + SMARTLIST_FOREACH_BEGIN(all_files, char *, f) { + if (f[0] == '.') { + tor_free(f); + continue; + } + + char *fullname; + tor_asprintf(&fullname, "%s"PATH_SEPARATOR"%s", path, f); + tor_free(f); + + if (opened_files) { + smartlist_add_strdup(opened_files, fullname); + } + + if (file_status(fullname) != FN_FILE) { + tor_free(fullname); + continue; + } + smartlist_add(file_list, fullname); + } SMARTLIST_FOREACH_END(f); + smartlist_free(all_files); + return file_list; + } else if (file_type == FN_EMPTY) { + return file_list; + } else { + smartlist_free(file_list); + return NULL; + } +} + +/** Creates a list of config lines present on included <b>path</b>. + * Set <b>config</b> to the list and <b>config_last</b> to the last element of + * <b>config</b>. <b>opened_lst</b> will have a list of opened files if + * provided. Return 0 on success, -1 on failure. */ +static int +config_get_included_config(const char *path, int recursion_level, int extended, + config_line_t **config, config_line_t **config_last, + smartlist_t *opened_lst) +{ + char *included_conf = read_file_to_str(path, 0, NULL); + if (!included_conf) { + return -1; + } + + if (config_get_lines_aux(included_conf, config, extended, 1, NULL, + opened_lst, recursion_level+1, config_last, + config_process_include) < 0) { + tor_free(included_conf); + return -1; + } + + tor_free(included_conf); + return 0; +} + +/** Process an %include <b>path</b> in a config file. Set <b>list</b> to the + * list of configuration settings obtained and <b>list_last</b> to the last + * element of the same list. <b>opened_lst</b> will have a list of opened + * files if provided. Return 0 on success, -1 on failure. */ +static int +config_process_include(const char *path, int recursion_level, int extended, + config_line_t **list, config_line_t **list_last, + smartlist_t *opened_lst) +{ + config_line_t *ret_list = NULL; + config_line_t **next = &ret_list; + + smartlist_t *config_files = config_get_file_list(path, opened_lst); + if (!config_files) { + return -1; + } + + int rv = -1; + SMARTLIST_FOREACH_BEGIN(config_files, const char *, config_file) { + config_line_t *included_config = NULL; + if (config_get_included_config(config_file, recursion_level, extended, + &included_config, list_last, + opened_lst) < 0) { + goto done; + } + + *next = included_config; + if (*list_last) + next = &(*list_last)->next; + + } SMARTLIST_FOREACH_END(config_file); + *list = ret_list; + rv = 0; + + done: + SMARTLIST_FOREACH(config_files, char *, f, tor_free(f)); + smartlist_free(config_files); + return rv; +} diff --git a/src/lib/fs/conffile.h b/src/lib/fs/conffile.h new file mode 100644 index 0000000000..a926f4ac05 --- /dev/null +++ b/src/lib/fs/conffile.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_CONFFILE_H +#define TOR_CONFFILE_H + +/** + * \file conffile.h + * + * \brief Header for conffile.c + **/ + +struct smartlist_t; +struct config_line_t; + +int config_get_lines_include(const char *string, struct config_line_t **result, + int extended, int *has_include, + struct smartlist_t *opened_lst); + +#endif /* !defined(TOR_CONFLINE_H) */ diff --git a/src/lib/fs/dir.c b/src/lib/fs/dir.c new file mode 100644 index 0000000000..cc339f747e --- /dev/null +++ b/src/lib/fs/dir.c @@ -0,0 +1,367 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file dir.c + * + * \brief Read directories, and create directories with restrictive + * permissions. + **/ + +#include "lib/fs/dir.h" +#include "lib/fs/path.h" +#include "lib/fs/userdb.h" + +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/container/smartlist.h" +#include "lib/sandbox/sandbox.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" +#include "lib/string/compat_string.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef _WIN32 +#include <io.h> +#include <direct.h> +#include <windows.h> +#else /* !(defined(_WIN32)) */ +#include <dirent.h> +#include <pwd.h> +#include <grp.h> +#endif /* defined(_WIN32) */ + +#include <errno.h> +#include <string.h> + +/** Check whether <b>dirname</b> exists and is private. If yes return 0. + * If <b>dirname</b> does not exist: + * - if <b>check</b>&CPD_CREATE, try to create it and return 0 on success. + * - if <b>check</b>&CPD_CHECK, and we think we can create it, return 0. + * - if <b>check</b>&CPD_CHECK is false, and the directory exists, return 0. + * - otherwise, return -1. + * If CPD_GROUP_OK is set, then it's okay if the directory + * is group-readable, but in all cases we create the directory mode 0700. + * If CPD_GROUP_READ is set, existing directory behaves as CPD_GROUP_OK and + * if the directory is created it will use mode 0750 with group read + * permission. Group read privileges also assume execute permission + * as norm for directories. If CPD_CHECK_MODE_ONLY is set, then we don't + * alter the directory permissions if they are too permissive: + * we just return -1. + * When effective_user is not NULL, check permissions against the given user + * and its primary group. + */ +MOCK_IMPL(int, +check_private_dir,(const char *dirname, cpd_check_t check, + const char *effective_user)) +{ + int r; + struct stat st; + + tor_assert(dirname); + +#ifndef _WIN32 + int fd; + const struct passwd *pw = NULL; + uid_t running_uid; + gid_t running_gid; + + /* + * Goal is to harden the implementation by removing any + * potential for race between stat() and chmod(). + * chmod() accepts filename as argument. If an attacker can move + * the file between stat() and chmod(), a potential race exists. + * + * Several suggestions taken from: + * https://developer.apple.com/library/mac/documentation/ + * Security/Conceptual/SecureCodingGuide/Articles/RaceConditions.html + */ + + /* Open directory. + * O_NOFOLLOW to ensure that it does not follow symbolic links */ + fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); + + /* Was there an error? Maybe the directory does not exist? */ + if (fd == -1) { + + if (errno != ENOENT) { + /* Other directory error */ + log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, + strerror(errno)); + return -1; + } + + /* Received ENOENT: Directory does not exist */ + + /* Should we create the directory? */ + if (check & CPD_CREATE) { + log_info(LD_GENERAL, "Creating directory %s", dirname); + if (check & CPD_GROUP_READ) { + r = mkdir(dirname, 0750); + } else { + r = mkdir(dirname, 0700); + } + + /* check for mkdir() error */ + if (r) { + log_warn(LD_FS, "Error creating directory %s: %s", dirname, + strerror(errno)); + return -1; + } + + /* we just created the directory. try to open it again. + * permissions on the directory will be checked again below.*/ + fd = open(sandbox_intern_string(dirname), O_NOFOLLOW); + + if (fd == -1) { + log_warn(LD_FS, "Could not reopen recently created directory %s: %s", + dirname, + strerror(errno)); + return -1; + } else { + close(fd); + } + + } else if (!(check & CPD_CHECK)) { + log_warn(LD_FS, "Directory %s does not exist.", dirname); + return -1; + } + + /* XXXX In the case where check==CPD_CHECK, we should look at the + * parent directory a little harder. */ + return 0; + } + + tor_assert(fd >= 0); + + //f = tor_strdup(dirname); + //clean_name_for_stat(f); + log_debug(LD_FS, "stat()ing %s", dirname); + //r = stat(sandbox_intern_string(f), &st); + r = fstat(fd, &st); + if (r == -1) { + log_warn(LD_FS, "fstat() on directory %s failed.", dirname); + close(fd); + return -1; + } + //tor_free(f); + + /* check that dirname is a directory */ + if (!(st.st_mode & S_IFDIR)) { + log_warn(LD_FS, "%s is not a directory", dirname); + close(fd); + return -1; + } + + if (effective_user) { + /* Look up the user and group information. + * If we have a problem, bail out. */ + pw = tor_getpwnam(effective_user); + if (pw == NULL) { + log_warn(LD_CONFIG, "Error setting configured user: %s not found", + effective_user); + close(fd); + return -1; + } + running_uid = pw->pw_uid; + running_gid = pw->pw_gid; + } else { + running_uid = getuid(); + running_gid = getgid(); + } + if (st.st_uid != running_uid) { + char *process_ownername = NULL, *file_ownername = NULL; + + { + const struct passwd *pw_running = tor_getpwuid(running_uid); + process_ownername = pw_running ? tor_strdup(pw_running->pw_name) : + tor_strdup("<unknown>"); + } + + { + const struct passwd *pw_stat = tor_getpwuid(st.st_uid); + file_ownername = pw_stat ? tor_strdup(pw_stat->pw_name) : + tor_strdup("<unknown>"); + } + + log_warn(LD_FS, "%s is not owned by this user (%s, %d) but by " + "%s (%d). Perhaps you are running Tor as the wrong user?", + dirname, process_ownername, (int)running_uid, + file_ownername, (int)st.st_uid); + + tor_free(process_ownername); + tor_free(file_ownername); + close(fd); + return -1; + } + if ( (check & (CPD_GROUP_OK|CPD_GROUP_READ)) + && (st.st_gid != running_gid) && (st.st_gid != 0)) { + struct group *gr; + char *process_groupname = NULL; + gr = getgrgid(running_gid); + process_groupname = gr ? tor_strdup(gr->gr_name) : tor_strdup("<unknown>"); + gr = getgrgid(st.st_gid); + + log_warn(LD_FS, "%s is not owned by this group (%s, %d) but by group " + "%s (%d). Are you running Tor as the wrong user?", + dirname, process_groupname, (int)running_gid, + gr ? gr->gr_name : "<unknown>", (int)st.st_gid); + + tor_free(process_groupname); + close(fd); + return -1; + } + unsigned unwanted_bits = 0; + if (check & (CPD_GROUP_OK|CPD_GROUP_READ)) { + unwanted_bits = 0027; + } else { + unwanted_bits = 0077; + } + unsigned check_bits_filter = ~0; + if (check & CPD_RELAX_DIRMODE_CHECK) { + check_bits_filter = 0022; + } + if ((st.st_mode & unwanted_bits & check_bits_filter) != 0) { + unsigned new_mode; + if (check & CPD_CHECK_MODE_ONLY) { + log_warn(LD_FS, "Permissions on directory %s are too permissive.", + dirname); + close(fd); + return -1; + } + log_warn(LD_FS, "Fixing permissions on directory %s", dirname); + new_mode = st.st_mode; + new_mode |= 0700; /* Owner should have rwx */ + if (check & CPD_GROUP_READ) { + new_mode |= 0050; /* Group should have rx */ + } + new_mode &= ~unwanted_bits; /* Clear the bits that we didn't want set...*/ + if (fchmod(fd, new_mode)) { + log_warn(LD_FS, "Could not chmod directory %s: %s", dirname, + strerror(errno)); + close(fd); + return -1; + } else { + close(fd); + return 0; + } + } + close(fd); +#else /* !(!defined(_WIN32)) */ + /* Win32 case: we can't open() a directory. */ + (void)effective_user; + + char *f = tor_strdup(dirname); + clean_fname_for_stat(f); + log_debug(LD_FS, "stat()ing %s", f); + r = stat(sandbox_intern_string(f), &st); + tor_free(f); + if (r) { + if (errno != ENOENT) { + log_warn(LD_FS, "Directory %s cannot be read: %s", dirname, + strerror(errno)); + return -1; + } + if (check & CPD_CREATE) { + log_info(LD_GENERAL, "Creating directory %s", dirname); + r = mkdir(dirname); + if (r) { + log_warn(LD_FS, "Error creating directory %s: %s", dirname, + strerror(errno)); + return -1; + } + } else if (!(check & CPD_CHECK)) { + log_warn(LD_FS, "Directory %s does not exist.", dirname); + return -1; + } + return 0; + } + if (!(st.st_mode & S_IFDIR)) { + log_warn(LD_FS, "%s is not a directory", dirname); + return -1; + } + +#endif /* !defined(_WIN32) */ + return 0; +} + +/** Return a new list containing the filenames in the directory <b>dirname</b>. + * Return NULL on error or if <b>dirname</b> is not a directory. + */ +MOCK_IMPL(smartlist_t *, +tor_listdir, (const char *dirname)) +{ + smartlist_t *result; +#ifdef _WIN32 + char *pattern=NULL; + TCHAR tpattern[MAX_PATH] = {0}; + char name[MAX_PATH*2+1] = {0}; + HANDLE handle; + WIN32_FIND_DATA findData; + tor_asprintf(&pattern, "%s\\*", dirname); +#ifdef UNICODE + mbstowcs(tpattern,pattern,MAX_PATH); +#else + strlcpy(tpattern, pattern, MAX_PATH); +#endif + if (INVALID_HANDLE_VALUE == (handle = FindFirstFile(tpattern, &findData))) { + tor_free(pattern); + return NULL; + } + result = smartlist_new(); + while (1) { +#ifdef UNICODE + wcstombs(name,findData.cFileName,MAX_PATH); + name[sizeof(name)-1] = '\0'; +#else + strlcpy(name,findData.cFileName,sizeof(name)); +#endif /* defined(UNICODE) */ + if (strcmp(name, ".") && + strcmp(name, "..")) { + smartlist_add_strdup(result, name); + } + if (!FindNextFile(handle, &findData)) { + DWORD err; + if ((err = GetLastError()) != ERROR_NO_MORE_FILES) { + char *errstr = format_win32_error(err); + log_warn(LD_FS, "Error reading directory '%s': %s", dirname, errstr); + tor_free(errstr); + } + break; + } + } + FindClose(handle); + tor_free(pattern); +#else /* !(defined(_WIN32)) */ + const char *prot_dname = sandbox_intern_string(dirname); + DIR *d; + struct dirent *de; + if (!(d = opendir(prot_dname))) + return NULL; + + result = smartlist_new(); + while ((de = readdir(d))) { + if (!strcmp(de->d_name, ".") || + !strcmp(de->d_name, "..")) + continue; + smartlist_add_strdup(result, de->d_name); + } + closedir(d); +#endif /* defined(_WIN32) */ + return result; +} diff --git a/src/lib/fs/dir.h b/src/lib/fs/dir.h new file mode 100644 index 0000000000..61a04e6d58 --- /dev/null +++ b/src/lib/fs/dir.h @@ -0,0 +1,33 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DIR_H +#define TOR_DIR_H + +/** + * \file dir.h + * + * \brief Header for dir.c + **/ + +#include "lib/cc/compat_compiler.h" +#include "lib/testsupport/testsupport.h" + +/** Possible behaviors for check_private_dir() on encountering a nonexistent + * directory; see that function's documentation for details. */ +typedef unsigned int cpd_check_t; +#define CPD_NONE 0 +#define CPD_CREATE (1u << 0) +#define CPD_CHECK (1u << 1) +#define CPD_GROUP_OK (1u << 2) +#define CPD_GROUP_READ (1u << 3) +#define CPD_CHECK_MODE_ONLY (1u << 4) +#define CPD_RELAX_DIRMODE_CHECK (1u << 5) +MOCK_DECL(int, check_private_dir, (const char *dirname, cpd_check_t check, + const char *effective_user)); + +MOCK_DECL(struct smartlist_t *, tor_listdir, (const char *dirname)); + +#endif diff --git a/src/lib/fs/files.c b/src/lib/fs/files.c new file mode 100644 index 0000000000..4e0a398baa --- /dev/null +++ b/src/lib/fs/files.c @@ -0,0 +1,717 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file files.h + * + * \brief Wrappers for reading and writing data to files on disk. + **/ + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include "lib/fs/files.h" +#include "lib/fs/path.h" +#include "lib/container/smartlist.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/escape.h" +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" +#include "lib/fdio/fdio.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UTIME_H +#include <utime.h> +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> +#include <stdio.h> +#include <string.h> + +/** As open(path, flags, mode), but return an fd with the close-on-exec mode + * set. */ +int +tor_open_cloexec(const char *path, int flags, unsigned mode) +{ + int fd; + const char *p = sandbox_intern_string(path); +#ifdef O_CLOEXEC + fd = open(p, flags|O_CLOEXEC, mode); + if (fd >= 0) + return fd; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with O_CLOEXEC support, we + * are running on one without. */ + if (errno != EINVAL) + return -1; +#endif /* defined(O_CLOEXEC) */ + + log_debug(LD_FS, "Opening %s with flags %x", p, flags); + fd = open(p, flags, mode); +#ifdef FD_CLOEXEC + if (fd >= 0) { + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + close(fd); + return -1; + } + } +#endif /* defined(FD_CLOEXEC) */ + return fd; +} + +/** As fopen(path,mode), but ensures that the O_CLOEXEC bit is set on the + * underlying file handle. */ +FILE * +tor_fopen_cloexec(const char *path, const char *mode) +{ + FILE *result = fopen(path, mode); +#ifdef FD_CLOEXEC + if (result != NULL) { + if (fcntl(fileno(result), F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + fclose(result); + return NULL; + } + } +#endif /* defined(FD_CLOEXEC) */ + return result; +} + +/** As rename(), but work correctly with the sandbox. */ +int +tor_rename(const char *path_old, const char *path_new) +{ + log_debug(LD_FS, "Renaming %s to %s", path_old, path_new); + return rename(sandbox_intern_string(path_old), + sandbox_intern_string(path_new)); +} + +/** + * Rename the file <b>from</b> to the file <b>to</b>. On Unix, this is + * the same as rename(2). On windows, this removes <b>to</b> first if + * it already exists. + * Returns 0 on success. Returns -1 and sets errno on failure. + */ +int +replace_file(const char *from, const char *to) +{ +#ifndef _WIN32 + return tor_rename(from, to); +#else + switch (file_status(to)) + { + case FN_NOENT: + break; + case FN_FILE: + case FN_EMPTY: + if (unlink(to)) return -1; + break; + case FN_ERROR: + return -1; + case FN_DIR: + errno = EISDIR; + return -1; + } + return tor_rename(from,to); +#endif /* !defined(_WIN32) */ +} + +/** Change <b>fname</b>'s modification time to now. */ +int +touch_file(const char *fname) +{ + if (utime(fname, NULL)!=0) + return -1; + return 0; +} + +/** Wrapper for unlink() to make it mockable for the test suite; returns 0 + * if unlinking the file succeeded, -1 and sets errno if unlinking fails. + */ + +MOCK_IMPL(int, +tor_unlink,(const char *pathname)) +{ + return unlink(pathname); +} + +/** Write <b>count</b> bytes from <b>buf</b> to <b>fd</b>. Return the number + * of bytes written, or -1 on error. Only use if fd is a blocking fd. */ +ssize_t +write_all_to_fd(int fd, const char *buf, size_t count) +{ + size_t written = 0; + ssize_t result; + raw_assert(count < SSIZE_MAX); + + while (written != count) { + result = write(fd, buf+written, count-written); + if (result<0) + return -1; + written += result; + } + return (ssize_t)count; +} + +/** Read from <b>fd</b> to <b>buf</b>, until we get <b>count</b> bytes or + * reach the end of the file. Return the number of bytes read, or -1 on + * error. Only use if fd is a blocking fd. */ +ssize_t +read_all_from_fd(int fd, char *buf, size_t count) +{ + size_t numread = 0; + ssize_t result; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + while (numread < count) { + result = read(fd, buf+numread, count-numread); + if (result<0) + return -1; + else if (result == 0) + break; + numread += result; + } + return (ssize_t)numread; +} + +/** Return: + * FN_ERROR if filename can't be read, is NULL, or is zero-length, + * FN_NOENT if it doesn't exist, + * FN_FILE if it is a non-empty regular file, or a FIFO on unix-like systems, + * FN_EMPTY for zero-byte regular files, + * FN_DIR if it's a directory, and + * FN_ERROR for any other file type. + * On FN_ERROR and FN_NOENT, sets errno. (errno is not set when FN_ERROR + * is returned due to an unhandled file type.) */ +file_status_t +file_status(const char *fname) +{ + struct stat st; + char *f; + int r; + if (!fname || strlen(fname) == 0) { + return FN_ERROR; + } + f = tor_strdup(fname); + clean_fname_for_stat(f); + log_debug(LD_FS, "stat()ing %s", f); + r = stat(sandbox_intern_string(f), &st); + tor_free(f); + if (r) { + if (errno == ENOENT) { + return FN_NOENT; + } + return FN_ERROR; + } + if (st.st_mode & S_IFDIR) { + return FN_DIR; + } else if (st.st_mode & S_IFREG) { + if (st.st_size > 0) { + return FN_FILE; + } else if (st.st_size == 0) { + return FN_EMPTY; + } else { + return FN_ERROR; + } +#ifndef _WIN32 + } else if (st.st_mode & S_IFIFO) { + return FN_FILE; +#endif + } else { + return FN_ERROR; + } +} + +/** Create a file named <b>fname</b> with the contents <b>str</b>. Overwrite + * the previous <b>fname</b> if possible. Return 0 on success, -1 on failure. + * + * This function replaces the old file atomically, if possible. This + * function, and all other functions in util.c that create files, create them + * with mode 0600. + */ +MOCK_IMPL(int, +write_str_to_file,(const char *fname, const char *str, int bin)) +{ +#ifdef _WIN32 + if (!bin && strchr(str, '\r')) { + log_warn(LD_BUG, + "We're writing a text string that already contains a CR to %s", + escaped(fname)); + } +#endif /* defined(_WIN32) */ + return write_bytes_to_file(fname, str, strlen(str), bin); +} + +/** Represents a file that we're writing to, with support for atomic commit: + * we can write into a temporary file, and either remove the file on + * failure, or replace the original file on success. */ +struct open_file_t { + char *tempname; /**< Name of the temporary file. */ + char *filename; /**< Name of the original file. */ + unsigned rename_on_close:1; /**< Are we using the temporary file or not? */ + unsigned binary:1; /**< Did we open in binary mode? */ + int fd; /**< fd for the open file. */ + FILE *stdio_file; /**< stdio wrapper for <b>fd</b>. */ +}; + +/** Try to start writing to the file in <b>fname</b>, passing the flags + * <b>open_flags</b> to the open() syscall, creating the file (if needed) with + * access value <b>mode</b>. If the O_APPEND flag is set, we append to the + * original file. Otherwise, we open a new temporary file in the same + * directory, and either replace the original or remove the temporary file + * when we're done. + * + * Return the fd for the newly opened file, and store working data in + * *<b>data_out</b>. The caller should not close the fd manually: + * instead, call finish_writing_to_file() or abort_writing_to_file(). + * Returns -1 on failure. + * + * NOTE: When not appending, the flags O_CREAT and O_TRUNC are treated + * as true and the flag O_EXCL is treated as false. + * + * NOTE: Ordinarily, O_APPEND means "seek to the end of the file before each + * write()". We don't do that. + */ +int +start_writing_to_file(const char *fname, int open_flags, int mode, + open_file_t **data_out) +{ + open_file_t *new_file = tor_malloc_zero(sizeof(open_file_t)); + const char *open_name; + int append = 0; + + tor_assert(fname); + tor_assert(data_out); +#if (O_BINARY != 0 && O_TEXT != 0) + tor_assert((open_flags & (O_BINARY|O_TEXT)) != 0); +#endif + new_file->fd = -1; + new_file->filename = tor_strdup(fname); + if (open_flags & O_APPEND) { + open_name = fname; + new_file->rename_on_close = 0; + append = 1; + open_flags &= ~O_APPEND; + } else { + tor_asprintf(&new_file->tempname, "%s.tmp", fname); + open_name = new_file->tempname; + /* We always replace an existing temporary file if there is one. */ + open_flags |= O_CREAT|O_TRUNC; + open_flags &= ~O_EXCL; + new_file->rename_on_close = 1; + } +#if O_BINARY != 0 + if (open_flags & O_BINARY) + new_file->binary = 1; +#endif + + new_file->fd = tor_open_cloexec(open_name, open_flags, mode); + if (new_file->fd < 0) { + log_warn(LD_FS, "Couldn't open \"%s\" (%s) for writing: %s", + open_name, fname, strerror(errno)); + goto err; + } + if (append) { + if (tor_fd_seekend(new_file->fd) < 0) { + log_warn(LD_FS, "Couldn't seek to end of file \"%s\": %s", open_name, + strerror(errno)); + goto err; + } + } + + *data_out = new_file; + + return new_file->fd; + + err: + if (new_file->fd >= 0) + close(new_file->fd); + *data_out = NULL; + tor_free(new_file->filename); + tor_free(new_file->tempname); + tor_free(new_file); + return -1; +} + +/** Given <b>file_data</b> from start_writing_to_file(), return a stdio FILE* + * that can be used to write to the same file. The caller should not mix + * stdio calls with non-stdio calls. */ +FILE * +fdopen_file(open_file_t *file_data) +{ + tor_assert(file_data); + if (file_data->stdio_file) + return file_data->stdio_file; + tor_assert(file_data->fd >= 0); + if (!(file_data->stdio_file = fdopen(file_data->fd, + file_data->binary?"ab":"a"))) { + log_warn(LD_FS, "Couldn't fdopen \"%s\" [%d]: %s", file_data->filename, + file_data->fd, strerror(errno)); + } + return file_data->stdio_file; +} + +/** Combines start_writing_to_file with fdopen_file(): arguments are as + * for start_writing_to_file, but */ +FILE * +start_writing_to_stdio_file(const char *fname, int open_flags, int mode, + open_file_t **data_out) +{ + FILE *res; + if (start_writing_to_file(fname, open_flags, mode, data_out)<0) + return NULL; + if (!(res = fdopen_file(*data_out))) { + abort_writing_to_file(*data_out); + *data_out = NULL; + } + return res; +} + +/** Helper function: close and free the underlying file and memory in + * <b>file_data</b>. If we were writing into a temporary file, then delete + * that file (if abort_write is true) or replaces the target file with + * the temporary file (if abort_write is false). */ +static int +finish_writing_to_file_impl(open_file_t *file_data, int abort_write) +{ + int r = 0; + + tor_assert(file_data && file_data->filename); + if (file_data->stdio_file) { + if (fclose(file_data->stdio_file)) { + log_warn(LD_FS, "Error closing \"%s\": %s", file_data->filename, + strerror(errno)); + abort_write = r = -1; + } + } else if (file_data->fd >= 0 && close(file_data->fd) < 0) { + log_warn(LD_FS, "Error flushing \"%s\": %s", file_data->filename, + strerror(errno)); + abort_write = r = -1; + } + + if (file_data->rename_on_close) { + tor_assert(file_data->tempname && file_data->filename); + if (!abort_write) { + tor_assert(strcmp(file_data->filename, file_data->tempname)); + if (replace_file(file_data->tempname, file_data->filename)) { + log_warn(LD_FS, "Error replacing \"%s\": %s", file_data->filename, + strerror(errno)); + abort_write = r = -1; + } + } + if (abort_write) { + int res = unlink(file_data->tempname); + if (res != 0) { + /* We couldn't unlink and we'll leave a mess behind */ + log_warn(LD_FS, "Failed to unlink %s: %s", + file_data->tempname, strerror(errno)); + r = -1; + } + } + } + + tor_free(file_data->filename); + tor_free(file_data->tempname); + tor_free(file_data); + + return r; +} + +/** Finish writing to <b>file_data</b>: close the file handle, free memory as + * needed, and if using a temporary file, replace the original file with + * the temporary file. */ +int +finish_writing_to_file(open_file_t *file_data) +{ + return finish_writing_to_file_impl(file_data, 0); +} + +/** Finish writing to <b>file_data</b>: close the file handle, free memory as + * needed, and if using a temporary file, delete it. */ +int +abort_writing_to_file(open_file_t *file_data) +{ + return finish_writing_to_file_impl(file_data, 1); +} + +/** Helper: given a set of flags as passed to open(2), open the file + * <b>fname</b> and write all the sized_chunk_t structs in <b>chunks</b> to + * the file. Do so as atomically as possible e.g. by opening temp files and + * renaming. */ +static int +write_chunks_to_file_impl(const char *fname, const smartlist_t *chunks, + int open_flags) +{ + open_file_t *file = NULL; + int fd; + ssize_t result; + fd = start_writing_to_file(fname, open_flags, 0600, &file); + if (fd<0) + return -1; + SMARTLIST_FOREACH(chunks, sized_chunk_t *, chunk, + { + result = write_all_to_fd(fd, chunk->bytes, chunk->len); + if (result < 0) { + log_warn(LD_FS, "Error writing to \"%s\": %s", fname, + strerror(errno)); + goto err; + } + tor_assert((size_t)result == chunk->len); + }); + + return finish_writing_to_file(file); + err: + abort_writing_to_file(file); + return -1; +} + +/** Given a smartlist of sized_chunk_t, write them to a file + * <b>fname</b>, overwriting or creating the file as necessary. + * If <b>no_tempfile</b> is 0 then the file will be written + * atomically. */ +int +write_chunks_to_file(const char *fname, const smartlist_t *chunks, int bin, + int no_tempfile) +{ + int flags = OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT); + + if (no_tempfile) { + /* O_APPEND stops write_chunks_to_file from using tempfiles */ + flags |= O_APPEND; + } + return write_chunks_to_file_impl(fname, chunks, flags); +} + +/** Write <b>len</b> bytes, starting at <b>str</b>, to <b>fname</b> + using the open() flags passed in <b>flags</b>. */ +static int +write_bytes_to_file_impl(const char *fname, const char *str, size_t len, + int flags) +{ + int r; + sized_chunk_t c = { str, len }; + smartlist_t *chunks = smartlist_new(); + smartlist_add(chunks, &c); + r = write_chunks_to_file_impl(fname, chunks, flags); + smartlist_free(chunks); + return r; +} + +/** As write_str_to_file, but does not assume a NUL-terminated + * string. Instead, we write <b>len</b> bytes, starting at <b>str</b>. */ +MOCK_IMPL(int, +write_bytes_to_file,(const char *fname, const char *str, size_t len, + int bin)) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_REPLACE|(bin?O_BINARY:O_TEXT)); +} + +/** As write_bytes_to_file, but if the file already exists, append the bytes + * to the end of the file instead of overwriting it. */ +int +append_bytes_to_file(const char *fname, const char *str, size_t len, + int bin) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_APPEND|(bin?O_BINARY:O_TEXT)); +} + +/** Like write_str_to_file(), but also return -1 if there was a file + already residing in <b>fname</b>. */ +int +write_bytes_to_new_file(const char *fname, const char *str, size_t len, + int bin) +{ + return write_bytes_to_file_impl(fname, str, len, + OPEN_FLAGS_DONT_REPLACE| + (bin?O_BINARY:O_TEXT)); +} + +/** + * Read the contents of the open file <b>fd</b> presuming it is a FIFO + * (or similar) file descriptor for which the size of the file isn't + * known ahead of time. Return NULL on failure, and a NUL-terminated + * string on success. On success, set <b>sz_out</b> to the number of + * bytes read. + */ +char * +read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, size_t *sz_out) +{ + ssize_t r; + size_t pos = 0; + char *string = NULL; + size_t string_max = 0; + + if (max_bytes_to_read+1 >= SIZE_T_CEILING) { + errno = EINVAL; + return NULL; + } + + do { + /* XXXX This "add 1K" approach is a little goofy; if we care about + * performance here, we should be doubling. But in practice we shouldn't + * be using this function on big files anyway. */ + string_max = pos + 1024; + if (string_max > max_bytes_to_read) + string_max = max_bytes_to_read + 1; + string = tor_realloc(string, string_max); + r = read(fd, string + pos, string_max - pos - 1); + if (r < 0) { + int save_errno = errno; + tor_free(string); + errno = save_errno; + return NULL; + } + + pos += r; + } while (r > 0 && pos < max_bytes_to_read); + + tor_assert(pos < string_max); + *sz_out = pos; + string[pos] = '\0'; + return string; +} + +/** Read the contents of <b>filename</b> into a newly allocated + * string; return the string on success or NULL on failure. + * + * If <b>stat_out</b> is provided, store the result of stat()ing the + * file into <b>stat_out</b>. + * + * If <b>flags</b> & RFTS_BIN, open the file in binary mode. + * If <b>flags</b> & RFTS_IGNORE_MISSING, don't warn if the file + * doesn't exist. + */ +/* + * This function <em>may</em> return an erroneous result if the file + * is modified while it is running, but must not crash or overflow. + * Right now, the error case occurs when the file length grows between + * the call to stat and the call to read_all: the resulting string will + * be truncated. + */ +MOCK_IMPL(char *, +read_file_to_str, (const char *filename, int flags, struct stat *stat_out)) +{ + int fd; /* router file */ + struct stat statbuf; + char *string; + ssize_t r; + int bin = flags & RFTS_BIN; + + tor_assert(filename); + + fd = tor_open_cloexec(filename,O_RDONLY|(bin?O_BINARY:O_TEXT),0); + if (fd<0) { + int severity = LOG_WARN; + int save_errno = errno; + if (errno == ENOENT && (flags & RFTS_IGNORE_MISSING)) + severity = LOG_INFO; + log_fn(severity, LD_FS,"Could not open \"%s\": %s",filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + if (fstat(fd, &statbuf)<0) { + int save_errno = errno; + close(fd); + log_warn(LD_FS,"Could not fstat \"%s\".",filename); + errno = save_errno; + return NULL; + } + +#ifndef _WIN32 +/** When we detect that we're reading from a FIFO, don't read more than + * this many bytes. It's insane overkill for most uses. */ +#define FIFO_READ_MAX (1024*1024) + if (S_ISFIFO(statbuf.st_mode)) { + size_t sz = 0; + string = read_file_to_str_until_eof(fd, FIFO_READ_MAX, &sz); + int save_errno = errno; + if (string && stat_out) { + statbuf.st_size = sz; + memcpy(stat_out, &statbuf, sizeof(struct stat)); + } + close(fd); + if (!string) + errno = save_errno; + return string; + } +#endif /* !defined(_WIN32) */ + + if ((uint64_t)(statbuf.st_size)+1 >= SIZE_T_CEILING) { + close(fd); + errno = EINVAL; + return NULL; + } + + string = tor_malloc((size_t)(statbuf.st_size+1)); + + r = read_all_from_fd(fd,string,(size_t)statbuf.st_size); + if (r<0) { + int save_errno = errno; + log_warn(LD_FS,"Error reading from file \"%s\": %s", filename, + strerror(errno)); + tor_free(string); + close(fd); + errno = save_errno; + return NULL; + } + string[r] = '\0'; /* NUL-terminate the result. */ + +#if defined(_WIN32) || defined(__CYGWIN__) + if (!bin && strchr(string, '\r')) { + log_debug(LD_FS, "We didn't convert CRLF to LF as well as we hoped " + "when reading %s. Coping.", + filename); + tor_strstrip(string, "\r"); + r = strlen(string); + } + if (!bin) { + statbuf.st_size = (size_t) r; + } else +#endif /* defined(_WIN32) || defined(__CYGWIN__) */ + if (r != statbuf.st_size) { + /* Unless we're using text mode on win32, we'd better have an exact + * match for size. */ + int save_errno = errno; + log_warn(LD_FS,"Could read only %d of %ld bytes of file \"%s\".", + (int)r, (long)statbuf.st_size,filename); + tor_free(string); + close(fd); + errno = save_errno; + return NULL; + } + close(fd); + if (stat_out) { + memcpy(stat_out, &statbuf, sizeof(struct stat)); + } + + return string; +} diff --git a/src/lib/fs/files.h b/src/lib/fs/files.h new file mode 100644 index 0000000000..5a12eb8215 --- /dev/null +++ b/src/lib/fs/files.h @@ -0,0 +1,106 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file files.h + * + * \brief Header for files.c + **/ + +#ifndef TOR_FS_H +#define TOR_FS_H + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" + +#include <stddef.h> +#include <stdio.h> + +#ifdef _WIN32 +/* We need these for struct stat to work */ +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#endif + +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#ifndef O_TEXT +#define O_TEXT 0 +#endif +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 0 +#endif + +struct stat; + +int tor_open_cloexec(const char *path, int flags, unsigned mode); +FILE *tor_fopen_cloexec(const char *path, const char *mode); +int tor_rename(const char *path_old, const char *path_new); + +int replace_file(const char *from, const char *to); +int touch_file(const char *fname); + +MOCK_DECL(int,tor_unlink,(const char *pathname)); + +/** Return values from file_status(); see that function's documentation + * for details. */ +typedef enum { FN_ERROR, FN_NOENT, FN_FILE, FN_DIR, FN_EMPTY } file_status_t; + +file_status_t file_status(const char *filename); + +int64_t tor_get_avail_disk_space(const char *path); + +ssize_t write_all_to_fd(int fd, const char *buf, size_t count); +ssize_t read_all_from_fd(int fd, char *buf, size_t count); + +#define OPEN_FLAGS_REPLACE (O_WRONLY|O_CREAT|O_TRUNC) +#define OPEN_FLAGS_APPEND (O_WRONLY|O_CREAT|O_APPEND) +#define OPEN_FLAGS_DONT_REPLACE (O_CREAT|O_EXCL|O_APPEND|O_WRONLY) +typedef struct open_file_t open_file_t; +int start_writing_to_file(const char *fname, int open_flags, int mode, + open_file_t **data_out); +FILE *start_writing_to_stdio_file(const char *fname, int open_flags, int mode, + open_file_t **data_out); +FILE *fdopen_file(open_file_t *file_data); +int finish_writing_to_file(open_file_t *file_data); +int abort_writing_to_file(open_file_t *file_data); +MOCK_DECL(int, write_str_to_file,(const char *fname, const char *str, + int bin)); +MOCK_DECL(int, write_bytes_to_file,(const char *fname, const char *str, + size_t len,int bin)); + +/** An ad-hoc type to hold a string of characters and a count; used by + * write_chunks_to_file. */ +typedef struct sized_chunk_t { + const char *bytes; + size_t len; +} sized_chunk_t; +struct smartlist_t; +int write_chunks_to_file(const char *fname, const struct smartlist_t *chunks, + int bin, int no_tempfile); +int append_bytes_to_file(const char *fname, const char *str, size_t len, + int bin); +int write_bytes_to_new_file(const char *fname, const char *str, size_t len, + int bin); + +/** Flag for read_file_to_str: open the file in binary mode. */ +#define RFTS_BIN 1 +/** Flag for read_file_to_str: it's okay if the file doesn't exist. */ +#define RFTS_IGNORE_MISSING 2 + +MOCK_DECL_ATTR(char *, read_file_to_str,(const char *filename, int flags, + struct stat *stat_out), + ATTR_MALLOC); +char *read_file_to_str_until_eof(int fd, size_t max_bytes_to_read, + size_t *sz_out) + ATTR_MALLOC; + +#endif diff --git a/src/lib/fs/freespace.c b/src/lib/fs/freespace.c new file mode 100644 index 0000000000..2dbba3c5f8 --- /dev/null +++ b/src/lib/fs/freespace.c @@ -0,0 +1,62 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file freespace.c + * + * \brief Find the available disk space on the current volume. + **/ + +#include "lib/fs/files.h" +#include "lib/cc/torint.h" + +#ifdef HAVE_SYS_STATVFS_H +#include <sys/statvfs.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <string.h> + +/** Return the amount of free disk space we have permission to use, in + * bytes. Return -1 if the amount of free space can't be determined. */ +int64_t +tor_get_avail_disk_space(const char *path) +{ +#ifdef HAVE_STATVFS + struct statvfs st; + int r; + memset(&st, 0, sizeof(st)); + + r = statvfs(path, &st); + if (r < 0) + return -1; + + int64_t result = st.f_bavail; + if (st.f_frsize) { + result *= st.f_frsize; + } else if (st.f_bsize) { + result *= st.f_bsize; + } else { + return -1; + } + + return result; +#elif defined(_WIN32) + ULARGE_INTEGER freeBytesAvail; + BOOL ok; + + ok = GetDiskFreeSpaceEx(path, &freeBytesAvail, NULL, NULL); + if (!ok) { + return -1; + } + return (int64_t)freeBytesAvail.QuadPart; +#else + (void)path; + errno = ENOSYS; + return -1; +#endif /* defined(HAVE_STATVFS) || ... */ +} diff --git a/src/lib/fs/include.am b/src/lib/fs/include.am new file mode 100644 index 0000000000..f33e4d6430 --- /dev/null +++ b/src/lib/fs/include.am @@ -0,0 +1,37 @@ + +noinst_LIBRARIES += src/lib/libtor-fs.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-fs-testing.a +endif + +src_lib_libtor_fs_a_SOURCES = \ + src/lib/fs/conffile.c \ + src/lib/fs/dir.c \ + src/lib/fs/files.c \ + src/lib/fs/freespace.c \ + src/lib/fs/lockfile.c \ + src/lib/fs/mmap.c \ + src/lib/fs/path.c \ + src/lib/fs/storagedir.c \ + src/lib/fs/userdb.c + +if WIN32 +src_lib_libtor_fs_a_SOURCES += src/lib/fs/winlib.c +endif + +src_lib_libtor_fs_testing_a_SOURCES = \ + $(src_lib_libtor_fs_a_SOURCES) +src_lib_libtor_fs_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_fs_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/fs/conffile.h \ + src/lib/fs/dir.h \ + src/lib/fs/files.h \ + src/lib/fs/lockfile.h \ + src/lib/fs/mmap.h \ + src/lib/fs/path.h \ + src/lib/fs/storagedir.h \ + src/lib/fs/userdb.h \ + src/lib/fs/winlib.h diff --git a/src/lib/fs/lockfile.c b/src/lib/fs/lockfile.c new file mode 100644 index 0000000000..972fd5658d --- /dev/null +++ b/src/lib/fs/lockfile.c @@ -0,0 +1,145 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file lockfile.c + * + * \brief Implements lock files to prevent two Tor processes from using the + * same data directory at the same time. + **/ + +#include "orconfig.h" +#include "lib/fs/files.h" +#include "lib/fs/lockfile.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#include <sys/locking.h> +#endif + +#include <errno.h> +#include <string.h> + +/** Represents a lockfile on which we hold the lock. */ +struct tor_lockfile_t { + /** Name of the file */ + char *filename; + /** File descriptor used to hold the file open */ + int fd; +}; + +/** Try to get a lock on the lockfile <b>filename</b>, creating it as + * necessary. If someone else has the lock and <b>blocking</b> is true, + * wait until the lock is available. Otherwise return immediately whether + * we succeeded or not. + * + * Set *<b>locked_out</b> to true if somebody else had the lock, and to false + * otherwise. + * + * Return a <b>tor_lockfile_t</b> on success, NULL on failure. + * + * (Implementation note: because we need to fall back to fcntl on some + * platforms, these locks are per-process, not per-thread. If you want + * to do in-process locking, use tor_mutex_t like a normal person. + * On Windows, when <b>blocking</b> is true, the maximum time that + * is actually waited is 10 seconds, after which NULL is returned + * and <b>locked_out</b> is set to 1.) + */ +tor_lockfile_t * +tor_lockfile_lock(const char *filename, int blocking, int *locked_out) +{ + tor_lockfile_t *result; + int fd; + *locked_out = 0; + + log_info(LD_FS, "Locking \"%s\"", filename); + fd = tor_open_cloexec(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (fd < 0) { + log_warn(LD_FS,"Couldn't open \"%s\" for locking: %s", filename, + strerror(errno)); + return NULL; + } + +#ifdef _WIN32 + _lseek(fd, 0, SEEK_SET); + if (_locking(fd, blocking ? _LK_LOCK : _LK_NBLCK, 1) < 0) { + if (errno != EACCES && errno != EDEADLOCK) + log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } +#elif defined(HAVE_FLOCK) + if (flock(fd, LOCK_EX|(blocking ? 0 : LOCK_NB)) < 0) { + if (errno != EWOULDBLOCK) + log_warn(LD_FS,"Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } +#else + { + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + if (fcntl(fd, blocking ? F_SETLKW : F_SETLK, &lock) < 0) { + if (errno != EACCES && errno != EAGAIN) + log_warn(LD_FS, "Couldn't lock \"%s\": %s", filename, strerror(errno)); + else + *locked_out = 1; + close(fd); + return NULL; + } + } +#endif /* defined(_WIN32) || ... */ + + result = tor_malloc(sizeof(tor_lockfile_t)); + result->filename = tor_strdup(filename); + result->fd = fd; + return result; +} + +/** Release the lock held as <b>lockfile</b>. */ +void +tor_lockfile_unlock(tor_lockfile_t *lockfile) +{ + tor_assert(lockfile); + + log_info(LD_FS, "Unlocking \"%s\"", lockfile->filename); +#ifdef _WIN32 + _lseek(lockfile->fd, 0, SEEK_SET); + if (_locking(lockfile->fd, _LK_UNLCK, 1) < 0) { + log_warn(LD_FS,"Error unlocking \"%s\": %s", lockfile->filename, + strerror(errno)); + } +#elif defined(HAVE_FLOCK) + if (flock(lockfile->fd, LOCK_UN) < 0) { + log_warn(LD_FS, "Error unlocking \"%s\": %s", lockfile->filename, + strerror(errno)); + } +#else + /* Closing the lockfile is sufficient. */ +#endif /* defined(_WIN32) || ... */ + + close(lockfile->fd); + lockfile->fd = -1; + tor_free(lockfile->filename); + tor_free(lockfile); +} diff --git a/src/lib/fs/lockfile.h b/src/lib/fs/lockfile.h new file mode 100644 index 0000000000..e26349811c --- /dev/null +++ b/src/lib/fs/lockfile.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file lockfile.h + * + * \brief Header for lockfile.c + **/ + +#ifndef TOR_LOCKFILE_H +#define TOR_LOCKFILE_H + +typedef struct tor_lockfile_t tor_lockfile_t; +tor_lockfile_t *tor_lockfile_lock(const char *filename, int blocking, + int *locked_out); +void tor_lockfile_unlock(tor_lockfile_t *lockfile); + +#endif diff --git a/src/lib/fs/mmap.c b/src/lib/fs/mmap.c new file mode 100644 index 0000000000..2d758c1b5f --- /dev/null +++ b/src/lib/fs/mmap.c @@ -0,0 +1,240 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file mmap.c + * + * \brief Cross-platform support for mapping files into our address space. + **/ + +#include "lib/fs/mmap.h" +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/string/compat_string.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_MMAP +#include <sys/mman.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <errno.h> +#include <string.h> + +#if defined(HAVE_MMAP) || defined(RUNNING_DOXYGEN) +/** Try to create a memory mapping for <b>filename</b> and return it. On + * failure, return NULL. Sets errno properly, using ERANGE to mean + * "empty file". Must only be called on trusted Tor-owned files, as changing + * the underlying file's size causes unspecified behavior. */ +tor_mmap_t * +tor_mmap_file(const char *filename) +{ + int fd; /* router file */ + char *string; + int result; + tor_mmap_t *res; + size_t size, filesize; + struct stat st; + + tor_assert(filename); + + fd = tor_open_cloexec(filename, O_RDONLY, 0); + if (fd<0) { + int save_errno = errno; + int severity = (errno == ENOENT) ? LOG_INFO : LOG_WARN; + log_fn(severity, LD_FS,"Could not open \"%s\" for mmap(): %s",filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + /* Get the size of the file */ + result = fstat(fd, &st); + if (result != 0) { + int save_errno = errno; + log_warn(LD_FS, + "Couldn't fstat opened descriptor for \"%s\" during mmap: %s", + filename, strerror(errno)); + close(fd); + errno = save_errno; + return NULL; + } + size = filesize = (size_t)(st.st_size); + + if (st.st_size > SSIZE_T_CEILING || (off_t)size < st.st_size) { + log_warn(LD_FS, "File \"%s\" is too large. Ignoring.",filename); + errno = EFBIG; + close(fd); + return NULL; + } + if (!size) { + /* Zero-length file. If we call mmap on it, it will succeed but + * return NULL, and bad things will happen. So just fail. */ + log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); + errno = ERANGE; + close(fd); + return NULL; + } + + string = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (string == MAP_FAILED) { + int save_errno = errno; + log_warn(LD_FS,"Could not mmap file \"%s\": %s", filename, + strerror(errno)); + errno = save_errno; + return NULL; + } + + res = tor_malloc_zero(sizeof(tor_mmap_t)); + res->data = string; + res->size = filesize; + res->mapping_size = size; + + return res; +} +/** Release storage held for a memory mapping; returns 0 on success, + * or -1 on failure (and logs a warning). */ +int +tor_munmap_file(tor_mmap_t *handle) +{ + int res; + + if (handle == NULL) + return 0; + + res = munmap((char*)handle->data, handle->mapping_size); + if (res == 0) { + /* munmap() succeeded */ + tor_free(handle); + } else { + log_warn(LD_FS, "Failed to munmap() in tor_munmap_file(): %s", + strerror(errno)); + res = -1; + } + + return res; +} +#elif defined(_WIN32) +tor_mmap_t * +tor_mmap_file(const char *filename) +{ + TCHAR tfilename[MAX_PATH]= {0}; + tor_mmap_t *res = tor_malloc_zero(sizeof(tor_mmap_t)); + int empty = 0; + HANDLE file_handle = INVALID_HANDLE_VALUE; + DWORD size_low, size_high; + uint64_t real_size; + res->mmap_handle = NULL; +#ifdef UNICODE + mbstowcs(tfilename,filename,MAX_PATH); +#else + strlcpy(tfilename,filename,MAX_PATH); +#endif + file_handle = CreateFile(tfilename, + GENERIC_READ, FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + 0); + + if (file_handle == INVALID_HANDLE_VALUE) + goto win_err; + + size_low = GetFileSize(file_handle, &size_high); + + if (size_low == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) { + log_warn(LD_FS,"Error getting size of \"%s\".",filename); + goto win_err; + } + if (size_low == 0 && size_high == 0) { + log_info(LD_FS,"File \"%s\" is empty. Ignoring.",filename); + empty = 1; + goto err; + } + real_size = (((uint64_t)size_high)<<32) | size_low; + if (real_size > SIZE_MAX) { + log_warn(LD_FS,"File \"%s\" is too big to map; not trying.",filename); + goto err; + } + res->size = real_size; + + res->mmap_handle = CreateFileMapping(file_handle, + NULL, + PAGE_READONLY, + size_high, + size_low, + NULL); + if (res->mmap_handle == NULL) + goto win_err; + res->data = (char*) MapViewOfFile(res->mmap_handle, + FILE_MAP_READ, + 0, 0, 0); + if (!res->data) + goto win_err; + + CloseHandle(file_handle); + return res; + win_err: { + DWORD e = GetLastError(); + int severity = (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) ? + LOG_INFO : LOG_WARN; + char *msg = format_win32_error(e); + log_fn(severity, LD_FS, "Couldn't mmap file \"%s\": %s", filename, msg); + tor_free(msg); + if (e == ERROR_FILE_NOT_FOUND || e == ERROR_PATH_NOT_FOUND) + errno = ENOENT; + else + errno = EINVAL; + } + err: + if (empty) + errno = ERANGE; + if (file_handle != INVALID_HANDLE_VALUE) + CloseHandle(file_handle); + tor_munmap_file(res); + return NULL; +} + +/* Unmap the file, and return 0 for success or -1 for failure */ +int +tor_munmap_file(tor_mmap_t *handle) +{ + if (handle == NULL) + return 0; + + if (handle->data) { + /* This is an ugly cast, but without it, "data" in struct tor_mmap_t would + have to be redefined as non-const. */ + BOOL ok = UnmapViewOfFile( (LPVOID) handle->data); + if (!ok) { + log_warn(LD_FS, "Failed to UnmapViewOfFile() in tor_munmap_file(): %d", + (int)GetLastError()); + } + } + + if (handle->mmap_handle != NULL) + CloseHandle(handle->mmap_handle); + tor_free(handle); + + return 0; +} +#else +#error "cannot implement tor_mmap_file" +#endif /* defined(HAVE_MMAP) || ... || ... */ diff --git a/src/lib/fs/mmap.h b/src/lib/fs/mmap.h new file mode 100644 index 0000000000..8d6ca9a0e2 --- /dev/null +++ b/src/lib/fs/mmap.h @@ -0,0 +1,41 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file mmap.h + * + * \brief Header for mmap.c + **/ + +#ifndef TOR_MMAP_H +#define TOR_MMAP_H + +#include "lib/cc/compat_compiler.h" +#include <stddef.h> + +#ifdef _WIN32 +#include <windef.h> +#endif + +/** Represents an mmaped file. Allocated via tor_mmap_file; freed with + * tor_munmap_file. */ +typedef struct tor_mmap_t { + const char *data; /**< Mapping of the file's contents. */ + size_t size; /**< Size of the file. */ + + /* None of the fields below should be accessed from outside compat.c */ +#ifdef HAVE_MMAP + size_t mapping_size; /**< Size of the actual mapping. (This is this file + * size, rounded up to the nearest page.) */ +#elif defined _WIN32 + HANDLE mmap_handle; +#endif /* defined(HAVE_MMAP) || ... */ + +} tor_mmap_t; + +tor_mmap_t *tor_mmap_file(const char *filename); +int tor_munmap_file(tor_mmap_t *handle); + +#endif diff --git a/src/lib/fs/path.c b/src/lib/fs/path.c new file mode 100644 index 0000000000..708ff0505a --- /dev/null +++ b/src/lib/fs/path.c @@ -0,0 +1,295 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file path.c + * + * \brief Manipulate strings that contain filesystem paths. + **/ + +#include "lib/fs/path.h" +#include "lib/malloc/util_malloc.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/fs/userdb.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <errno.h> +#include <string.h> + +/** Removes enclosing quotes from <b>path</b> and unescapes quotes between the + * enclosing quotes. Backslashes are not unescaped. Return the unquoted + * <b>path</b> on success or 0 if <b>path</b> is not quoted correctly. */ +char * +get_unquoted_path(const char *path) +{ + size_t len = strlen(path); + + if (len == 0) { + return tor_strdup(""); + } + + int has_start_quote = (path[0] == '\"'); + int has_end_quote = (len > 0 && path[len-1] == '\"'); + if (has_start_quote != has_end_quote || (len == 1 && has_start_quote)) { + return NULL; + } + + char *unquoted_path = tor_malloc(len - has_start_quote - has_end_quote + 1); + char *s = unquoted_path; + size_t i; + for (i = has_start_quote; i < len - has_end_quote; i++) { + if (path[i] == '\"' && (i > 0 && path[i-1] == '\\')) { + *(s-1) = path[i]; + } else if (path[i] != '\"') { + *s++ = path[i]; + } else { /* unescaped quote */ + tor_free(unquoted_path); + return NULL; + } + } + *s = '\0'; + return unquoted_path; +} + +/** Expand any homedir prefix on <b>filename</b>; return a newly allocated + * string. */ +char * +expand_filename(const char *filename) +{ + tor_assert(filename); +#ifdef _WIN32 + /* Might consider using GetFullPathName() as described here: + * http://etutorials.org/Programming/secure+programming/ + * Chapter+3.+Input+Validation/3.7+Validating+Filenames+and+Paths/ + */ + return tor_strdup(filename); +#else /* !(defined(_WIN32)) */ + if (*filename == '~') { + char *home, *result=NULL; + const char *rest; + + if (filename[1] == '/' || filename[1] == '\0') { + home = getenv("HOME"); + if (!home) { + log_warn(LD_CONFIG, "Couldn't find $HOME environment variable while " + "expanding \"%s\"; defaulting to \"\".", filename); + home = tor_strdup(""); + } else { + home = tor_strdup(home); + } + rest = strlen(filename)>=2?(filename+2):""; + } else { +#ifdef HAVE_PWD_H + char *username, *slash; + slash = strchr(filename, '/'); + if (slash) + username = tor_strndup(filename+1,slash-filename-1); + else + username = tor_strdup(filename+1); + if (!(home = get_user_homedir(username))) { + log_warn(LD_CONFIG,"Couldn't get homedir for \"%s\"",username); + tor_free(username); + return NULL; + } + tor_free(username); + rest = slash ? (slash+1) : ""; +#else /* !(defined(HAVE_PWD_H)) */ + log_warn(LD_CONFIG, "Couldn't expand homedir on system without pwd.h"); + return tor_strdup(filename); +#endif /* defined(HAVE_PWD_H) */ + } + tor_assert(home); + /* Remove trailing slash. */ + if (strlen(home)>1 && !strcmpend(home,PATH_SEPARATOR)) { + home[strlen(home)-1] = '\0'; + } + tor_asprintf(&result,"%s"PATH_SEPARATOR"%s",home,rest); + tor_free(home); + return result; + } else { + return tor_strdup(filename); + } +#endif /* defined(_WIN32) */ +} + +/** Return true iff <b>filename</b> is a relative path. */ +int +path_is_relative(const char *filename) +{ + if (filename && filename[0] == '/') + return 0; +#ifdef _WIN32 + else if (filename && filename[0] == '\\') + return 0; + else if (filename && strlen(filename)>3 && TOR_ISALPHA(filename[0]) && + filename[1] == ':' && filename[2] == '\\') + return 0; +#endif /* defined(_WIN32) */ + else + return 1; +} + +/** Clean up <b>name</b> so that we can use it in a call to "stat". On Unix, + * we do nothing. On Windows, we remove a trailing slash, unless the path is + * the root of a disk. */ +void +clean_fname_for_stat(char *name) +{ +#ifdef _WIN32 + size_t len = strlen(name); + if (!len) + return; + if (name[len-1]=='\\' || name[len-1]=='/') { + if (len == 1 || (len==3 && name[1]==':')) + return; + name[len-1]='\0'; + } +#else /* !(defined(_WIN32)) */ + (void)name; +#endif /* defined(_WIN32) */ +} + +/** Modify <b>fname</b> to contain the name of its parent directory. Doesn't + * actually examine the filesystem; does a purely syntactic modification. + * + * The parent of the root director is considered to be iteself. + * + * Path separators are the forward slash (/) everywhere and additionally + * the backslash (\) on Win32. + * + * Cuts off any number of trailing path separators but otherwise ignores + * them for purposes of finding the parent directory. + * + * Returns 0 if a parent directory was successfully found, -1 otherwise (fname + * did not have any path separators or only had them at the end). + * */ +int +get_parent_directory(char *fname) +{ + char *cp; + int at_end = 1; + tor_assert(fname); +#ifdef _WIN32 + /* If we start with, say, c:, then don't consider that the start of the path + */ + if (fname[0] && fname[1] == ':') { + fname += 2; + } +#endif /* defined(_WIN32) */ + /* Now we want to remove all path-separators at the end of the string, + * and to remove the end of the string starting with the path separator + * before the last non-path-separator. In perl, this would be + * s#[/]*$##; s#/[^/]*$##; + * on a unixy platform. + */ + cp = fname + strlen(fname); + at_end = 1; + while (--cp >= fname) { + int is_sep = (*cp == '/' +#ifdef _WIN32 + || *cp == '\\' +#endif + ); + if (is_sep) { + if (cp == fname) { + /* This is the first separator in the file name; don't remove it! */ + cp[1] = '\0'; + return 0; + } + *cp = '\0'; + if (! at_end) + return 0; + } else { + at_end = 0; + } + } + return -1; +} + +#ifndef _WIN32 +/** Return a newly allocated string containing the output of getcwd(). Return + * NULL on failure. (We can't just use getcwd() into a PATH_MAX buffer, since + * Hurd hasn't got a PATH_MAX.) + */ +static char * +alloc_getcwd(void) +{ +#ifdef HAVE_GET_CURRENT_DIR_NAME + /* Glibc makes this nice and simple for us. */ + char *cwd = get_current_dir_name(); + char *result = NULL; + if (cwd) { + /* We make a copy here, in case tor_malloc() is not malloc(). */ + result = tor_strdup(cwd); + raw_free(cwd); // alias for free to avoid tripping check-spaces. + } + return result; +#else /* !(defined(HAVE_GET_CURRENT_DIR_NAME)) */ + size_t size = 1024; + char *buf = NULL; + char *ptr = NULL; + + while (ptr == NULL) { + buf = tor_realloc(buf, size); + ptr = getcwd(buf, size); + + if (ptr == NULL && errno != ERANGE) { + tor_free(buf); + return NULL; + } + + size *= 2; + } + return buf; +#endif /* defined(HAVE_GET_CURRENT_DIR_NAME) */ +} +#endif /* !defined(_WIN32) */ + +/** Expand possibly relative path <b>fname</b> to an absolute path. + * Return a newly allocated string, possibly equal to <b>fname</b>. */ +char * +make_path_absolute(char *fname) +{ +#ifdef _WIN32 + char *absfname_malloced = _fullpath(NULL, fname, 1); + + /* We don't want to assume that tor_free can free a string allocated + * with malloc. On failure, return fname (it's better than nothing). */ + char *absfname = tor_strdup(absfname_malloced ? absfname_malloced : fname); + if (absfname_malloced) raw_free(absfname_malloced); + + return absfname; +#else /* !(defined(_WIN32)) */ + char *absfname = NULL, *path = NULL; + + tor_assert(fname); + + if (fname[0] == '/') { + absfname = tor_strdup(fname); + } else { + path = alloc_getcwd(); + if (path) { + tor_asprintf(&absfname, "%s/%s", path, fname); + tor_free(path); + } else { + /* LCOV_EXCL_START Can't make getcwd fail. */ + /* If getcwd failed, the best we can do here is keep using the + * relative path. (Perhaps / isn't readable by this UID/GID.) */ + log_warn(LD_GENERAL, "Unable to find current working directory: %s", + strerror(errno)); + absfname = tor_strdup(fname); + /* LCOV_EXCL_STOP */ + } + } + return absfname; +#endif /* defined(_WIN32) */ +} diff --git a/src/lib/fs/path.h b/src/lib/fs/path.h new file mode 100644 index 0000000000..384d1f514f --- /dev/null +++ b/src/lib/fs/path.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file path.h + * + * \brief Header for path.c + **/ + +#ifndef TOR_PATH_H +#define TOR_PATH_H + +#include "lib/cc/compat_compiler.h" + +#ifdef _WIN32 +#define PATH_SEPARATOR "\\" +#else +#define PATH_SEPARATOR "/" +#endif + +char *get_unquoted_path(const char *path); +char *expand_filename(const char *filename); +int path_is_relative(const char *filename); +void clean_fname_for_stat(char *name); +int get_parent_directory(char *fname); +char *make_path_absolute(char *fname); + +#endif diff --git a/src/common/storagedir.c b/src/lib/fs/storagedir.c index e2c7b4bb87..1cda2374d8 100644 --- a/src/common/storagedir.c +++ b/src/lib/fs/storagedir.c @@ -1,14 +1,32 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "container.h" -#include "compat.h" -#include "confline.h" -#include "memarea.h" -#include "sandbox.h" -#include "storagedir.h" -#include "torlog.h" -#include "util.h" +/** + * \file storagedir.c + * + * \brief An abstraction for a directory full of similar files. + * + * Storagedirs are used by our consensus cache code, and may someday also get + * used for unparseable objects. A large part of the need for this type is to + * work around the limitations in our sandbox code, where all filenames need + * to be registered in advance. + **/ + +#include "lib/fs/storagedir.h" + +#include "lib/container/smartlist.h" +#include "lib/encoding/confline.h" +#include "lib/fs/dir.h" +#include "lib/fs/files.h" +#include "lib/fs/mmap.h" +#include "lib/log/escape.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "lib/memarea/memarea.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -19,6 +37,9 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#include <stdlib.h> +#include <errno.h> +#include <string.h> #define FNAME_MIN_NUM 1000 @@ -583,4 +604,3 @@ storage_dir_get_max_files(storage_dir_t *d) { return d->max_files; } - diff --git a/src/common/storagedir.h b/src/lib/fs/storagedir.h index d99bd7ec52..58594b4634 100644 --- a/src/common/storagedir.h +++ b/src/lib/fs/storagedir.h @@ -1,12 +1,23 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +/** + * \file storagedir.h + * + * \brief Header for storagedir.c + **/ + #ifndef TOR_STORAGEDIR_H #define TOR_STORAGEDIR_H +#include "lib/cc/torint.h" +#include <stddef.h> + typedef struct storage_dir_t storage_dir_t; struct config_line_t; struct sandbox_cfg_elem; +struct tor_mmap_t; +struct smartlist_t; storage_dir_t * storage_dir_new(const char *dirname, int n_files); void storage_dir_free_(storage_dir_t *d); @@ -15,9 +26,9 @@ void storage_dir_free_(storage_dir_t *d); int storage_dir_register_with_sandbox(storage_dir_t *d, struct sandbox_cfg_elem **cfg); -const smartlist_t *storage_dir_list(storage_dir_t *d); +const struct smartlist_t *storage_dir_list(storage_dir_t *d); uint64_t storage_dir_get_usage(storage_dir_t *d); -tor_mmap_t *storage_dir_map(storage_dir_t *d, const char *fname); +struct tor_mmap_t *storage_dir_map(storage_dir_t *d, const char *fname); uint8_t *storage_dir_read(storage_dir_t *d, const char *fname, int bin, size_t *sz_out); int storage_dir_save_bytes_to_file(storage_dir_t *d, @@ -34,7 +45,7 @@ int storage_dir_save_labeled_to_file(storage_dir_t *d, const uint8_t *data, size_t length, char **fname_out); -tor_mmap_t *storage_dir_map_labeled(storage_dir_t *dir, +struct tor_mmap_t *storage_dir_map_labeled(storage_dir_t *dir, const char *fname, struct config_line_t **labels_out, const uint8_t **data_out, @@ -51,4 +62,3 @@ int storage_dir_remove_all(storage_dir_t *d); int storage_dir_get_max_files(storage_dir_t *d); #endif /* !defined(TOR_STORAGEDIR_H) */ - diff --git a/src/lib/fs/userdb.c b/src/lib/fs/userdb.c new file mode 100644 index 0000000000..3d7a9da59d --- /dev/null +++ b/src/lib/fs/userdb.c @@ -0,0 +1,138 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file userdb.c + * + * \brief Access the POSIX user database. + **/ + +#include "lib/fs/userdb.h" + +#ifndef _WIN32 +#include "lib/malloc/util_malloc.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <pwd.h> +#include <stddef.h> +#include <string.h> + +/** Cached struct from the last getpwname() call we did successfully. */ +static struct passwd *passwd_cached = NULL; + +/** Helper: copy a struct passwd object. + * + * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use + * any others, and I don't want to run into incompatibilities. + */ +static struct passwd * +tor_passwd_dup(const struct passwd *pw) +{ + struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd)); + if (pw->pw_name) + new_pw->pw_name = tor_strdup(pw->pw_name); + if (pw->pw_dir) + new_pw->pw_dir = tor_strdup(pw->pw_dir); + new_pw->pw_uid = pw->pw_uid; + new_pw->pw_gid = pw->pw_gid; + + return new_pw; +} + +#define tor_passwd_free(pw) \ + FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw)) + +/** Helper: free one of our cached 'struct passwd' values. */ +static void +tor_passwd_free_(struct passwd *pw) +{ + if (!pw) + return; + + tor_free(pw->pw_name); + tor_free(pw->pw_dir); + tor_free(pw); +} + +/** Wrapper around getpwnam() that caches result. Used so that we don't need + * to give the sandbox access to /etc/passwd. + * + * The following fields alone will definitely be copied in the output: pw_uid, + * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. + * + * When called with a NULL argument, this function clears storage associated + * with static variables it uses. + **/ +const struct passwd * +tor_getpwnam(const char *username) +{ + struct passwd *pw; + + if (username == NULL) { + tor_passwd_free(passwd_cached); + passwd_cached = NULL; + return NULL; + } + + if ((pw = getpwnam(username))) { + tor_passwd_free(passwd_cached); + passwd_cached = tor_passwd_dup(pw); + log_info(LD_GENERAL, "Caching new entry %s for %s", + passwd_cached->pw_name, username); + return pw; + } + + /* Lookup failed */ + if (! passwd_cached || ! passwd_cached->pw_name) + return NULL; + + if (! strcmp(username, passwd_cached->pw_name)) + return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky + + return NULL; +} + +/** Wrapper around getpwnam() that can use cached result from + * tor_getpwnam(). Used so that we don't need to give the sandbox access to + * /etc/passwd. + * + * The following fields alone will definitely be copied in the output: pw_uid, + * pw_gid, pw_name, pw_dir. Other fields are not present in cached values. + */ +const struct passwd * +tor_getpwuid(uid_t uid) +{ + struct passwd *pw; + + if ((pw = getpwuid(uid))) { + return pw; + } + + /* Lookup failed */ + if (! passwd_cached) + return NULL; + + if (uid == passwd_cached->pw_uid) + return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky + + return NULL; +} + +/** Allocate and return a string containing the home directory for the + * user <b>username</b>. Only works on posix-like systems. */ +char * +get_user_homedir(const char *username) +{ + const struct passwd *pw; + tor_assert(username); + + if (!(pw = tor_getpwnam(username))) { + log_err(LD_CONFIG,"User \"%s\" not found.", username); + return NULL; + } + return tor_strdup(pw->pw_dir); +} +#endif /* !defined(_WIN32) */ diff --git a/src/lib/fs/userdb.h b/src/lib/fs/userdb.h new file mode 100644 index 0000000000..3b3ab6ed2b --- /dev/null +++ b/src/lib/fs/userdb.h @@ -0,0 +1,26 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file userdb.h + * + * \brief Header for userdb.c + **/ + +#ifndef TOR_USERDB_H +#define TOR_USERDB_H + +#include "orconfig.h" + +#ifndef _WIN32 +#include <sys/types.h> + +struct passwd; +const struct passwd *tor_getpwnam(const char *username); +const struct passwd *tor_getpwuid(uid_t uid); +char *get_user_homedir(const char *username); +#endif + +#endif diff --git a/src/lib/fs/winlib.c b/src/lib/fs/winlib.c new file mode 100644 index 0000000000..532807c03f --- /dev/null +++ b/src/lib/fs/winlib.c @@ -0,0 +1,30 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file winlib.c + * + * \brief Find and load windows system libraries. + * + * We use this function to dynamically load code at runtime that might not be + * available on all versions of Windows that we support. + **/ + +#ifdef _WIN32 +#include "lib/fs/winlib.h" + +HANDLE +load_windows_system_library(const TCHAR *library_name) +{ + TCHAR path[MAX_PATH]; + unsigned n; + n = GetSystemDirectory(path, MAX_PATH); + if (n == 0 || n + _tcslen(library_name) + 2 >= MAX_PATH) + return 0; + _tcscat(path, TEXT("\\")); + _tcscat(path, library_name); + return LoadLibrary(path); +} +#endif /* defined(_WIN32) */ diff --git a/src/lib/fs/winlib.h b/src/lib/fs/winlib.h new file mode 100644 index 0000000000..5b10b9b78d --- /dev/null +++ b/src/lib/fs/winlib.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file winlib.h + * + * \brief Header for winlib.c + **/ + +#ifndef TOR_WINLIB_H +#define TOR_WINLIB_H + +#ifdef _WIN32 +#include <windows.h> +#include <tchar.h> + +HANDLE load_windows_system_library(const TCHAR *library_name); +#endif + +#endif diff --git a/src/lib/include.libdonna.am b/src/lib/include.libdonna.am new file mode 100644 index 0000000000..5b92dc58a0 --- /dev/null +++ b/src/lib/include.libdonna.am @@ -0,0 +1,24 @@ +src_lib_libcurve25519_donna_a_CFLAGS= + +if BUILD_CURVE25519_DONNA +src_lib_libcurve25519_donna_a_SOURCES=\ + src/ext/curve25519_donna/curve25519-donna.c +# See bug 13538 -- this code is known to have signed overflow issues. +src_lib_libcurve25519_donna_a_CFLAGS+=\ + @F_OMIT_FRAME_POINTER@ @CFLAGS_CONSTTIME@ +noinst_LIBRARIES+=src/lib/libcurve25519_donna.a +LIBDONNA=src/lib/libcurve25519_donna.a +else +if BUILD_CURVE25519_DONNA_C64 +src_lib_libcurve25519_donna_a_CFLAGS+=@CFLAGS_CONSTTIME@ +src_lib_libcurve25519_donna_a_SOURCES=\ + src/ext/curve25519_donna/curve25519-donna-c64.c +noinst_LIBRARIES+=src/lib/libcurve25519_donna.a +LIBDONNA=src/lib/libcurve25519_donna.a +else +LIBDONNA= +endif +endif + +LIBDONNA += $(LIBED25519_REF10) +LIBDONNA += $(LIBED25519_DONNA) diff --git a/src/lib/intmath/.may_include b/src/lib/intmath/.may_include new file mode 100644 index 0000000000..d96c112220 --- /dev/null +++ b/src/lib/intmath/.may_include @@ -0,0 +1,4 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/intmath/*.h diff --git a/src/lib/intmath/addsub.c b/src/lib/intmath/addsub.c new file mode 100644 index 0000000000..fcfdca6822 --- /dev/null +++ b/src/lib/intmath/addsub.c @@ -0,0 +1,28 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file addsub.c + * + * \brief Helpers for addition and subtraction. + * + * Currently limited to non-wrapping (saturating) addition. + **/ + +#include "lib/intmath/addsub.h" +#include "lib/cc/compat_compiler.h" + +/* Helper: safely add two uint32_t's, capping at UINT32_MAX rather + * than overflow */ +uint32_t +tor_add_u32_nowrap(uint32_t a, uint32_t b) +{ + /* a+b > UINT32_MAX check, without overflow */ + if (PREDICT_UNLIKELY(a > UINT32_MAX - b)) { + return UINT32_MAX; + } else { + return a+b; + } +} diff --git a/src/lib/intmath/addsub.h b/src/lib/intmath/addsub.h new file mode 100644 index 0000000000..5bbc32e4a9 --- /dev/null +++ b/src/lib/intmath/addsub.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file addsub.h + * + * \brief Header for addsub.c + **/ + +#ifndef TOR_INTMATH_ADDSUB_H +#define TOR_INTMATH_ADDSUB_H + +#include "lib/cc/torint.h" + +uint32_t tor_add_u32_nowrap(uint32_t a, uint32_t b); + +#endif /* !defined(TOR_INTMATH_MULDIV_H) */ diff --git a/src/lib/intmath/bits.c b/src/lib/intmath/bits.c new file mode 100644 index 0000000000..7da524449d --- /dev/null +++ b/src/lib/intmath/bits.c @@ -0,0 +1,94 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file bits.c + * + * \brief Count the bits in an integer, manipulate powers of 2, etc. + **/ + +#include "lib/intmath/bits.h" + +/** Returns floor(log2(u64)). If u64 is 0, (incorrectly) returns 0. */ +int +tor_log2(uint64_t u64) +{ + int r = 0; + if (u64 >= (UINT64_C(1)<<32)) { + u64 >>= 32; + r = 32; + } + if (u64 >= (UINT64_C(1)<<16)) { + u64 >>= 16; + r += 16; + } + if (u64 >= (UINT64_C(1)<<8)) { + u64 >>= 8; + r += 8; + } + if (u64 >= (UINT64_C(1)<<4)) { + u64 >>= 4; + r += 4; + } + if (u64 >= (UINT64_C(1)<<2)) { + u64 >>= 2; + r += 2; + } + if (u64 >= (UINT64_C(1)<<1)) { + // u64 >>= 1; // not using this any more. + r += 1; + } + return r; +} + +/** Return the power of 2 in range [1,UINT64_MAX] closest to <b>u64</b>. If + * there are two powers of 2 equally close, round down. */ +uint64_t +round_to_power_of_2(uint64_t u64) +{ + int lg2; + uint64_t low; + uint64_t high; + if (u64 == 0) + return 1; + + lg2 = tor_log2(u64); + low = UINT64_C(1) << lg2; + + if (lg2 == 63) + return low; + + high = UINT64_C(1) << (lg2+1); + if (high - u64 < u64 - low) + return high; + else + return low; +} + +/** Return the number of bits set in <b>v</b>. */ +int +n_bits_set_u8(uint8_t v) +{ + static const int nybble_table[] = { + 0, /* 0000 */ + 1, /* 0001 */ + 1, /* 0010 */ + 2, /* 0011 */ + 1, /* 0100 */ + 2, /* 0101 */ + 2, /* 0110 */ + 3, /* 0111 */ + 1, /* 1000 */ + 2, /* 1001 */ + 2, /* 1010 */ + 3, /* 1011 */ + 2, /* 1100 */ + 3, /* 1101 */ + 3, /* 1110 */ + 4, /* 1111 */ + }; + + return nybble_table[v & 15] + nybble_table[v>>4]; +} diff --git a/src/lib/intmath/bits.h b/src/lib/intmath/bits.h new file mode 100644 index 0000000000..80eebe9358 --- /dev/null +++ b/src/lib/intmath/bits.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file bits.h + * + * \brief Header for bits.c + **/ + +#ifndef TOR_INTMATH_BITS_H +#define TOR_INTMATH_BITS_H + +#include "lib/cc/torint.h" +#include "lib/cc/compat_compiler.h" + +int tor_log2(uint64_t u64) ATTR_CONST; +uint64_t round_to_power_of_2(uint64_t u64); +int n_bits_set_u8(uint8_t v); + +#endif /* !defined(TOR_INTMATH_BITS_H) */ diff --git a/src/lib/intmath/cmp.h b/src/lib/intmath/cmp.h new file mode 100644 index 0000000000..16952bee3e --- /dev/null +++ b/src/lib/intmath/cmp.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file cmp.h + * + * \brief Macro definitions for MIN, MAX, and CLAMP. + **/ + +#ifndef TOR_INTMATH_CMP_H +#define TOR_INTMATH_CMP_H + +/** Macros for MIN/MAX. Never use these when the arguments could have + * side-effects. + * {With GCC extensions we could probably define a safer MIN/MAX. But + * depending on that safety would be dangerous, since not every platform + * has it.} + **/ +#ifndef MAX +#define MAX(a,b) ( ((a)<(b)) ? (b) : (a) ) +#endif +#ifndef MIN +#define MIN(a,b) ( ((a)>(b)) ? (b) : (a) ) +#endif + +/* Return <b>v</b> if it's between <b>min</b> and <b>max</b>. Otherwise + * return <b>min</b> if <b>v</b> is smaller than <b>min</b>, or <b>max</b> if + * <b>b</b> is larger than <b>max</b>. + * + * Requires that <b>min</b> is no more than <b>max</b>. May evaluate any of + * its arguments more than once! */ +#define CLAMP(min,v,max) \ + ( ((v) < (min)) ? (min) : \ + ((v) > (max)) ? (max) : \ + (v) ) + +#endif /* !defined(TOR_INTMATH_CMP_H) */ diff --git a/src/lib/intmath/include.am b/src/lib/intmath/include.am new file mode 100644 index 0000000000..45ee3bd53b --- /dev/null +++ b/src/lib/intmath/include.am @@ -0,0 +1,25 @@ + +noinst_LIBRARIES += src/lib/libtor-intmath.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-intmath-testing.a +endif + +src_lib_libtor_intmath_a_SOURCES = \ + src/lib/intmath/addsub.c \ + src/lib/intmath/bits.c \ + src/lib/intmath/muldiv.c \ + src/lib/intmath/weakrng.c + +src_lib_libtor_intmath_testing_a_SOURCES = \ + $(src_lib_libtor_intmath_a_SOURCES) +src_lib_libtor_intmath_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_intmath_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/intmath/addsub.h \ + src/lib/intmath/cmp.h \ + src/lib/intmath/bits.h \ + src/lib/intmath/logic.h \ + src/lib/intmath/muldiv.h \ + src/lib/intmath/weakrng.h diff --git a/src/lib/intmath/logic.h b/src/lib/intmath/logic.h new file mode 100644 index 0000000000..b3eabc652e --- /dev/null +++ b/src/lib/intmath/logic.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file logic.h + * + * \brief Macros for comparing the boolean value of integers. + **/ + +#ifndef HAVE_TOR_LOGIC_H +#define HAVE_TOR_LOGIC_H + +/** Macro: true if two values have the same boolean value. */ +#define bool_eq(a,b) (!(a)==!(b)) +/** Macro: true if two values have different boolean values. */ +#define bool_neq(a,b) (!(a)!=!(b)) + +#endif diff --git a/src/lib/intmath/muldiv.c b/src/lib/intmath/muldiv.c new file mode 100644 index 0000000000..c5fc689e2d --- /dev/null +++ b/src/lib/intmath/muldiv.c @@ -0,0 +1,81 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file muldiv.c + * + * \brief Integer math related to multiplication, division, and rounding. + **/ + +#include "lib/intmath/muldiv.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +/** Return the lowest x such that x is at least <b>number</b>, and x modulo + * <b>divisor</b> == 0. If no such x can be expressed as an unsigned, return + * UINT_MAX. Asserts if divisor is zero. */ +unsigned +round_to_next_multiple_of(unsigned number, unsigned divisor) +{ + raw_assert(divisor > 0); + if (UINT_MAX - divisor + 1 < number) + return UINT_MAX; + number += divisor - 1; + number -= number % divisor; + return number; +} + +/** Return the lowest x such that x is at least <b>number</b>, and x modulo + * <b>divisor</b> == 0. If no such x can be expressed as a uint32_t, return + * UINT32_MAX. Asserts if divisor is zero. */ +uint32_t +round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor) +{ + raw_assert(divisor > 0); + if (UINT32_MAX - divisor + 1 < number) + return UINT32_MAX; + + number += divisor - 1; + number -= number % divisor; + return number; +} + +/** Return the lowest x such that x is at least <b>number</b>, and x modulo + * <b>divisor</b> == 0. If no such x can be expressed as a uint64_t, return + * UINT64_MAX. Asserts if divisor is zero. */ +uint64_t +round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor) +{ + raw_assert(divisor > 0); + if (UINT64_MAX - divisor + 1 < number) + return UINT64_MAX; + number += divisor - 1; + number -= number % divisor; + return number; +} + +/* Helper: return greatest common divisor of a,b */ +static uint64_t +gcd64(uint64_t a, uint64_t b) +{ + while (b) { + uint64_t t = b; + b = a % b; + a = t; + } + return a; +} + +/* Given a fraction *<b>numer</b> / *<b>denom</b>, simplify it. + * Requires that the denominator is greater than 0. */ +void +simplify_fraction64(uint64_t *numer, uint64_t *denom) +{ + raw_assert(denom); + uint64_t gcd = gcd64(*numer, *denom); + *numer /= gcd; + *denom /= gcd; +} diff --git a/src/lib/intmath/muldiv.h b/src/lib/intmath/muldiv.h new file mode 100644 index 0000000000..45b896922f --- /dev/null +++ b/src/lib/intmath/muldiv.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file muldiv.h + * + * \brief Header for muldiv.c + **/ + +#ifndef TOR_INTMATH_MULDIV_H +#define TOR_INTMATH_MULDIV_H + +#include "lib/cc/torint.h" + +unsigned round_to_next_multiple_of(unsigned number, unsigned divisor); +uint32_t round_uint32_to_next_multiple_of(uint32_t number, uint32_t divisor); +uint64_t round_uint64_to_next_multiple_of(uint64_t number, uint64_t divisor); + +void simplify_fraction64(uint64_t *numer, uint64_t *denom); + +/* Compute the CEIL of <b>a</b> divided by <b>b</b>, for nonnegative <b>a</b> + * and positive <b>b</b>. Works on integer types only. Not defined if a+(b-1) + * can overflow. */ +#define CEIL_DIV(a,b) (((a)+((b)-1))/(b)) + +#endif /* !defined(TOR_INTMATH_MULDIV_H) */ diff --git a/src/lib/intmath/weakrng.c b/src/lib/intmath/weakrng.c new file mode 100644 index 0000000000..36cf5fb0aa --- /dev/null +++ b/src/lib/intmath/weakrng.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file weakrng.c + * + * \brief A weak but fast PRNG based on a linear congruential generator. + * + * We don't want to use the platform random(), since some of them are even + * worse than this. + **/ + +#include "lib/intmath/weakrng.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +/** Initialize the insecure RNG <b>rng</b> from a seed value <b>seed</b>. */ +void +tor_init_weak_random(tor_weak_rng_t *rng, unsigned seed) +{ + rng->state = (uint32_t)(seed & 0x7fffffff); +} + +/** Return a randomly chosen value in the range 0..TOR_WEAK_RANDOM_MAX based + * on the RNG state of <b>rng</b>. This entropy will not be cryptographically + * strong; do not rely on it for anything an adversary should not be able to + * predict. */ +int32_t +tor_weak_random(tor_weak_rng_t *rng) +{ + /* Here's a linear congruential generator. OpenBSD and glibc use these + * parameters; they aren't too bad, and should have maximal period over the + * range 0..INT32_MAX. We don't want to use the platform rand() or random(), + * since some platforms have bad weak RNGs that only return values in the + * range 0..INT16_MAX, which just isn't enough. */ + rng->state = (rng->state * 1103515245 + 12345) & 0x7fffffff; + return (int32_t) rng->state; +} + +/** Return a random number in the range [0 , <b>top</b>). {That is, the range + * of integers i such that 0 <= i < top.} Chooses uniformly. Requires that + * top is greater than 0. This randomness is not cryptographically strong; do + * not rely on it for anything an adversary should not be able to predict. */ +int32_t +tor_weak_random_range(tor_weak_rng_t *rng, int32_t top) +{ + /* We don't want to just do tor_weak_random() % top, since random() is often + * implemented with an LCG whose modulus is a power of 2, and those are + * cyclic in their low-order bits. */ + int divisor, result; + raw_assert(top > 0); + divisor = TOR_WEAK_RANDOM_MAX / top; + do { + result = (int32_t)(tor_weak_random(rng) / divisor); + } while (result >= top); + return result; +} diff --git a/src/lib/intmath/weakrng.h b/src/lib/intmath/weakrng.h new file mode 100644 index 0000000000..679bf2449c --- /dev/null +++ b/src/lib/intmath/weakrng.h @@ -0,0 +1,31 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file weakrng.h + * + * \brief Header for weakrng.c + **/ + +#ifndef TOR_WEAKRNG_H +#define TOR_WEAKRNG_H + +#include "lib/cc/torint.h" + +/* ===== Insecure rng */ +typedef struct tor_weak_rng_t { + uint32_t state; +} tor_weak_rng_t; + +#define TOR_WEAK_RNG_INIT {383745623} +#define TOR_WEAK_RANDOM_MAX (INT_MAX) +void tor_init_weak_random(tor_weak_rng_t *weak_rng, unsigned seed); +int32_t tor_weak_random(tor_weak_rng_t *weak_rng); +int32_t tor_weak_random_range(tor_weak_rng_t *rng, int32_t top); +/** Randomly return true according to <b>rng</b> with probability 1 in + * <b>n</b> */ +#define tor_weak_random_one_in_n(rng, n) (0==tor_weak_random_range((rng),(n))) + +#endif diff --git a/src/lib/lock/.may_include b/src/lib/lock/.may_include new file mode 100644 index 0000000000..9522e3af49 --- /dev/null +++ b/src/lib/lock/.may_include @@ -0,0 +1,5 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/lock/*.h +lib/malloc/*.h diff --git a/src/lib/lock/compat_mutex.c b/src/lib/lock/compat_mutex.c new file mode 100644 index 0000000000..bfab6dd29b --- /dev/null +++ b/src/lib/lock/compat_mutex.c @@ -0,0 +1,40 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_mutex.c + * + * \brief Portable wrapper for platform mutex implementations. + **/ + +#include "lib/lock/compat_mutex.h" +#include "lib/malloc/util_malloc.h" + +/** Return a newly allocated, ready-for-use mutex. */ +tor_mutex_t * +tor_mutex_new(void) +{ + tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); + tor_mutex_init(m); + return m; +} +/** Return a newly allocated, ready-for-use mutex. This one might be + * non-recursive, if that's faster. */ +tor_mutex_t * +tor_mutex_new_nonrecursive(void) +{ + tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); + tor_mutex_init_nonrecursive(m); + return m; +} +/** Release all storage and system resources held by <b>m</b>. */ +void +tor_mutex_free_(tor_mutex_t *m) +{ + if (!m) + return; + tor_mutex_uninit(m); + tor_free(m); +} diff --git a/src/lib/lock/compat_mutex.h b/src/lib/lock/compat_mutex.h new file mode 100644 index 0000000000..f467aa5dba --- /dev/null +++ b/src/lib/lock/compat_mutex.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_mutex.h + * + * \brief Header for compat_mutex.c + **/ + +#ifndef TOR_COMPAT_MUTEX_H +#define TOR_COMPAT_MUTEX_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + +#if defined(HAVE_PTHREAD_H) && !defined(_WIN32) +#include <pthread.h> +#endif + +#if defined(_WIN32) +#include <windows.h> +#endif + +#if defined(_WIN32) +#define USE_WIN32_THREADS +#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE) +#define USE_PTHREADS +#else +#error "No threading system was found" +#endif /* defined(_WIN32) || ... */ + +/* Because we use threads instead of processes on most platforms (Windows, + * Linux, etc), we need locking for them. On platforms with poor thread + * support or broken gethostbyname_r, these functions are no-ops. */ + +/** A generic lock structure for multithreaded builds. */ +typedef struct tor_mutex_t { +#if defined(USE_WIN32_THREADS) + /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ + CRITICAL_SECTION mutex; +#elif defined(USE_PTHREADS) + /** Pthreads-only: with pthreads, we implement locks with + * pthread_mutex_t. */ + pthread_mutex_t mutex; +#else + /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ + int _unused; +#endif /* defined(USE_WIN32_MUTEX) || ... */ +} tor_mutex_t; + +tor_mutex_t *tor_mutex_new(void); +tor_mutex_t *tor_mutex_new_nonrecursive(void); +void tor_mutex_init(tor_mutex_t *m); +void tor_mutex_init_nonrecursive(tor_mutex_t *m); +void tor_mutex_acquire(tor_mutex_t *m); +void tor_mutex_release(tor_mutex_t *m); +void tor_mutex_free_(tor_mutex_t *m); +#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m)) +void tor_mutex_uninit(tor_mutex_t *m); + +void tor_locking_init(void); + +#endif /* !defined(TOR_COMPAT_MUTEX_H) */ diff --git a/src/lib/lock/compat_mutex_pthreads.c b/src/lib/lock/compat_mutex_pthreads.c new file mode 100644 index 0000000000..983abf5ae5 --- /dev/null +++ b/src/lib/lock/compat_mutex_pthreads.c @@ -0,0 +1,103 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_mutex_pthreads.c + * + * \brief Implement the tor_mutex API using pthread_mutex_t. + **/ + +#include "lib/lock/compat_mutex.h" +#include "lib/cc/compat_compiler.h" +#include "lib/err/torerr.h" + +/** A mutex attribute that we're going to use to tell pthreads that we want + * "recursive" mutexes (i.e., once we can re-lock if we're already holding + * them.) */ +static pthread_mutexattr_t attr_recursive; +static int attr_initialized = 0; + +void +tor_locking_init(void) +{ + if (!attr_initialized) { + pthread_mutexattr_init(&attr_recursive); + pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); + attr_initialized = 1; + } +} + +/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set + * up with tor_mutex_init() or tor_mutex_new(); not both. */ +void +tor_mutex_init(tor_mutex_t *mutex) +{ + if (PREDICT_UNLIKELY(!attr_initialized)) + tor_locking_init(); // LCOV_EXCL_LINE + const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error creating a mutex."); + // LCOV_EXCL_STOP + } +} + +/** As tor_mutex_init, but initialize a mutex suitable that may be + * non-recursive, if the OS supports that. */ +void +tor_mutex_init_nonrecursive(tor_mutex_t *mutex) +{ + int err; + if (!attr_initialized) + tor_locking_init(); // LCOV_EXCL_LINE + err = pthread_mutex_init(&mutex->mutex, NULL); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error creating a mutex."); + // LCOV_EXCL_STOP + } +} + +/** Wait until <b>m</b> is free, then acquire it. */ +void +tor_mutex_acquire(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_lock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error locking a mutex."); + // LCOV_EXCL_STOP + } +} +/** Release the lock <b>m</b> so another thread can have it. */ +void +tor_mutex_release(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_unlock(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error unlocking a mutex."); + // LCOV_EXCL_STOP + } +} +/** Clean up the mutex <b>m</b> so that it no longer uses any system + * resources. Does not free <b>m</b>. This function must only be called on + * mutexes from tor_mutex_init(). */ +void +tor_mutex_uninit(tor_mutex_t *m) +{ + int err; + raw_assert(m); + err = pthread_mutex_destroy(&m->mutex); + if (PREDICT_UNLIKELY(err)) { + // LCOV_EXCL_START + raw_assert_unreached_msg("Error destroying a mutex."); + // LCOV_EXCL_STOP + } +} diff --git a/src/lib/lock/compat_mutex_winthreads.c b/src/lib/lock/compat_mutex_winthreads.c new file mode 100644 index 0000000000..22c1edeed4 --- /dev/null +++ b/src/lib/lock/compat_mutex_winthreads.c @@ -0,0 +1,46 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_mutex_winthreads.c + * + * \brief Implement the tor_mutex API using CRITICAL_SECTION. + **/ + +#include "lib/lock/compat_mutex.h" +#include "lib/err/torerr.h" + +void +tor_locking_init(void) +{ +} + +void +tor_mutex_init(tor_mutex_t *m) +{ + InitializeCriticalSection(&m->mutex); +} +void +tor_mutex_init_nonrecursive(tor_mutex_t *m) +{ + InitializeCriticalSection(&m->mutex); +} + +void +tor_mutex_uninit(tor_mutex_t *m) +{ + DeleteCriticalSection(&m->mutex); +} +void +tor_mutex_acquire(tor_mutex_t *m) +{ + raw_assert(m); + EnterCriticalSection(&m->mutex); +} +void +tor_mutex_release(tor_mutex_t *m) +{ + LeaveCriticalSection(&m->mutex); +} diff --git a/src/lib/lock/include.am b/src/lib/lock/include.am new file mode 100644 index 0000000000..4e6f444347 --- /dev/null +++ b/src/lib/lock/include.am @@ -0,0 +1,24 @@ + +noinst_LIBRARIES += src/lib/libtor-lock.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-lock-testing.a +endif + +src_lib_libtor_lock_a_SOURCES = \ + src/lib/lock/compat_mutex.c + +if THREADS_PTHREADS +src_lib_libtor_lock_a_SOURCES += src/lib/lock/compat_mutex_pthreads.c +endif +if THREADS_WIN32 +src_lib_libtor_lock_a_SOURCES += src/lib/lock/compat_mutex_winthreads.c +endif + +src_lib_libtor_lock_testing_a_SOURCES = \ + $(src_lib_libtor_lock_a_SOURCES) +src_lib_libtor_lock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_lock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/lock/compat_mutex.h diff --git a/src/lib/log/.may_include b/src/lib/log/.may_include new file mode 100644 index 0000000000..852173aab3 --- /dev/null +++ b/src/lib/log/.may_include @@ -0,0 +1,15 @@ +orconfig.h + +lib/cc/*.h +lib/smartlist_core/*.h +lib/err/*.h +lib/fdio/*.h +lib/intmath/*.h +lib/lock/*.h +lib/log/*.h +lib/malloc/*.h +lib/string/*.h +lib/testsupport/*.h +lib/wallclock/*.h + +micro-revision.i
\ No newline at end of file diff --git a/src/lib/log/escape.c b/src/lib/log/escape.c new file mode 100644 index 0000000000..7561710309 --- /dev/null +++ b/src/lib/log/escape.c @@ -0,0 +1,132 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/log/escape.h" +#include "lib/log/util_bug.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/printf.h" +#include "lib/malloc/util_malloc.h" + +/** Allocate and return a new string representing the contents of <b>s</b>, + * surrounded by quotes and using standard C escapes. + * + * Generally, we use this for logging values that come in over the network to + * keep them from tricking users, and for sending certain values to the + * controller. + * + * We trust values from the resolver, OS, configuration file, and command line + * to not be maliciously ill-formed. We validate incoming routerdescs and + * SOCKS requests and addresses from BEGIN cells as they're parsed; + * afterwards, we trust them as non-malicious. + */ +char * +esc_for_log(const char *s) +{ + const char *cp; + char *result, *outp; + size_t len = 3; + if (!s) { + return tor_strdup("(null)"); + } + + for (cp = s; *cp; ++cp) { + switch (*cp) { + case '\\': + case '\"': + case '\'': + case '\r': + case '\n': + case '\t': + len += 2; + break; + default: + if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) + ++len; + else + len += 4; + break; + } + } + + tor_assert(len <= SSIZE_MAX); + + result = outp = tor_malloc(len); + *outp++ = '\"'; + for (cp = s; *cp; ++cp) { + /* This assertion should always succeed, since we will write at least + * one char here, and two chars for closing quote and nul later */ + tor_assert((outp-result) < (ssize_t)len-2); + switch (*cp) { + case '\\': + case '\"': + case '\'': + *outp++ = '\\'; + *outp++ = *cp; + break; + case '\n': + *outp++ = '\\'; + *outp++ = 'n'; + break; + case '\t': + *outp++ = '\\'; + *outp++ = 't'; + break; + case '\r': + *outp++ = '\\'; + *outp++ = 'r'; + break; + default: + if (TOR_ISPRINT(*cp) && ((uint8_t)*cp)<127) { + *outp++ = *cp; + } else { + tor_assert((outp-result) < (ssize_t)len-4); + tor_snprintf(outp, 5, "\\%03o", (int)(uint8_t) *cp); + outp += 4; + } + break; + } + } + + tor_assert((outp-result) <= (ssize_t)len-2); + *outp++ = '\"'; + *outp++ = 0; + + return result; +} + +/** Similar to esc_for_log. Allocate and return a new string representing + * the first n characters in <b>chars</b>, surround by quotes and using + * standard C escapes. If a NUL character is encountered in <b>chars</b>, + * the resulting string will be terminated there. + */ +char * +esc_for_log_len(const char *chars, size_t n) +{ + char *string = tor_strndup(chars, n); + char *string_escaped = esc_for_log(string); + tor_free(string); + return string_escaped; +} + +/** Allocate and return a new string representing the contents of <b>s</b>, + * surrounded by quotes and using standard C escapes. + * + * THIS FUNCTION IS NOT REENTRANT. Don't call it from outside the main + * thread. Also, each call invalidates the last-returned value, so don't + * try log_warn(LD_GENERAL, "%s %s", escaped(a), escaped(b)); + */ +const char * +escaped(const char *s) +{ + static char *escaped_val_ = NULL; + tor_free(escaped_val_); + + if (s) + escaped_val_ = esc_for_log(s); + else + escaped_val_ = NULL; + + return escaped_val_; +} diff --git a/src/lib/log/escape.h b/src/lib/log/escape.h new file mode 100644 index 0000000000..5d2e79d6c2 --- /dev/null +++ b/src/lib/log/escape.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2001, Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ESCAPE_H +#define TOR_ESCAPE_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" +#include <stddef.h> + +char *esc_for_log(const char *string) ATTR_MALLOC; +char *esc_for_log_len(const char *chars, size_t n) ATTR_MALLOC; +const char *escaped(const char *string); + +#endif /* !defined(TOR_TORLOG_H) */ diff --git a/src/lib/log/include.am b/src/lib/log/include.am new file mode 100644 index 0000000000..f0491b3863 --- /dev/null +++ b/src/lib/log/include.am @@ -0,0 +1,31 @@ + +noinst_LIBRARIES += src/lib/libtor-log.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-log-testing.a +endif + +src_lib_libtor_log_a_SOURCES = \ + src/lib/log/escape.c \ + src/lib/log/ratelim.c \ + src/lib/log/torlog.c \ + src/lib/log/util_bug.c + +if WIN32 +src_lib_libtor_log_a_SOURCES += src/lib/log/win32err.c +endif + +src_lib_libtor_log_testing_a_SOURCES = \ + $(src_lib_libtor_log_a_SOURCES) +src_lib_libtor_log_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_log_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +src/lib/log/torlog.$(OBJEXT) \ + src/lib/log/src_lib_libtor_log_testing_a-torlog.$(OBJEXT): micro-revision.i + +noinst_HEADERS += \ + src/lib/log/escape.h \ + src/lib/log/ratelim.h \ + src/lib/log/torlog.h \ + src/lib/log/util_bug.h \ + src/lib/log/win32err.h diff --git a/src/lib/log/ratelim.c b/src/lib/log/ratelim.c new file mode 100644 index 0000000000..677c499110 --- /dev/null +++ b/src/lib/log/ratelim.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/log/ratelim.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return the number + * of calls to rate_limit_is_ready (including this one!) since the last time + * rate_limit_is_ready returned nonzero. Otherwise return 0. + * If the call number hits <b>RATELIM_TOOMANY</b> limit, drop a warning + * about this event and stop counting. */ +static int +rate_limit_is_ready(ratelim_t *lim, time_t now) +{ + if (lim->rate + lim->last_allowed <= now) { + int res = lim->n_calls_since_last_time + 1; + lim->last_allowed = now; + lim->n_calls_since_last_time = 0; + return res; + } else { + if (lim->n_calls_since_last_time <= RATELIM_TOOMANY) { + ++lim->n_calls_since_last_time; + } + + return 0; + } +} + +/** If the rate-limiter <b>lim</b> is ready at <b>now</b>, return a newly + * allocated string indicating how many messages were suppressed, suitable to + * append to a log message. Otherwise return NULL. */ +char * +rate_limit_log(ratelim_t *lim, time_t now) +{ + int n; + if ((n = rate_limit_is_ready(lim, now))) { + if (n == 1) { + return tor_strdup(""); + } else { + char *cp=NULL; + const char *opt_over = (n >= RATELIM_TOOMANY) ? "over " : ""; + /* XXXX this is not exactly correct: the messages could have occurred + * any time between the old value of lim->allowed and now. */ + tor_asprintf(&cp, + " [%s%d similar message(s) suppressed in last %d seconds]", + opt_over, n-1, lim->rate); + return cp; + } + } else { + return NULL; + } +} diff --git a/src/lib/log/ratelim.h b/src/lib/log/ratelim.h new file mode 100644 index 0000000000..4ee6c5fed4 --- /dev/null +++ b/src/lib/log/ratelim.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_RATELIM_H +#define TOR_RATELIM_H + +#include <time.h> + +/* Rate-limiter */ + +/** A ratelim_t remembers how often an event is occurring, and how often + * it's allowed to occur. Typical usage is something like: + * + <pre> + if (possibly_very_frequent_event()) { + const int INTERVAL = 300; + static ratelim_t warning_limit = RATELIM_INIT(INTERVAL); + char *m; + if ((m = rate_limit_log(&warning_limit, approx_time()))) { + log_warn(LD_GENERAL, "The event occurred!%s", m); + tor_free(m); + } + } + </pre> + + As a convenience wrapper for logging, you can replace the above with: + <pre> + if (possibly_very_frequent_event()) { + static ratelim_t warning_limit = RATELIM_INIT(300); + log_fn_ratelim(&warning_limit, LOG_WARN, LD_GENERAL, + "The event occurred!"); + } + </pre> + */ +typedef struct ratelim_t { + int rate; + time_t last_allowed; + int n_calls_since_last_time; +} ratelim_t; + +#define RATELIM_INIT(r) { (r), 0, 0 } +#define RATELIM_TOOMANY (16*1000*1000) + +char *rate_limit_log(ratelim_t *lim, time_t now); + +#endif diff --git a/src/common/log.c b/src/lib/log/torlog.c index ebd50f62d3..1c9f33790d 100644 --- a/src/common/log.c +++ b/src/lib/log/torlog.c @@ -1,18 +1,17 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file log.c + * \file torlog.c * \brief Functions to send messages to log files or the console. **/ #include "orconfig.h" #include <stdarg.h> -#include <assert.h> -// #include <stdio.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef HAVE_SYS_TIME_H @@ -30,11 +29,25 @@ #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#include "compat.h" -#include "util.h" + #define LOG_PRIVATE -#include "torlog.h" -#include "container.h" +#include "lib/log/torlog.h" +#include "lib/log/ratelim.h" +#include "lib/lock/compat_mutex.h" +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_foreach.h" +#include "lib/smartlist_core/smartlist_split.h" +#include "lib/err/torerr.h" +#include "lib/intmath/bits.h" +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/util_string.h" +#include "lib/wallclock/tor_gettimeofday.h" +#include "lib/wallclock/approx_time.h" +#include "lib/wallclock/tm_cvt.h" +#include "lib/fdio/fdio.h" + #ifdef HAVE_ANDROID_LOG_H #include <android/log.h> #endif // HAVE_ANDROID_LOG_H. @@ -50,8 +63,6 @@ #define TRUNCATED_STR_LEN 14 /** @} */ -#define raw_assert(x) assert(x) // assert OK - /** Defining compile-time constants for Tor log levels (used by the Rust * log wrapper at src/rust/tor_log) */ const int LOG_WARN_ = LOG_WARN; @@ -89,9 +100,9 @@ sev_to_string(int severity) case LOG_NOTICE: return "notice"; case LOG_WARN: return "warn"; case LOG_ERR: return "err"; - default: /* Call assert, not tor_assert, since tor_assert - * calls log on failure. */ - raw_assert(0); return "UNKNOWN"; // LCOV_EXCL_LINE + default: /* Call assert, not tor_assert, since tor_assert + * calls log on failure. */ + raw_assert_unreached(); return "UNKNOWN"; // LCOV_EXCL_LINE } } @@ -195,12 +206,12 @@ static int pretty_fn_has_parens = 0; /** Lock the log_mutex to prevent others from changing the logfile_t list */ #define LOCK_LOGS() STMT_BEGIN \ - tor_assert(log_mutex_initialized); \ + raw_assert(log_mutex_initialized); \ tor_mutex_acquire(&log_mutex); \ STMT_END /** Unlock the log_mutex */ #define UNLOCK_LOGS() STMT_BEGIN \ - tor_assert(log_mutex_initialized); \ + raw_assert(log_mutex_initialized); \ tor_mutex_release(&log_mutex); \ STMT_END @@ -268,6 +279,7 @@ void set_log_time_granularity(int granularity_msec) { log_time_granularity = granularity_msec; + tor_log_sigsafe_err_set_granularity(granularity_msec); } /** Helper: Write the standard prefix for log lines to a @@ -292,7 +304,8 @@ log_prefix_(char *buf, size_t buf_len, int severity) ms -= ((int)now.tv_usec / 1000) % log_time_granularity; } - n = strftime(buf, buf_len, "%b %d %H:%M:%S", tor_localtime_r(&t, &tm)); + n = strftime(buf, buf_len, "%b %d %H:%M:%S", + tor_localtime_r_msg(&t, &tm, NULL)); r = tor_snprintf(buf+n, buf_len-n, ".%.3i [%s] ", ms, sev_to_string(severity)); @@ -335,7 +348,7 @@ log_tor_version(logfile_t *lf, int reset) tor_snprintf(buf+n, sizeof(buf)-n, "Tor %s opening %slog file.\n", VERSION, is_new?"new ":""); } - if (write_all(lf->fd, buf, strlen(buf), 0) < 0) /* error */ + if (write_all_to_fd_minimal(lf->fd, buf, strlen(buf)) < 0) /* error */ return -1; /* failed */ return 0; } @@ -549,7 +562,7 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len, lf->callback(severity, domain, msg_after_prefix); } } else { - if (write_all(lf->fd, buf, msg_len, 0) < 0) { /* error */ + if (write_all_to_fd_minimal(lf->fd, buf, msg_len) < 0) { /* error */ /* don't log the error! mark this log entry to be blown away, and * continue. */ lf->seems_dead = 1; @@ -572,7 +585,7 @@ logv,(int severity, log_domain_mask_t domain, const char *funcname, char *end_of_prefix=NULL; int callbacks_deferred = 0; - /* Call assert, not tor_assert, since tor_assert calls log on failure. */ + /* Call assert, not raw_assert, since raw_assert calls log on failure. */ raw_assert(format); /* check that severity is sane. Overrunning the masks array leads to * interesting and hard to diagnose effects */ @@ -634,71 +647,6 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...) va_end(ap); } -/** Maximum number of fds that will get notifications if we crash */ -#define MAX_SIGSAFE_FDS 8 -/** Array of fds to log crash-style warnings to. */ -static int sigsafe_log_fds[MAX_SIGSAFE_FDS] = { STDERR_FILENO }; -/** The number of elements used in sigsafe_log_fds */ -static int n_sigsafe_log_fds = 1; - -/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1 - * on failure. */ -static int -tor_log_err_sigsafe_write(const char *s) -{ - int i; - ssize_t r; - size_t len = strlen(s); - int err = 0; - for (i=0; i < n_sigsafe_log_fds; ++i) { - r = write(sigsafe_log_fds[i], s, len); - err += (r != (ssize_t)len); - } - return err ? -1 : 0; -} - -/** Given a list of string arguments ending with a NULL, writes them - * to our logs and to stderr (if possible). This function is safe to call - * from within a signal handler. */ -void -tor_log_err_sigsafe(const char *m, ...) -{ - va_list ap; - const char *x; - char timebuf[33]; - time_t now = time(NULL); - - if (!m) - return; - if (log_time_granularity >= 2000) { - int g = log_time_granularity / 1000; - now -= now % g; - } - timebuf[0] = now < 0 ? '-' : ' '; - if (now < 0) now = -now; - timebuf[1] = '\0'; - format_dec_number_sigsafe(now, timebuf+1, sizeof(timebuf)-1); - tor_log_err_sigsafe_write("\n==========================================" - "================== T="); - tor_log_err_sigsafe_write(timebuf); - tor_log_err_sigsafe_write("\n"); - tor_log_err_sigsafe_write(m); - va_start(ap, m); - while ((x = va_arg(ap, const char*))) { - tor_log_err_sigsafe_write(x); - } - va_end(ap); -} - -/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from - * inside a signal handler. Return the number of elements in the array. */ -int -tor_log_get_sigsafe_err_fds(const int **out) -{ - *out = sigsafe_log_fds; - return n_sigsafe_log_fds; -} - /** Helper function; return true iff the <b>n</b>-element array <b>array</b> * contains <b>item</b>. */ static int @@ -720,11 +668,14 @@ tor_log_update_sigsafe_err_fds(void) const logfile_t *lf; int found_real_stderr = 0; + int fds[TOR_SIGSAFE_LOG_MAX_FDS]; + int n_fds; + LOCK_LOGS(); /* Reserve the first one for stderr. This is safe because when we daemonize, * we dup2 /dev/null to stderr, */ - sigsafe_log_fds[0] = STDERR_FILENO; - n_sigsafe_log_fds = 1; + fds[0] = STDERR_FILENO; + n_fds = 1; for (lf = logfiles; lf; lf = lf->next) { /* Don't try callback to the control port, or syslogs: We can't @@ -738,22 +689,24 @@ tor_log_update_sigsafe_err_fds(void) if (lf->fd == STDERR_FILENO) found_real_stderr = 1; /* Avoid duplicates */ - if (int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, lf->fd)) + if (int_array_contains(fds, n_fds, lf->fd)) continue; - sigsafe_log_fds[n_sigsafe_log_fds++] = lf->fd; - if (n_sigsafe_log_fds == MAX_SIGSAFE_FDS) + fds[n_fds++] = lf->fd; + if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS) break; } } if (!found_real_stderr && - int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, STDOUT_FILENO)) { + int_array_contains(fds, n_fds, STDOUT_FILENO)) { /* Don't use a virtual stderr when we're also logging to stdout. */ - raw_assert(n_sigsafe_log_fds >= 2); /* Don't tor_assert inside log fns */ - sigsafe_log_fds[0] = sigsafe_log_fds[--n_sigsafe_log_fds]; + raw_assert(n_fds >= 2); /* Don't raw_assert inside log fns */ + fds[0] = fds[--n_fds]; } UNLOCK_LOGS(); + + tor_log_set_sigsafe_err_fds(fds, n_fds); } /** Add to <b>out</b> a copy of every currently configured log file name. Used @@ -762,7 +715,7 @@ void tor_log_get_logfile_names(smartlist_t *out) { logfile_t *lf; - tor_assert(out); + raw_assert(out); LOCK_LOGS(); @@ -875,8 +828,8 @@ delete_log(logfile_t *victim) logfiles = victim->next; else { for (tmpl = logfiles; tmpl && tmpl->next != victim; tmpl=tmpl->next) ; -// tor_assert(tmpl); -// tor_assert(tmpl->next == victim); +// raw_assert(tmpl); +// raw_assert(tmpl->next == victim); if (!tmpl) return; tmpl->next = victim->next; @@ -910,9 +863,9 @@ set_log_severity_config(int loglevelMin, int loglevelMax, log_severity_list_t *severity_out) { int i; - tor_assert(loglevelMin >= loglevelMax); - tor_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG); - tor_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG); + raw_assert(loglevelMin >= loglevelMax); + raw_assert(loglevelMin >= LOG_ERR && loglevelMin <= LOG_DEBUG); + raw_assert(loglevelMax >= LOG_ERR && loglevelMax <= LOG_DEBUG); memset(severity_out, 0, sizeof(log_severity_list_t)); for (i = loglevelMin; i >= loglevelMax; --i) { severity_out->masks[SEVERITY_MASK_IDX(i)] = ~0u; @@ -1182,20 +1135,17 @@ mark_logs_temp(void) } /** - * Add a log handler to send messages to <b>filename</b>. If opening the - * logfile fails, -1 is returned and errno is set appropriately (by open(2)). + * Add a log handler to send messages to <b>filename</b> via <b>fd</b>. If + * opening the logfile failed, -1 is returned and errno is set appropriately + * (by open(2)). Takes ownership of fd. */ int -add_file_log(const log_severity_list_t *severity, const char *filename, - const int truncate_log) +add_file_log(const log_severity_list_t *severity, + const char *filename, + int fd) { - int fd; logfile_t *lf; - int open_flags = O_WRONLY|O_CREAT; - open_flags |= truncate_log ? O_TRUNC : O_APPEND; - - fd = tor_open_cloexec(filename, open_flags, 0640); if (fd<0) return -1; if (tor_fd_seekend(fd)<0) { @@ -1536,4 +1486,3 @@ truncate_logs(void) } } } - diff --git a/src/common/torlog.h b/src/lib/log/torlog.h index de389883c0..c24b638191 100644 --- a/src/common/torlog.h +++ b/src/lib/log/torlog.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001, Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,8 +12,10 @@ #ifndef TOR_TORLOG_H -#include "compat.h" -#include "testsupport.h" +#include <stdarg.h> +#include "lib/cc/torint.h" +#include "lib/cc/compat_compiler.h" +#include "lib/testsupport/testsupport.h" #ifdef HAVE_SYSLOG_H #include <syslog.h> @@ -143,8 +145,10 @@ void set_log_severity_config(int minSeverity, int maxSeverity, log_severity_list_t *severity_out); void add_stream_log(const log_severity_list_t *severity, const char *name, int fd); -int add_file_log(const log_severity_list_t *severity, const char *filename, - const int truncate); +int add_file_log(const log_severity_list_t *severity, + const char *filename, + int fd); + #ifdef HAVE_SYSLOG_H int add_syslog_log(const log_severity_list_t *severity, const char* syslog_identity_tag); @@ -175,8 +179,6 @@ void truncate_logs(void); void tor_log(int severity, log_domain_mask_t domain, const char *format, ...) CHECK_PRINTF(3,4); -void tor_log_err_sigsafe(const char *m, ...); -int tor_log_get_sigsafe_err_fds(const int **out); void tor_log_update_sigsafe_err_fds(void); struct smartlist_t; @@ -272,4 +274,3 @@ MOCK_DECL(STATIC void, logv, (int severity, log_domain_mask_t domain, # define TOR_TORLOG_H #endif /* !defined(TOR_TORLOG_H) */ - diff --git a/src/common/util_bug.c b/src/lib/log/util_bug.c index 126e843866..78af08f022 100644 --- a/src/common/util_bug.c +++ b/src/lib/log/util_bug.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,10 +8,17 @@ **/ #include "orconfig.h" -#include "util_bug.h" -#include "torlog.h" -#include "backtrace.h" -#include "container.h" +#include "lib/log/util_bug.h" +#include "lib/log/torlog.h" +#include "lib/err/backtrace.h" +#ifdef TOR_UNIT_TESTS +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_foreach.h" +#endif +#include "lib/malloc/util_malloc.h" +#include "lib/string/printf.h" + +#include <string.h> #ifdef __COVERITY__ int bug_macro_deadcode_dummy__ = 0; @@ -117,3 +124,28 @@ tor_bug_occurred_(const char *fname, unsigned int line, #endif } +#ifdef _WIN32 +/** Take a filename and return a pointer to its final element. This + * function is called on __FILE__ to fix a MSVC nit where __FILE__ + * contains the full path to the file. This is bad, because it + * confuses users to find the home directory of the person who + * compiled the binary in their warning messages. + */ +const char * +tor_fix_source_file(const char *fname) +{ + const char *cp1, *cp2, *r; + cp1 = strrchr(fname, '/'); + cp2 = strrchr(fname, '\\'); + if (cp1 && cp2) { + r = (cp1<cp2)?(cp2+1):(cp1+1); + } else if (cp1) { + r = cp1+1; + } else if (cp2) { + r = cp2+1; + } else { + r = fname; + } + return r; +} +#endif /* defined(_WIN32) */ diff --git a/src/common/util_bug.h b/src/lib/log/util_bug.h index be549fde07..a0753c807b 100644 --- a/src/common/util_bug.h +++ b/src/lib/log/util_bug.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -37,8 +37,9 @@ #define TOR_UTIL_BUG_H #include "orconfig.h" -#include "compat.h" -#include "testsupport.h" +#include "lib/cc/compat_compiler.h" +#include "lib/log/torlog.h" +#include "lib/testsupport/testsupport.h" /* Replace assert() with a variant that sends failures to the log before * calling assert() normally. @@ -191,6 +192,14 @@ void tor_bug_occurred_(const char *fname, unsigned int line, const char *func, const char *expr, int once); +#ifdef _WIN32 +#define SHORT_FILE__ (tor_fix_source_file(__FILE__)) +const char *tor_fix_source_file(const char *fname); +#else +#define SHORT_FILE__ (__FILE__) +#define tor_fix_source_file(s) (s) +#endif /* defined(_WIN32) */ + #ifdef TOR_UNIT_TESTS void tor_capture_bugs_(int n); void tor_end_capture_bugs_(void); @@ -199,4 +208,3 @@ void tor_set_failed_assertion_callback(void (*fn)(void)); #endif /* defined(TOR_UNIT_TESTS) */ #endif /* !defined(TOR_UTIL_BUG_H) */ - diff --git a/src/lib/log/win32err.c b/src/lib/log/win32err.c new file mode 100644 index 0000000000..4586c23c84 --- /dev/null +++ b/src/lib/log/win32err.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifdef _WIN32 +#include "orconfig.h" +#include "lib/log/win32err.h" +#include "lib/malloc/util_malloc.h" + +#include <tchar.h> +#include <windows.h> + +/** Return a newly allocated string describing the windows system error code + * <b>err</b>. Note that error codes are different from errno. Error codes + * come from GetLastError() when a winapi call fails. errno is set only when + * ANSI functions fail. Whee. */ +char * +format_win32_error(DWORD err) +{ + TCHAR *str = NULL; + char *result; + DWORD n; + + /* Somebody once decided that this interface was better than strerror(). */ + n = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err, + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), + (LPVOID)&str, + 0, NULL); + + if (str && n) { +#ifdef UNICODE + size_t len; + if (n > 128*1024) + len = (128 * 1024) * 2 + 1; /* This shouldn't be possible, but let's + * make sure. */ + else + len = n * 2 + 1; + result = tor_malloc(len); + wcstombs(result,str,len); + result[len-1] = '\0'; +#else /* !(defined(UNICODE)) */ + result = tor_strdup(str); +#endif /* defined(UNICODE) */ + } else { + result = tor_strdup("<unformattable error>"); + } + if (str) { + LocalFree(str); /* LocalFree != free() */ + } + return result; +} +#endif /* defined(_WIN32) */ diff --git a/src/lib/log/win32err.h b/src/lib/log/win32err.h new file mode 100644 index 0000000000..61d3af57dd --- /dev/null +++ b/src/lib/log/win32err.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_WIN32ERR_H +#define TOR_WIN32ERR_H + +#include "orconfig.h" + +/* Platform-specific helpers. */ +#ifdef _WIN32 +#include <windef.h> +char *format_win32_error(DWORD err); +#endif + +#endif diff --git a/src/lib/malloc/.may_include b/src/lib/malloc/.may_include new file mode 100644 index 0000000000..cc62bb1013 --- /dev/null +++ b/src/lib/malloc/.may_include @@ -0,0 +1,6 @@ +orconfig.h + +lib/cc/*.h +lib/err/*.h +lib/malloc/*.h +lib/testsupport/testsupport.h diff --git a/src/lib/malloc/include.am b/src/lib/malloc/include.am new file mode 100644 index 0000000000..50de9cb736 --- /dev/null +++ b/src/lib/malloc/include.am @@ -0,0 +1,21 @@ + +noinst_LIBRARIES += src/lib/libtor-malloc.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-malloc-testing.a +endif + +src_lib_libtor_malloc_a_SOURCES = \ + src/lib/malloc/util_malloc.c + +if USE_OPENBSD_MALLOC +src_lib_libtor_malloc_a_SOURCES += src/ext/OpenBSD_malloc_Linux.c +endif + +src_lib_libtor_malloc_testing_a_SOURCES = \ + $(src_lib_libtor_malloc_a_SOURCES) +src_lib_libtor_malloc_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_malloc_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/malloc/util_malloc.h diff --git a/src/lib/malloc/util_malloc.c b/src/lib/malloc/util_malloc.c new file mode 100644 index 0000000000..f3b0e50c70 --- /dev/null +++ b/src/lib/malloc/util_malloc.c @@ -0,0 +1,230 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file util_malloc.c + * \brief Wrappers for C malloc code, and replacements for items that + * may be missing. + **/ + +#include "orconfig.h" + +#include <stdlib.h> +#include <string.h> + +#include "lib/testsupport/testsupport.h" +#define UTIL_MALLOC_PRIVATE +#include "lib/malloc/util_malloc.h" +#include "lib/cc/torint.h" +#include "lib/err/torerr.h" + +#ifdef __clang_analyzer__ +#undef MALLOC_ZERO_WORKS +#endif + +/** Allocate a chunk of <b>size</b> bytes of memory, and return a pointer to + * result. On error, log and terminate the process. (Same as malloc(size), + * but never returns NULL.) + */ +void * +tor_malloc_(size_t size) +{ + void *result; + + raw_assert(size < SIZE_T_CEILING); + +#ifndef MALLOC_ZERO_WORKS + /* Some libc mallocs don't work when size==0. Override them. */ + if (size==0) { + size=1; + } +#endif /* !defined(MALLOC_ZERO_WORKS) */ + + result = raw_malloc(size); + + if (PREDICT_UNLIKELY(result == NULL)) { + /* LCOV_EXCL_START */ + /* If these functions die within a worker process, they won't call + * spawn_exit, but that's ok, since the parent will run out of memory soon + * anyway. */ + raw_assert_unreached_msg("Out of memory on malloc(). Dying."); + /* LCOV_EXCL_STOP */ + } + return result; +} + +/** Allocate a chunk of <b>size</b> bytes of memory, fill the memory with + * zero bytes, and return a pointer to the result. Log and terminate + * the process on error. (Same as calloc(size,1), but never returns NULL.) + */ +void * +tor_malloc_zero_(size_t size) +{ + /* You may ask yourself, "wouldn't it be smart to use calloc instead of + * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick + * we don't!" Indeed it does, but its optimizations are only a big win when + * we're allocating something very big (it knows if it just got the memory + * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero + * for big stuff, so we don't bother with calloc. */ + void *result = tor_malloc_(size); + memset(result, 0, size); + return result; +} + +/* The square root of SIZE_MAX + 1. If a is less than this, and b is less + * than this, then a*b is less than SIZE_MAX. (For example, if size_t is + * 32 bits, then SIZE_MAX is 0xffffffff and this value is 0x10000. If a and + * b are less than this, then their product is at most (65535*65535) == + * 0xfffe0001. */ +#define SQRT_SIZE_MAX_P1 (((size_t)1) << (sizeof(size_t)*4)) + +/** Return non-zero if and only if the product of the arguments is exact, + * and cannot overflow. */ +STATIC int +size_mul_check(const size_t x, const size_t y) +{ + /* This first check is equivalent to + (x < SQRT_SIZE_MAX_P1 && y < SQRT_SIZE_MAX_P1) + + Rationale: if either one of x or y is >= SQRT_SIZE_MAX_P1, then it + will have some bit set in its most significant half. + */ + return ((x|y) < SQRT_SIZE_MAX_P1 || + y == 0 || + x <= SIZE_MAX / y); +} + +/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill + * the memory with zero bytes, and return a pointer to the result. + * Log and terminate the process on error. (Same as + * calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.) + * The second argument (<b>size</b>) should preferably be non-zero + * and a compile-time constant. + */ +void * +tor_calloc_(size_t nmemb, size_t size) +{ + raw_assert(size_mul_check(nmemb, size)); + return tor_malloc_zero_((nmemb * size)); +} + +/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b> + * bytes long; return the new memory block. On error, log and + * terminate. (Like realloc(ptr,size), but never returns NULL.) + */ +void * +tor_realloc_(void *ptr, size_t size) +{ + void *result; + + raw_assert(size < SIZE_T_CEILING); + +#ifndef MALLOC_ZERO_WORKS + /* Some libc mallocs don't work when size==0. Override them. */ + if (size==0) { + size=1; + } +#endif /* !defined(MALLOC_ZERO_WORKS) */ + + result = raw_realloc(ptr, size); + + if (PREDICT_UNLIKELY(result == NULL)) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("Out of memory on realloc(). Dying."); + /* LCOV_EXCL_STOP */ + } + return result; +} + +/** + * Try to realloc <b>ptr</b> so that it takes up sz1 * sz2 bytes. Check for + * overflow. Unlike other allocation functions, return NULL on overflow. + */ +void * +tor_reallocarray_(void *ptr, size_t sz1, size_t sz2) +{ + /* XXXX we can make this return 0, but we would need to check all the + * reallocarray users. */ + raw_assert(size_mul_check(sz1, sz2)); + + return tor_realloc(ptr, (sz1 * sz2)); +} + +/** Return a newly allocated copy of the NUL-terminated string s. On + * error, log and terminate. (Like strdup(s), but never returns + * NULL.) + */ +char * +tor_strdup_(const char *s) +{ + char *duplicate; + raw_assert(s); + + duplicate = raw_strdup(s); + + if (PREDICT_UNLIKELY(duplicate == NULL)) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("Out of memory on strdup(). Dying."); + /* LCOV_EXCL_STOP */ + } + return duplicate; +} + +/** Allocate and return a new string containing the first <b>n</b> + * characters of <b>s</b>. If <b>s</b> is longer than <b>n</b> + * characters, only the first <b>n</b> are copied. The result is + * always NUL-terminated. (Like strndup(s,n), but never returns + * NULL.) + */ +char * +tor_strndup_(const char *s, size_t n) +{ + char *duplicate; + raw_assert(s); + raw_assert(n < SIZE_T_CEILING); + duplicate = tor_malloc_((n+1)); + /* Performance note: Ordinarily we prefer strlcpy to strncpy. But + * this function gets called a whole lot, and platform strncpy is + * much faster than strlcpy when strlen(s) is much longer than n. + */ + strncpy(duplicate, s, n); + duplicate[n]='\0'; + return duplicate; +} + +/** Allocate a chunk of <b>len</b> bytes, with the same contents as the + * <b>len</b> bytes starting at <b>mem</b>. */ +void * +tor_memdup_(const void *mem, size_t len) +{ + char *duplicate; + raw_assert(len < SIZE_T_CEILING); + raw_assert(mem); + duplicate = tor_malloc_(len); + memcpy(duplicate, mem, len); + return duplicate; +} + +/** As tor_memdup(), but add an extra 0 byte at the end of the resulting + * memory. */ +void * +tor_memdup_nulterm_(const void *mem, size_t len) +{ + char *duplicate; + raw_assert(len < SIZE_T_CEILING+1); + raw_assert(mem); + duplicate = tor_malloc_(len+1); + memcpy(duplicate, mem, len); + duplicate[len] = '\0'; + return duplicate; +} + +/** Helper for places that need to take a function pointer to the right + * spelling of "free()". */ +void +tor_free_(void *mem) +{ + tor_free(mem); +} diff --git a/src/lib/malloc/util_malloc.h b/src/lib/malloc/util_malloc.h new file mode 100644 index 0000000000..a1e9531176 --- /dev/null +++ b/src/lib/malloc/util_malloc.h @@ -0,0 +1,92 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file util_malloc.h + * \brief Headers for util_malloc.c + **/ + +#ifndef TOR_UTIL_MALLOC_H +#define TOR_UTIL_MALLOC_H + +#include <stddef.h> +#include <stdlib.h> +#include "lib/cc/compat_compiler.h" + +/* Memory management */ +void *tor_malloc_(size_t size) ATTR_MALLOC; +void *tor_malloc_zero_(size_t size) ATTR_MALLOC; +void *tor_calloc_(size_t nmemb, size_t size) ATTR_MALLOC; +void *tor_realloc_(void *ptr, size_t size); +void *tor_reallocarray_(void *ptr, size_t size1, size_t size2); +char *tor_strdup_(const char *s) ATTR_MALLOC; +char *tor_strndup_(const char *s, size_t n) + ATTR_MALLOC; +void *tor_memdup_(const void *mem, size_t len) + ATTR_MALLOC; +void *tor_memdup_nulterm_(const void *mem, size_t len) + ATTR_MALLOC; +void tor_free_(void *mem); + +/** Release memory allocated by tor_malloc, tor_realloc, tor_strdup, + * etc. Unlike the free() function, the tor_free() macro sets the + * pointer value to NULL after freeing it. + * + * This is a macro. If you need a function pointer to release memory from + * tor_malloc(), use tor_free_(). + * + * Note that this macro takes the address of the pointer it is going to + * free and clear. If that pointer is stored with a nonstandard + * alignment (eg because of a "packed" pragma) it is not correct to use + * tor_free(). + */ +#ifdef __GNUC__ +#define tor_free(p) STMT_BEGIN \ + typeof(&(p)) tor_free__tmpvar = &(p); \ + raw_free(*tor_free__tmpvar); \ + *tor_free__tmpvar=NULL; \ + STMT_END +#else +#define tor_free(p) STMT_BEGIN \ + raw_free(p); \ + (p)=NULL; \ + STMT_END +#endif + +#define tor_malloc(size) tor_malloc_(size) +#define tor_malloc_zero(size) tor_malloc_zero_(size) +#define tor_calloc(nmemb,size) tor_calloc_(nmemb, size) +#define tor_realloc(ptr, size) tor_realloc_(ptr, size) +#define tor_reallocarray(ptr, sz1, sz2) \ + tor_reallocarray_((ptr), (sz1), (sz2)) +#define tor_strdup(s) tor_strdup_(s) +#define tor_strndup(s, n) tor_strndup_(s, n) +#define tor_memdup(s, n) tor_memdup_(s, n) +#define tor_memdup_nulterm(s, n) tor_memdup_nulterm_(s, n) + +/* Aliases for the underlying system malloc/realloc/free. Only use + * them to indicate "I really want the underlying system function, I know + * what I'm doing." */ +#define raw_malloc malloc +#define raw_realloc realloc +#define raw_free free +#define raw_strdup strdup + +/* Helper macro: free a variable of type 'typename' using freefn, and + * set the variable to NULL. + */ +#define FREE_AND_NULL(typename, freefn, var) \ + do { \ + /* only evaluate (var) once. */ \ + typename **tmp__free__ptr ## freefn = &(var); \ + freefn(*tmp__free__ptr ## freefn); \ + (*tmp__free__ptr ## freefn) = NULL; \ + } while (0) + +#ifdef UTIL_MALLOC_PRIVATE +STATIC int size_mul_check(const size_t x, const size_t y); +#endif + +#endif /* !defined(TOR_UTIL_MALLOC_H) */ diff --git a/src/lib/math/.may_include b/src/lib/math/.may_include new file mode 100644 index 0000000000..1fd26864dc --- /dev/null +++ b/src/lib/math/.may_include @@ -0,0 +1,5 @@ +orconfig.h + +lib/cc/*.h +lib/log/*.h +lib/math/*.h diff --git a/src/lib/math/fp.c b/src/lib/math/fp.c new file mode 100644 index 0000000000..d5989db637 --- /dev/null +++ b/src/lib/math/fp.c @@ -0,0 +1,119 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file fp.c + * + * \brief Basic floating-point compatibility and convenience code. + **/ + +#include "orconfig.h" +#include "lib/math/fp.h" + +#include <math.h> + +/** + * Returns the natural logarithm of d base e. We defined this wrapper here so + * to avoid conflicts with old versions of tor_log(), which were named log(). + */ +double +tor_mathlog(double d) +{ + return log(d); +} + +/** Return the long integer closest to <b>d</b>. We define this wrapper + * here so that not all users of math.h need to use the right incantations + * to get the c99 functions. */ +long +tor_lround(double d) +{ +#if defined(HAVE_LROUND) + return lround(d); +#elif defined(HAVE_RINT) + return (long)rint(d); +#else + return (long)(d > 0 ? d + 0.5 : ceil(d - 0.5)); +#endif /* defined(HAVE_LROUND) || ... */ +} + +/** Return the 64-bit integer closest to d. We define this wrapper here so + * that not all users of math.h need to use the right incantations to get the + * c99 functions. */ +int64_t +tor_llround(double d) +{ +#if defined(HAVE_LLROUND) + return (int64_t)llround(d); +#elif defined(HAVE_RINT) + return (int64_t)rint(d); +#else + return (int64_t)(d > 0 ? d + 0.5 : ceil(d - 0.5)); +#endif /* defined(HAVE_LLROUND) || ... */ +} + +/** Cast a given double value to a int64_t. Return 0 if number is NaN. + * Returns either INT64_MIN or INT64_MAX if number is outside of the int64_t + * range. */ +int64_t +clamp_double_to_int64(double number) +{ + int exponent; + +#if defined(MINGW_ANY) && GCC_VERSION >= 409 +/* + Mingw's math.h uses gcc's __builtin_choose_expr() facility to declare + isnan, isfinite, and signbit. But as implemented in at least some + versions of gcc, __builtin_choose_expr() can generate type warnings + even from branches that are not taken. So, suppress those warnings. +*/ +#define PROBLEMATIC_FLOAT_CONVERSION_WARNING +DISABLE_GCC_WARNING(float-conversion) +#endif /* defined(MINGW_ANY) && GCC_VERSION >= 409 */ + +/* + With clang 4.0 we apparently run into "double promotion" warnings here, + since clang thinks we're promoting a double to a long double. + */ +#if defined(__clang__) +#if __has_warning("-Wdouble-promotion") +#define PROBLEMATIC_DOUBLE_PROMOTION_WARNING +DISABLE_GCC_WARNING(double-promotion) +#endif +#endif /* defined(__clang__) */ + + /* NaN is a special case that can't be used with the logic below. */ + if (isnan(number)) { + return 0; + } + + /* Time to validate if result can overflows a int64_t value. Fun with + * float! Find that exponent exp such that + * number == x * 2^exp + * for some x with abs(x) in [0.5, 1.0). Note that this implies that the + * magnitude of number is strictly less than 2^exp. + * + * If number is infinite, the call to frexp is legal but the contents of + * are exponent unspecified. */ + frexp(number, &exponent); + + /* If the magnitude of number is strictly less than 2^63, the truncated + * version of number is guaranteed to be representable. The only + * representable integer for which this is not the case is INT64_MIN, but + * it is covered by the logic below. */ + if (isfinite(number) && exponent <= 63) { + return (int64_t)number; + } + + /* Handle infinities and finite numbers with magnitude >= 2^63. */ + return signbit(number) ? INT64_MIN : INT64_MAX; + +#ifdef PROBLEMATIC_DOUBLE_PROMOTION_WARNING +ENABLE_GCC_WARNING(double-promotion) +#endif +#ifdef PROBLEMATIC_FLOAT_CONVERSION_WARNING +ENABLE_GCC_WARNING(float-conversion) +#endif +} diff --git a/src/lib/math/fp.h b/src/lib/math/fp.h new file mode 100644 index 0000000000..e27b8f8d80 --- /dev/null +++ b/src/lib/math/fp.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file fp.h + * + * \brief Header for fp.c + **/ + +#ifndef TOR_FP_H +#define TOR_FP_H + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +double tor_mathlog(double d) ATTR_CONST; +long tor_lround(double d) ATTR_CONST; +int64_t tor_llround(double d) ATTR_CONST; +int64_t clamp_double_to_int64(double number); + +#endif diff --git a/src/lib/math/include.am b/src/lib/math/include.am new file mode 100644 index 0000000000..b088b3f3cc --- /dev/null +++ b/src/lib/math/include.am @@ -0,0 +1,20 @@ + +noinst_LIBRARIES += src/lib/libtor-math.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-math-testing.a +endif + +src_lib_libtor_math_a_SOURCES = \ + src/lib/math/fp.c \ + src/lib/math/laplace.c + + +src_lib_libtor_math_testing_a_SOURCES = \ + $(src_lib_libtor_math_a_SOURCES) +src_lib_libtor_math_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_math_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/math/fp.h \ + src/lib/math/laplace.h diff --git a/src/lib/math/laplace.c b/src/lib/math/laplace.c new file mode 100644 index 0000000000..6b33b46902 --- /dev/null +++ b/src/lib/math/laplace.c @@ -0,0 +1,73 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file laplace.c + * + * \brief Implements a Laplace distribution, used for adding noise to things. + **/ + +#include "orconfig.h" +#include "lib/math/laplace.h" +#include "lib/math/fp.h" + +#include "lib/log/util_bug.h" + +#include <math.h> +#include <stdlib.h> + +/** Transform a random value <b>p</b> from the uniform distribution in + * [0.0, 1.0[ into a Laplace distributed value with location parameter + * <b>mu</b> and scale parameter <b>b</b>. Truncate the final result + * to be an integer in [INT64_MIN, INT64_MAX]. */ +int64_t +sample_laplace_distribution(double mu, double b, double p) +{ + double result; + tor_assert(p >= 0.0 && p < 1.0); + + /* This is the "inverse cumulative distribution function" from: + * http://en.wikipedia.org/wiki/Laplace_distribution */ + if (p <= 0.0) { + /* Avoid taking log(0.0) == -INFINITY, as some processors or compiler + * options can cause the program to trap. */ + return INT64_MIN; + } + + result = mu - b * (p > 0.5 ? 1.0 : -1.0) + * tor_mathlog(1.0 - 2.0 * fabs(p - 0.5)); + + return clamp_double_to_int64(result); +} + +/** Add random noise between INT64_MIN and INT64_MAX coming from a Laplace + * distribution with mu = 0 and b = <b>delta_f</b>/<b>epsilon</b> to + * <b>signal</b> based on the provided <b>random</b> value in [0.0, 1.0[. + * The epsilon value must be between ]0.0, 1.0]. delta_f must be greater + * than 0. */ +int64_t +add_laplace_noise(int64_t signal_, double random_, double delta_f, + double epsilon) +{ + int64_t noise; + + /* epsilon MUST be between ]0.0, 1.0] */ + tor_assert(epsilon > 0.0 && epsilon <= 1.0); + /* delta_f MUST be greater than 0. */ + tor_assert(delta_f > 0.0); + + /* Just add noise, no further signal */ + noise = sample_laplace_distribution(0.0, + delta_f / epsilon, + random_); + + /* Clip (signal + noise) to [INT64_MIN, INT64_MAX] */ + if (noise > 0 && INT64_MAX - noise < signal_) + return INT64_MAX; + else if (noise < 0 && INT64_MIN - noise > signal_) + return INT64_MIN; + else + return signal_ + noise; +} diff --git a/src/lib/math/laplace.h b/src/lib/math/laplace.h new file mode 100644 index 0000000000..62d698e369 --- /dev/null +++ b/src/lib/math/laplace.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file laplace.h + * + * \brief Header for laplace.c + **/ + +#ifndef TOR_LAPLACE_H +#define TOR_LAPLACE_H + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" + +int64_t sample_laplace_distribution(double mu, double b, double p); +int64_t add_laplace_noise(int64_t signal, double random, double delta_f, + double epsilon); + +#endif diff --git a/src/lib/memarea/.may_include b/src/lib/memarea/.may_include new file mode 100644 index 0000000000..814652a93c --- /dev/null +++ b/src/lib/memarea/.may_include @@ -0,0 +1,7 @@ +orconfig.h +lib/arch/*.h +lib/cc/*.h +lib/container/*.h +lib/log/*.h +lib/malloc/*.h +lib/memarea/*.h diff --git a/src/lib/memarea/include.am b/src/lib/memarea/include.am new file mode 100644 index 0000000000..94343dcead --- /dev/null +++ b/src/lib/memarea/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-memarea.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-memarea-testing.a +endif + +src_lib_libtor_memarea_a_SOURCES = \ + src/lib/memarea/memarea.c + +src_lib_libtor_memarea_testing_a_SOURCES = \ + $(src_lib_libtor_memarea_a_SOURCES) +src_lib_libtor_memarea_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_memarea_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/memarea/memarea.h diff --git a/src/common/memarea.c b/src/lib/memarea/memarea.c index 68c1625fe4..9d494ab2d4 100644 --- a/src/common/memarea.c +++ b/src/lib/memarea/memarea.c @@ -1,19 +1,25 @@ -/* Copyright (c) 2008-2017, The Tor Project, Inc. */ +/* Copyright (c) 2008-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -/** \file memarea.c +/** + * \file memarea.c + * * \brief Implementation for memarea_t, an allocator for allocating lots of * small objects that will be freed all at once. */ #include "orconfig.h" -#include <stddef.h> +#include "lib/memarea/memarea.h" + #include <stdlib.h> -#include "memarea.h" -#include "util.h" -#include "compat.h" -#include "torlog.h" -#include "container.h" +#include <string.h> + +#include "lib/arch/bytes.h" +#include "lib/cc/torint.h" +#include "lib/container/smartlist.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" #ifndef DISABLE_MEMORY_SENTINELS @@ -395,4 +401,3 @@ memarea_assert_ok(memarea_t *area) } #endif /* !defined(DISABLE_MEMORY_SENTINELS) */ - diff --git a/src/common/memarea.h b/src/lib/memarea/memarea.h index 5207e8a5bd..4978b54162 100644 --- a/src/common/memarea.h +++ b/src/lib/memarea/memarea.h @@ -1,10 +1,17 @@ -/* Copyright (c) 2008-2017, The Tor Project, Inc. */ +/* Copyright (c) 2008-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -/* Tor dependencies */ + +/** + * \file memarea.h + * + * \brief Header for memarea.c + **/ #ifndef TOR_MEMAREA_H #define TOR_MEMAREA_H +#include <stddef.h> + typedef struct memarea_t memarea_t; memarea_t *memarea_new(void); @@ -26,4 +33,3 @@ void memarea_get_stats(memarea_t *area, void memarea_assert_ok(memarea_t *area); #endif /* !defined(TOR_MEMAREA_H) */ - diff --git a/src/lib/meminfo/.may_include b/src/lib/meminfo/.may_include new file mode 100644 index 0000000000..9e4d25fd6a --- /dev/null +++ b/src/lib/meminfo/.may_include @@ -0,0 +1,8 @@ +orconfig.h + +lib/cc/*.h +lib/fs/*.h +lib/log/*.h +lib/malloc/*.h +lib/meminfo/*.h +lib/testsupport/*.h diff --git a/src/lib/meminfo/include.am b/src/lib/meminfo/include.am new file mode 100644 index 0000000000..d1fdde6313 --- /dev/null +++ b/src/lib/meminfo/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-meminfo.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-meminfo-testing.a +endif + +src_lib_libtor_meminfo_a_SOURCES = \ + src/lib/meminfo/meminfo.c + +src_lib_libtor_meminfo_testing_a_SOURCES = \ + $(src_lib_libtor_meminfo_a_SOURCES) +src_lib_libtor_meminfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_meminfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/meminfo/meminfo.h diff --git a/src/lib/meminfo/meminfo.c b/src/lib/meminfo/meminfo.c new file mode 100644 index 0000000000..b5a74ce624 --- /dev/null +++ b/src/lib/meminfo/meminfo.c @@ -0,0 +1,180 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file meminfo.c + * + * \brief Functions to query total memory, and access meta-information about + * the allocator. + **/ + +#include "lib/meminfo/meminfo.h" + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif +#include <string.h> + +DISABLE_GCC_WARNING(aggregate-return) +/** Call the platform malloc info function, and dump the results to the log at + * level <b>severity</b>. If no such function exists, do nothing. */ +void +tor_log_mallinfo(int severity) +{ +#ifdef HAVE_MALLINFO + struct mallinfo mi; + memset(&mi, 0, sizeof(mi)); + mi = mallinfo(); + tor_log(severity, LD_MM, + "mallinfo() said: arena=%d, ordblks=%d, smblks=%d, hblks=%d, " + "hblkhd=%d, usmblks=%d, fsmblks=%d, uordblks=%d, fordblks=%d, " + "keepcost=%d", + mi.arena, mi.ordblks, mi.smblks, mi.hblks, + mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks, + mi.keepcost); +#else /* !(defined(HAVE_MALLINFO)) */ + (void)severity; +#endif /* defined(HAVE_MALLINFO) */ +} +ENABLE_GCC_WARNING(aggregate-return) + +#if defined(HW_PHYSMEM64) +/* This appears to be an OpenBSD thing */ +#define INT64_HW_MEM HW_PHYSMEM64 +#elif defined(HW_MEMSIZE) +/* OSX defines this one */ +#define INT64_HW_MEM HW_MEMSIZE +#endif /* defined(HW_PHYSMEM64) || ... */ + +/** + * Helper: try to detect the total system memory, and return it. On failure, + * return 0. + */ +static uint64_t +get_total_system_memory_impl(void) +{ +#if defined(__linux__) + /* On linux, sysctl is deprecated. Because proc is so awesome that you + * shouldn't _want_ to write portable code, I guess? */ + unsigned long long result=0; + int fd = -1; + char *s = NULL; + const char *cp; + size_t file_size=0; + if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0))) + return 0; + s = read_file_to_str_until_eof(fd, 65536, &file_size); + if (!s) + goto err; + cp = strstr(s, "MemTotal:"); + if (!cp) + goto err; + /* Use the system sscanf so that space will match a wider number of space */ + if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1) + goto err; + + close(fd); + tor_free(s); + return result * 1024; + + /* LCOV_EXCL_START Can't reach this unless proc is broken. */ + err: + tor_free(s); + close(fd); + return 0; + /* LCOV_EXCL_STOP */ +#elif defined (_WIN32) + /* Windows has MEMORYSTATUSEX; pretty straightforward. */ + MEMORYSTATUSEX ms; + memset(&ms, 0, sizeof(ms)); + ms.dwLength = sizeof(ms); + if (! GlobalMemoryStatusEx(&ms)) + return 0; + + return ms.ullTotalPhys; + +#elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM) + /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better + * variant if we know about it. */ + uint64_t memsize = 0; + size_t len = sizeof(memsize); + int mib[2] = {CTL_HW, INT64_HW_MEM}; + if (sysctl(mib,2,&memsize,&len,NULL,0)) + return 0; + + return memsize; + +#elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM) + /* On some systems (like FreeBSD I hope) you can use a size_t with + * HW_PHYSMEM. */ + size_t memsize=0; + size_t len = sizeof(memsize); + int mib[2] = {CTL_HW, HW_USERMEM}; + if (sysctl(mib,2,&memsize,&len,NULL,0)) + return 0; + + return memsize; + +#else + /* I have no clue. */ + return 0; +#endif /* defined(__linux__) || ... */ +} + +/** + * Try to find out how much physical memory the system has. On success, + * return 0 and set *<b>mem_out</b> to that value. On failure, return -1. + */ +MOCK_IMPL(int, +get_total_system_memory, (size_t *mem_out)) +{ + static size_t mem_cached=0; + uint64_t m = get_total_system_memory_impl(); + if (0 == m) { + /* LCOV_EXCL_START -- can't make this happen without mocking. */ + /* We couldn't find our memory total */ + if (0 == mem_cached) { + /* We have no cached value either */ + *mem_out = 0; + return -1; + } + + *mem_out = mem_cached; + return 0; + /* LCOV_EXCL_STOP */ + } + +#if SIZE_MAX != UINT64_MAX + if (m > SIZE_MAX) { + /* I think this could happen if we're a 32-bit Tor running on a 64-bit + * system: we could have more system memory than would fit in a + * size_t. */ + m = SIZE_MAX; + } +#endif /* SIZE_MAX != UINT64_MAX */ + + *mem_out = mem_cached = (size_t) m; + + return 0; +} diff --git a/src/lib/meminfo/meminfo.h b/src/lib/meminfo/meminfo.h new file mode 100644 index 0000000000..b67d235559 --- /dev/null +++ b/src/lib/meminfo/meminfo.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file meminfo.h + * + * \brief Header for meminfo.c + **/ + +#ifndef TOR_MEMINFO_H +#define TOR_MEMINFO_H + +#include "lib/testsupport/testsupport.h" +#include <stddef.h> + +void tor_log_mallinfo(int severity); +MOCK_DECL(int, get_total_system_memory, (size_t *mem_out)); + +#endif diff --git a/src/lib/net/.may_include b/src/lib/net/.may_include new file mode 100644 index 0000000000..1458dad990 --- /dev/null +++ b/src/lib/net/.may_include @@ -0,0 +1,14 @@ +orconfig.h +siphash.h +ht.h + +lib/cc/*.h +lib/container/*.h +lib/ctime/*.h +lib/err/*.h +lib/lock/*.h +lib/log/*.h +lib/net/*.h +lib/string/*.h +lib/testsupport/*.h +lib/malloc/*.h
\ No newline at end of file diff --git a/src/common/address.c b/src/lib/net/address.c index a32df99107..f3eddca7bb 100644 --- a/src/common/address.c +++ b/src/lib/net/address.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -35,13 +35,22 @@ #include <iphlpapi.h> #endif /* defined(_WIN32) */ -#include "compat.h" -#include "util.h" -#include "util_format.h" -#include "address.h" -#include "torlog.h" -#include "container.h" -#include "sandbox.h" +#include "lib/net/address.h" +#include "lib/net/socket.h" +#include "lib/net/resolve.h" +#include "lib/container/smartlist.h" +#include "lib/ctime/di_ops.h" +#include "lib/log/torlog.h" +#include "lib/log/escape.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/ipv4.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/compat_string.h" +#include "lib/string/parse_int.h" +#include "lib/string/printf.h" +#include "lib/string/util_string.h" + +#include "siphash.h" #ifdef HAVE_SYS_TIME_H #include <sys/time.h> @@ -52,9 +61,6 @@ #ifdef HAVE_ERRNO_H #include <errno.h> #endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -83,7 +89,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <assert.h> /* tor_addr_is_null() and maybe other functions rely on AF_UNSPEC being 0 to * work correctly. Bail out here if we've found a platform where AF_UNSPEC @@ -272,7 +277,7 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) memset(&hints, 0, sizeof(hints)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; - err = sandbox_getaddrinfo(name, NULL, &hints, &res); + err = tor_getaddrinfo(name, NULL, &hints, &res); /* The check for 'res' here shouldn't be necessary, but it makes static * analysis tools happy. */ if (!err && res) { @@ -301,7 +306,7 @@ tor_addr_lookup,(const char *name, uint16_t family, tor_addr_t *addr)) &((struct sockaddr_in6*)best->ai_addr)->sin6_addr); result = 0; } - sandbox_freeaddrinfo(res); + tor_freeaddrinfo(res); return result; } return (err == EAI_AGAIN) ? 1 : -1; @@ -1474,14 +1479,7 @@ ip_adapter_addresses_to_smartlist(const IP_ADAPTER_ADDRESSES *addresses) STATIC smartlist_t * get_interface_addresses_win32(int severity, sa_family_t family) { - - /* Windows XP began to provide GetAdaptersAddresses. Windows 2000 had a - "GetAdaptersInfo", but that's deprecated; let's just try - GetAdaptersAddresses and fall back to connect+getsockname. - */ - HANDLE lib = load_windows_system_library(TEXT("iphlpapi.dll")); smartlist_t *result = NULL; - GetAdaptersAddresses_fn_t fn; ULONG size, res; IP_ADAPTER_ADDRESSES *addresses = NULL; @@ -1491,27 +1489,16 @@ get_interface_addresses_win32(int severity, sa_family_t family) GAA_FLAG_SKIP_MULTICAST | \ GAA_FLAG_SKIP_DNS_SERVER) - if (!lib) { - log_fn(severity, LD_NET, "Unable to load iphlpapi.dll"); - goto done; - } - - if (!(fn = (GetAdaptersAddresses_fn_t) - GetProcAddress(lib, "GetAdaptersAddresses"))) { - log_fn(severity, LD_NET, "Unable to obtain pointer to " - "GetAdaptersAddresses"); - goto done; - } - /* Guess how much space we need. */ size = 15*1024; addresses = tor_malloc(size); - res = fn(family, FLAGS, NULL, addresses, &size); + /* Exists in windows XP and later. */ + res = GetAdaptersAddresses(family, FLAGS, NULL, addresses, &size); if (res == ERROR_BUFFER_OVERFLOW) { /* we didn't guess that we needed enough space; try again */ tor_free(addresses); addresses = tor_malloc(size); - res = fn(AF_UNSPEC, FLAGS, NULL, addresses, &size); + res = GetAdaptersAddresses(AF_UNSPEC, FLAGS, NULL, addresses, &size); } if (res != NO_ERROR) { log_fn(severity, LD_NET, "GetAdaptersAddresses failed (result: %lu)", res); @@ -1521,8 +1508,6 @@ get_interface_addresses_win32(int severity, sa_family_t family) result = ip_adapter_addresses_to_smartlist(addresses); done: - if (lib) - FreeLibrary(lib); tor_free(addresses); return result; } @@ -2087,22 +2072,6 @@ parse_port_range(const char *port, uint16_t *port_min_out, return 0; } -/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), - * write it as a string into the <b>buf_len</b>-byte buffer in - * <b>buf</b>. Returns a non-negative integer on success. - * Returns -1 on failure. - */ -int -tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) -{ - uint32_t a = ntohl(in->s_addr); - return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", - (int)(uint8_t)((a>>24)&0xff), - (int)(uint8_t)((a>>16)&0xff), - (int)(uint8_t)((a>>8 )&0xff), - (int)(uint8_t)((a )&0xff)); -} - /** Given a host-order <b>addr</b>, call tor_inet_ntop() on it * and return a strdup of the resulting address. */ @@ -2171,3 +2140,117 @@ tor_addr_port_eq(const tor_addr_port_t *a, return tor_addr_eq(&a->addr, &b->addr) && a->port == b->port; } +/** Return true if <b>string</b> represents a valid IPv4 adddress in + * 'a.b.c.d' form. + */ +int +string_is_valid_ipv4_address(const char *string) +{ + struct in_addr addr; + + return (tor_inet_pton(AF_INET,string,&addr) == 1); +} + +/** Return true if <b>string</b> represents a valid IPv6 address in + * a form that inet_pton() can parse. + */ +int +string_is_valid_ipv6_address(const char *string) +{ + struct in6_addr addr; + + return (tor_inet_pton(AF_INET6,string,&addr) == 1); +} + +/** Return true iff <b>string</b> is a valid destination address, + * i.e. either a DNS hostname or IPv4/IPv6 address string. + */ +int +string_is_valid_dest(const char *string) +{ + char *tmp = NULL; + int retval; + size_t len; + + if (string == NULL) + return 0; + + len = strlen(string); + + if (len == 0) + return 0; + + if (string[0] == '[' && string[len - 1] == ']') + string = tmp = tor_strndup(string + 1, len - 2); + + retval = string_is_valid_ipv4_address(string) || + string_is_valid_ipv6_address(string) || + string_is_valid_nonrfc_hostname(string); + + tor_free(tmp); + + return retval; +} + +/** Return true iff <b>string</b> matches a pattern of DNS names + * that we allow Tor clients to connect to. + * + * Note: This allows certain technically invalid characters ('_') to cope + * with misconfigured zones that have been encountered in the wild. + */ +int +string_is_valid_nonrfc_hostname(const char *string) +{ + int result = 1; + int has_trailing_dot; + char *last_label; + smartlist_t *components; + + if (!string || strlen(string) == 0) + return 0; + + if (string_is_valid_ipv4_address(string)) + return 0; + + components = smartlist_new(); + + smartlist_split_string(components,string,".",0,0); + + if (BUG(smartlist_len(components) == 0)) + return 0; // LCOV_EXCL_LINE should be impossible given the earlier checks. + + /* Allow a single terminating '.' used rarely to indicate domains + * are FQDNs rather than relative. */ + last_label = (char *)smartlist_get(components, + smartlist_len(components) - 1); + has_trailing_dot = (last_label[0] == '\0'); + if (has_trailing_dot) { + smartlist_pop_last(components); + tor_free(last_label); + last_label = NULL; + } + + SMARTLIST_FOREACH_BEGIN(components, char *, c) { + if ((c[0] == '-') || (*c == '_')) { + result = 0; + break; + } + + do { + result = (TOR_ISALNUM(*c) || (*c == '-') || (*c == '_')); + c++; + } while (result && *c); + + if (result == 0) { + break; + } + } SMARTLIST_FOREACH_END(c); + + SMARTLIST_FOREACH_BEGIN(components, char *, c) { + tor_free(c); + } SMARTLIST_FOREACH_END(c); + + smartlist_free(components); + + return result; +} diff --git a/src/common/address.h b/src/lib/net/address.h index c9d9543dee..f8ea573c30 100644 --- a/src/common/address.h +++ b/src/lib/net/address.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,11 +11,22 @@ #ifndef TOR_ADDRESS_H #define TOR_ADDRESS_H -//#include <sys/sockio.h> #include "orconfig.h" -#include "torint.h" -#include "compat.h" -#include "container.h" +#include "lib/cc/torint.h" +#include "lib/log/util_bug.h" +#include "lib/net/ipv6.h" +#include "lib/net/nettypes.h" + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif + +#include <stddef.h> +#include <stdlib.h> #ifdef ADDRESS_PRIVATE @@ -73,6 +84,9 @@ typedef struct tor_addr_port_t #define TOR_ADDR_NULL {AF_UNSPEC, {0}} +/* XXXX To do: extract all of the functions here that can possibly invoke + * XXXX resolver, and make sure they have distinctive names. */ + static inline const struct in6_addr *tor_addr_to_in6(const tor_addr_t *a); static inline const struct in6_addr *tor_addr_to_in6_assert( const tor_addr_t *a); @@ -206,10 +220,11 @@ const char * fmt_addr32(uint32_t addr); MOCK_DECL(int,get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr)); -void interface_address6_list_free_(smartlist_t * addrs);// XXXX +struct smartlist_t; +void interface_address6_list_free_(struct smartlist_t * addrs);// XXXX #define interface_address6_list_free(addrs) \ - FREE_AND_NULL(smartlist_t, interface_address6_list_free_, (addrs)) -MOCK_DECL(smartlist_t *,get_interface_address6_list,(int severity, + FREE_AND_NULL(struct smartlist_t, interface_address6_list_free_, (addrs)) +MOCK_DECL(struct smartlist_t *,get_interface_address6_list,(int severity, sa_family_t family, int include_internal)); @@ -320,9 +335,6 @@ int addr_port_lookup(int severity, const char *addrport, char **address, int parse_port_range(const char *port, uint16_t *port_min_out, uint16_t *port_max_out); int addr_mask_get_bits(uint32_t mask); -/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/ -#define INET_NTOA_BUF_LEN 16 -int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); char *tor_dup_ip(uint32_t addr) ATTR_MALLOC; MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr)); #define interface_address_list_free(lst)\ @@ -335,7 +347,7 @@ MOCK_DECL(int,get_interface_address,(int severity, uint32_t *addr)); * Returns NULL on failure. * Use free_interface_address_list to free the returned list. */ -static inline smartlist_t * +static inline struct smartlist_t * get_interface_address_list(int severity, int include_internal) { return get_interface_address6_list(severity, AF_INET, include_internal); @@ -345,35 +357,39 @@ tor_addr_port_t *tor_addr_port_new(const tor_addr_t *addr, uint16_t port); int tor_addr_port_eq(const tor_addr_port_t *a, const tor_addr_port_t *b); +int string_is_valid_dest(const char *string); +int string_is_valid_nonrfc_hostname(const char *string); +int string_is_valid_ipv4_address(const char *string); +int string_is_valid_ipv6_address(const char *string); + #ifdef ADDRESS_PRIVATE -MOCK_DECL(smartlist_t *,get_interface_addresses_raw,(int severity, +MOCK_DECL(struct smartlist_t *,get_interface_addresses_raw,(int severity, sa_family_t family)); MOCK_DECL(int,get_interface_address6_via_udp_socket_hack,(int severity, sa_family_t family, tor_addr_t *addr)); #ifdef HAVE_IFADDRS_TO_SMARTLIST -STATIC smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa, +STATIC struct smartlist_t *ifaddrs_to_smartlist(const struct ifaddrs *ifa, sa_family_t family); -STATIC smartlist_t *get_interface_addresses_ifaddrs(int severity, +STATIC struct smartlist_t *get_interface_addresses_ifaddrs(int severity, sa_family_t family); #endif /* defined(HAVE_IFADDRS_TO_SMARTLIST) */ #ifdef HAVE_IP_ADAPTER_TO_SMARTLIST -STATIC smartlist_t *ip_adapter_addresses_to_smartlist( +STATIC struct smartlist_t *ip_adapter_addresses_to_smartlist( const IP_ADAPTER_ADDRESSES *addresses); -STATIC smartlist_t *get_interface_addresses_win32(int severity, +STATIC struct smartlist_t *get_interface_addresses_win32(int severity, sa_family_t family); #endif /* defined(HAVE_IP_ADAPTER_TO_SMARTLIST) */ #ifdef HAVE_IFCONF_TO_SMARTLIST -STATIC smartlist_t *ifreq_to_smartlist(char *ifr, +STATIC struct smartlist_t *ifreq_to_smartlist(char *ifr, size_t buflen); -STATIC smartlist_t *get_interface_addresses_ioctl(int severity, +STATIC struct smartlist_t *get_interface_addresses_ioctl(int severity, sa_family_t family); #endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */ #endif /* defined(ADDRESS_PRIVATE) */ #endif /* !defined(TOR_ADDRESS_H) */ - diff --git a/src/common/compat_threads.c b/src/lib/net/alertsock.c index 3171c4b2f2..340f9513fb 100644 --- a/src/common/compat_threads.c +++ b/src/lib/net/alertsock.c @@ -1,23 +1,23 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file compat_threads.c + * \file alertsock.c * - * \brief Cross-platform threading and inter-thread communication logic. - * (Platform-specific parts are written in the other compat_*threads - * modules.) - */ + * \brief Use a socket to alert the main thread from a worker thread. + * + * Because our main loop spends all of its time in select, epoll, kqueue, or + * etc, we need a way to wake up the main loop from another thread. This code + * tries to provide the fastest reasonable way to do that, depending on our + * platform. + **/ #include "orconfig.h" -#include <stdlib.h> -#include "compat.h" -#include "compat_threads.h" - -#include "util.h" -#include "torlog.h" +#include "lib/net/alertsock.h" +#include "lib/net/socket.h" +#include "lib/log/util_bug.h" #ifdef HAVE_SYS_EVENTFD_H #include <sys/eventfd.h> @@ -28,70 +28,12 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif - -/** Return a newly allocated, ready-for-use mutex. */ -tor_mutex_t * -tor_mutex_new(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init(m); - return m; -} -/** Return a newly allocated, ready-for-use mutex. This one might be - * non-recursive, if that's faster. */ -tor_mutex_t * -tor_mutex_new_nonrecursive(void) -{ - tor_mutex_t *m = tor_malloc_zero(sizeof(tor_mutex_t)); - tor_mutex_init_nonrecursive(m); - return m; -} -/** Release all storage and system resources held by <b>m</b>. */ -void -tor_mutex_free_(tor_mutex_t *m) -{ - if (!m) - return; - tor_mutex_uninit(m); - tor_free(m); -} - -/** Allocate and return a new condition variable. */ -tor_cond_t * -tor_cond_new(void) -{ - tor_cond_t *cond = tor_malloc(sizeof(tor_cond_t)); - if (BUG(tor_cond_init(cond)<0)) - tor_free(cond); // LCOV_EXCL_LINE - return cond; -} - -/** Free all storage held in <b>c</b>. */ -void -tor_cond_free_(tor_cond_t *c) -{ - if (!c) - return; - tor_cond_uninit(c); - tor_free(c); -} - -/** Identity of the "main" thread */ -static unsigned long main_thread_id = -1; - -/** Start considering the current thread to be the 'main thread'. This has - * no effect on anything besides in_main_thread(). */ -void -set_main_thread(void) -{ - main_thread_id = tor_get_thread_id(); -} -/** Return true iff called from the main thread. */ -int -in_main_thread(void) -{ - return main_thread_id == tor_get_thread_id(); -} +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#endif #if defined(HAVE_EVENTFD) || defined(HAVE_PIPE) /* As write(), but retry on EINTR, and return the negative error code on @@ -351,57 +293,3 @@ alert_sockets_close(alert_sockets_t *socks) } socks->read_fd = socks->write_fd = -1; } - -#ifndef HAVE_STDATOMIC_H -/** Initialize a new atomic counter with the value 0 */ -void -atomic_counter_init(atomic_counter_t *counter) -{ - memset(counter, 0, sizeof(*counter)); - tor_mutex_init_nonrecursive(&counter->mutex); -} -/** Clean up all resources held by an atomic counter. */ -void -atomic_counter_destroy(atomic_counter_t *counter) -{ - tor_mutex_uninit(&counter->mutex); - memset(counter, 0, sizeof(*counter)); -} -/** Add a value to an atomic counter. */ -void -atomic_counter_add(atomic_counter_t *counter, size_t add) -{ - tor_mutex_acquire(&counter->mutex); - counter->val += add; - tor_mutex_release(&counter->mutex); -} -/** Subtract a value from an atomic counter. */ -void -atomic_counter_sub(atomic_counter_t *counter, size_t sub) -{ - // this relies on unsigned overflow, but that's fine. - atomic_counter_add(counter, -sub); -} -/** Return the current value of an atomic counter */ -size_t -atomic_counter_get(atomic_counter_t *counter) -{ - size_t val; - tor_mutex_acquire(&counter->mutex); - val = counter->val; - tor_mutex_release(&counter->mutex); - return val; -} -/** Replace the value of an atomic counter; return the old one. */ -size_t -atomic_counter_exchange(atomic_counter_t *counter, size_t newval) -{ - size_t oldval; - tor_mutex_acquire(&counter->mutex); - oldval = counter->val; - counter->val = newval; - tor_mutex_release(&counter->mutex); - return oldval; -} -#endif /* !defined(HAVE_STDATOMIC_H) */ - diff --git a/src/lib/net/alertsock.h b/src/lib/net/alertsock.h new file mode 100644 index 0000000000..5dfe53a2a0 --- /dev/null +++ b/src/lib/net/alertsock.h @@ -0,0 +1,45 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file alertsock.h + * + * \brief Header for alertsock.c + **/ + +#ifndef TOR_ALERTSOCK_H +#define TOR_ALERTSOCK_H + +#include "orconfig.h" +#include "lib/net/nettypes.h" +#include "lib/cc/torint.h" + +/** Helper type used to manage waking up the main thread while it's in + * the libevent main loop. Used by the work queue code. */ +typedef struct alert_sockets_t { + /* XXXX This structure needs a better name. */ + /** Socket that the main thread should listen for EV_READ events on. + * Note that this socket may be a regular fd on a non-Windows platform. + */ + tor_socket_t read_fd; + /** Socket to use when alerting the main thread. */ + tor_socket_t write_fd; + /** Function to alert the main thread */ + int (*alert_fn)(tor_socket_t write_fd); + /** Function to make the main thread no longer alerted. */ + int (*drain_fn)(tor_socket_t read_fd); +} alert_sockets_t; + +/* Flags to disable one or more alert_sockets backends. */ +#define ASOCKS_NOEVENTFD2 (1u<<0) +#define ASOCKS_NOEVENTFD (1u<<1) +#define ASOCKS_NOPIPE2 (1u<<2) +#define ASOCKS_NOPIPE (1u<<3) +#define ASOCKS_NOSOCKETPAIR (1u<<4) + +int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags); +void alert_sockets_close(alert_sockets_t *socks); + +#endif diff --git a/src/lib/net/buffers_net.c b/src/lib/net/buffers_net.c new file mode 100644 index 0000000000..edc9954f22 --- /dev/null +++ b/src/lib/net/buffers_net.c @@ -0,0 +1,197 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define BUFFERS_PRIVATE +#include "lib/net/buffers_net.h" +#include "lib/container/buffers.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/net/nettypes.h" + +#ifdef _WIN32 +#include <winsock2.h> +#endif + +#include <stdlib.h> + +#ifdef PARANOIA +/** Helper: If PARANOIA is defined, assert that the buffer in local variable + * <b>buf</b> is well-formed. */ +#define check() STMT_BEGIN buf_assert_ok(buf); STMT_END +#else +#define check() STMT_NIL +#endif /* defined(PARANOIA) */ + +/** Read up to <b>at_most</b> bytes from the socket <b>fd</b> into + * <b>chunk</b> (which must be on <b>buf</b>). If we get an EOF, set + * *<b>reached_eof</b> to 1. Return -1 on error, 0 on eof or blocking, + * and the number of bytes read otherwise. */ +static inline int +read_to_chunk(buf_t *buf, chunk_t *chunk, tor_socket_t fd, size_t at_most, + int *reached_eof, int *socket_error) +{ + ssize_t read_result; + if (at_most > CHUNK_REMAINING_CAPACITY(chunk)) + at_most = CHUNK_REMAINING_CAPACITY(chunk); + read_result = tor_socket_recv(fd, CHUNK_WRITE_PTR(chunk), at_most, 0); + + if (read_result < 0) { + int e = tor_socket_errno(fd); + if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ +#ifdef _WIN32 + if (e == WSAENOBUFS) + log_warn(LD_NET,"recv() failed: WSAENOBUFS. Not enough ram?"); +#endif + *socket_error = e; + return -1; + } + return 0; /* would block. */ + } else if (read_result == 0) { + log_debug(LD_NET,"Encountered eof on fd %d", (int)fd); + *reached_eof = 1; + return 0; + } else { /* actually got bytes. */ + buf->datalen += read_result; + chunk->datalen += read_result; + log_debug(LD_NET,"Read %ld bytes. %d on inbuf.", (long)read_result, + (int)buf->datalen); + tor_assert(read_result < INT_MAX); + return (int)read_result; + } +} + +/** Read from socket <b>s</b>, writing onto end of <b>buf</b>. Read at most + * <b>at_most</b> bytes, growing the buffer as necessary. If recv() returns 0 + * (because of EOF), set *<b>reached_eof</b> to 1 and return 0. Return -1 on + * error; else return the number of bytes read. + */ +/* XXXX indicate "read blocked" somehow? */ +int +buf_read_from_socket(buf_t *buf, tor_socket_t s, size_t at_most, + int *reached_eof, + int *socket_error) +{ + /* XXXX It's stupid to overload the return values for these functions: + * "error status" and "number of bytes read" are not mutually exclusive. + */ + int r = 0; + size_t total_read = 0; + + check(); + tor_assert(reached_eof); + tor_assert(SOCKET_OK(s)); + + if (BUG(buf->datalen >= INT_MAX)) + return -1; + if (BUG(buf->datalen >= INT_MAX - at_most)) + return -1; + + while (at_most > total_read) { + size_t readlen = at_most - total_read; + chunk_t *chunk; + if (!buf->tail || CHUNK_REMAINING_CAPACITY(buf->tail) < MIN_READ_LEN) { + chunk = buf_add_chunk_with_capacity(buf, at_most, 1); + if (readlen > chunk->memlen) + readlen = chunk->memlen; + } else { + size_t cap = CHUNK_REMAINING_CAPACITY(buf->tail); + chunk = buf->tail; + if (cap < readlen) + readlen = cap; + } + + r = read_to_chunk(buf, chunk, s, readlen, reached_eof, socket_error); + check(); + if (r < 0) + return r; /* Error */ + tor_assert(total_read+r < INT_MAX); + total_read += r; + if ((size_t)r < readlen) { /* eof, block, or no more to read. */ + break; + } + } + return (int)total_read; +} + +/** Helper for buf_flush_to_socket(): try to write <b>sz</b> bytes from chunk + * <b>chunk</b> of buffer <b>buf</b> onto socket <b>s</b>. On success, deduct + * the bytes written from *<b>buf_flushlen</b>. Return the number of bytes + * written on success, 0 on blocking, -1 on failure. + */ +static inline int +flush_chunk(tor_socket_t s, buf_t *buf, chunk_t *chunk, size_t sz, + size_t *buf_flushlen) +{ + ssize_t write_result; + + if (sz > chunk->datalen) + sz = chunk->datalen; + write_result = tor_socket_send(s, chunk->data, sz, 0); + + if (write_result < 0) { + int e = tor_socket_errno(s); + if (!ERRNO_IS_EAGAIN(e)) { /* it's a real error */ +#ifdef _WIN32 + if (e == WSAENOBUFS) + log_warn(LD_NET,"write() failed: WSAENOBUFS. Not enough ram?"); +#endif + return -1; + } + log_debug(LD_NET,"write() would block, returning."); + return 0; + } else { + *buf_flushlen -= write_result; + buf_drain(buf, write_result); + tor_assert(write_result < INT_MAX); + return (int)write_result; + } +} + +/** Write data from <b>buf</b> to the socket <b>s</b>. Write at most + * <b>sz</b> bytes, decrement *<b>buf_flushlen</b> by + * the number of bytes actually written, and remove the written bytes + * from the buffer. Return the number of bytes written on success, + * -1 on failure. Return 0 if write() would block. + */ +int +buf_flush_to_socket(buf_t *buf, tor_socket_t s, size_t sz, + size_t *buf_flushlen) +{ + /* XXXX It's stupid to overload the return values for these functions: + * "error status" and "number of bytes flushed" are not mutually exclusive. + */ + int r; + size_t flushed = 0; + tor_assert(buf_flushlen); + tor_assert(SOCKET_OK(s)); + if (BUG(*buf_flushlen > buf->datalen)) { + *buf_flushlen = buf->datalen; + } + if (BUG(sz > *buf_flushlen)) { + sz = *buf_flushlen; + } + + check(); + while (sz) { + size_t flushlen0; + tor_assert(buf->head); + if (buf->head->datalen >= sz) + flushlen0 = sz; + else + flushlen0 = buf->head->datalen; + + r = flush_chunk(s, buf, buf->head, flushlen0, buf_flushlen); + check(); + if (r < 0) + return r; + flushed += r; + sz -= r; + if (r == 0 || (size_t)r < flushlen0) /* can't flush any more now. */ + break; + } + tor_assert(flushed < INT_MAX); + return (int)flushed; +} diff --git a/src/lib/net/buffers_net.h b/src/lib/net/buffers_net.h new file mode 100644 index 0000000000..417f6f9413 --- /dev/null +++ b/src/lib/net/buffers_net.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2001 Matej Pfajfar. + * Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file buffers_net.h + * + * \brief Header file for buffers_net.c. + **/ + +#ifndef TOR_BUFFERS_NET_H +#define TOR_BUFFERS_NET_H + +#include <stddef.h> +#include "lib/net/socket.h" + +struct buf_t; +int buf_read_from_socket(struct buf_t *buf, tor_socket_t s, size_t at_most, + int *reached_eof, + int *socket_error); + +int buf_flush_to_socket(struct buf_t *buf, tor_socket_t s, size_t sz, + size_t *buf_flushlen); + +#endif /* !defined(TOR_BUFFERS_H) */ diff --git a/src/lib/net/gethostname.c b/src/lib/net/gethostname.c new file mode 100644 index 0000000000..b6cc9b8e5f --- /dev/null +++ b/src/lib/net/gethostname.c @@ -0,0 +1,25 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/net/gethostname.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#endif + +/** Get name of current host and write it to <b>name</b> array, whose + * length is specified by <b>namelen</b> argument. Return 0 upon + * successful completion; otherwise return return -1. (Currently, + * this function is merely a mockable wrapper for POSIX gethostname().) + */ +MOCK_IMPL(int, +tor_gethostname,(char *name, size_t namelen)) +{ + return gethostname(name,namelen); +} diff --git a/src/lib/net/gethostname.h b/src/lib/net/gethostname.h new file mode 100644 index 0000000000..d83c5fe096 --- /dev/null +++ b/src/lib/net/gethostname.h @@ -0,0 +1,14 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GETHOSTNAME_H +#define TOR_GETHOSTNAME_H + +#include "lib/testsupport/testsupport.h" +#include <stddef.h> + +MOCK_DECL(int,tor_gethostname,(char *name, size_t namelen)); + +#endif diff --git a/src/lib/net/include.am b/src/lib/net/include.am new file mode 100644 index 0000000000..6fda173614 --- /dev/null +++ b/src/lib/net/include.am @@ -0,0 +1,33 @@ + +noinst_LIBRARIES += src/lib/libtor-net.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-net-testing.a +endif + +src_lib_libtor_net_a_SOURCES = \ + src/lib/net/address.c \ + src/lib/net/alertsock.c \ + src/lib/net/buffers_net.c \ + src/lib/net/gethostname.c \ + src/lib/net/ipv4.c \ + src/lib/net/ipv6.c \ + src/lib/net/resolve.c \ + src/lib/net/socket.c + +src_lib_libtor_net_testing_a_SOURCES = \ + $(src_lib_libtor_net_a_SOURCES) +src_lib_libtor_net_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_net_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/net/address.h \ + src/lib/net/alertsock.h \ + src/lib/net/buffers_net.h \ + src/lib/net/gethostname.h \ + src/lib/net/ipv4.h \ + src/lib/net/ipv6.h \ + src/lib/net/nettypes.h \ + src/lib/net/resolve.h \ + src/lib/net/socket.h \ + src/lib/net/socks5_status.h diff --git a/src/lib/net/ipv4.c b/src/lib/net/ipv4.c new file mode 100644 index 0000000000..18e69761e2 --- /dev/null +++ b/src/lib/net/ipv4.c @@ -0,0 +1,52 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/net/ipv4.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#endif + +/** Set *addr to the IP address (in dotted-quad notation) stored in *str. + * Return 1 on success, 0 if *str is badly formatted. + * (Like inet_aton(str,addr), but works on Windows and Solaris.) + */ +int +tor_inet_aton(const char *str, struct in_addr* addr) +{ + unsigned a,b,c,d; + char more; + if (tor_sscanf(str, "%3u.%3u.%3u.%3u%c", &a,&b,&c,&d,&more) != 4) + return 0; + if (a > 255) return 0; + if (b > 255) return 0; + if (c > 255) return 0; + if (d > 255) return 0; + addr->s_addr = htonl((a<<24) | (b<<16) | (c<<8) | d); + return 1; +} + +/** Given an IPv4 in_addr struct *<b>in</b> (in network order, as usual), + * write it as a string into the <b>buf_len</b>-byte buffer in + * <b>buf</b>. Returns a non-negative integer on success. + * Returns -1 on failure. + */ +int +tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len) +{ + uint32_t a = ntohl(in->s_addr); + return tor_snprintf(buf, buf_len, "%d.%d.%d.%d", + (int)(uint8_t)((a>>24)&0xff), + (int)(uint8_t)((a>>16)&0xff), + (int)(uint8_t)((a>>8 )&0xff), + (int)(uint8_t)((a )&0xff)); +} diff --git a/src/lib/net/ipv4.h b/src/lib/net/ipv4.h new file mode 100644 index 0000000000..1ccc729970 --- /dev/null +++ b/src/lib/net/ipv4.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_IPV4_H +#define TOR_IPV4_H + +#include <stddef.h> + +struct in_addr; +int tor_inet_aton(const char *str, struct in_addr *addr); +/** Length of a buffer to allocate to hold the results of tor_inet_ntoa.*/ +#define INET_NTOA_BUF_LEN 16 +int tor_inet_ntoa(const struct in_addr *in, char *buf, size_t buf_len); + +#endif diff --git a/src/lib/net/ipv6.c b/src/lib/net/ipv6.c new file mode 100644 index 0000000000..35d7ddb901 --- /dev/null +++ b/src/lib/net/ipv6.c @@ -0,0 +1,221 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/net/ipv6.h" +#include "lib/net/ipv4.h" +#include "lib/string/util_string.h" +#include "lib/string/compat_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/string/printf.h" +#include "lib/string/scanf.h" +#include "lib/log/util_bug.h" + +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#include <stdlib.h> +#include <string.h> + +/** Given <b>af</b>==AF_INET and <b>src</b> a struct in_addr, or + * <b>af</b>==AF_INET6 and <b>src</b> a struct in6_addr, try to format the + * address and store it in the <b>len</b>-byte buffer <b>dst</b>. Returns + * <b>dst</b> on success, NULL on failure. + * + * (Like inet_ntop(af,src,dst,len), but works on platforms that don't have it: + * Tor sometimes needs to format ipv6 addresses even on platforms without ipv6 + * support.) */ +const char * +tor_inet_ntop(int af, const void *src, char *dst, size_t len) +{ + if (af == AF_INET) { + if (tor_inet_ntoa(src, dst, len) < 0) + return NULL; + else + return dst; + } else if (af == AF_INET6) { + const struct in6_addr *addr = src; + char buf[64], *cp; + int longestGapLen = 0, longestGapPos = -1, i, + curGapPos = -1, curGapLen = 0; + uint16_t words[8]; + for (i = 0; i < 8; ++i) { + words[i] = (((uint16_t)addr->s6_addr[2*i])<<8) + addr->s6_addr[2*i+1]; + } + if (words[0] == 0 && words[1] == 0 && words[2] == 0 && words[3] == 0 && + words[4] == 0 && ((words[5] == 0 && words[6] && words[7]) || + (words[5] == 0xffff))) { + /* This is an IPv4 address. */ + if (words[5] == 0) { + tor_snprintf(buf, sizeof(buf), "::%d.%d.%d.%d", + addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } else { + tor_snprintf(buf, sizeof(buf), "::%x:%d.%d.%d.%d", words[5], + addr->s6_addr[12], addr->s6_addr[13], + addr->s6_addr[14], addr->s6_addr[15]); + } + if ((strlen(buf) + 1) > len) /* +1 for \0 */ + return NULL; + strlcpy(dst, buf, len); + return dst; + } + i = 0; + while (i < 8) { + if (words[i] == 0) { + curGapPos = i++; + curGapLen = 1; + while (i<8 && words[i] == 0) { + ++i; ++curGapLen; + } + if (curGapLen > longestGapLen) { + longestGapPos = curGapPos; + longestGapLen = curGapLen; + } + } else { + ++i; + } + } + if (longestGapLen<=1) + longestGapPos = -1; + + cp = buf; + for (i = 0; i < 8; ++i) { + if (words[i] == 0 && longestGapPos == i) { + if (i == 0) + *cp++ = ':'; + *cp++ = ':'; + while (i < 8 && words[i] == 0) + ++i; + --i; /* to compensate for loop increment. */ + } else { + tor_snprintf(cp, sizeof(buf)-(cp-buf), "%x", (unsigned)words[i]); + cp += strlen(cp); + if (i != 7) + *cp++ = ':'; + } + } + *cp = '\0'; + if ((strlen(buf) + 1) > len) /* +1 for \0 */ + return NULL; + strlcpy(dst, buf, len); + return dst; + } else { + return NULL; + } +} + +/** Given <b>af</b>==AF_INET or <b>af</b>==AF_INET6, and a string <b>src</b> + * encoding an IPv4 address or IPv6 address correspondingly, try to parse the + * address and store the result in <b>dst</b> (which must have space for a + * struct in_addr or a struct in6_addr, as appropriate). Return 1 on success, + * 0 on a bad parse, and -1 on a bad <b>af</b>. + * + * (Like inet_pton(af,src,dst) but works on platforms that don't have it: Tor + * sometimes needs to format ipv6 addresses even on platforms without ipv6 + * support.) */ +int +tor_inet_pton(int af, const char *src, void *dst) +{ + if (af == AF_INET) { + return tor_inet_aton(src, dst); + } else if (af == AF_INET6) { + struct in6_addr *out = dst; + uint16_t words[8]; + int gapPos = -1, i, setWords=0; + const char *dot = strchr(src, '.'); + const char *eow; /* end of words. */ + memset(words, 0xf8, sizeof(words)); + if (dot == src) + return 0; + else if (!dot) + eow = src+strlen(src); + else { + unsigned byte1,byte2,byte3,byte4; + char more; + for (eow = dot-1; eow > src && TOR_ISDIGIT(*eow); --eow) + ; + if (*eow != ':') + return 0; + ++eow; + + /* We use "scanf" because some platform inet_aton()s are too lax + * about IPv4 addresses of the form "1.2.3" */ + if (tor_sscanf(eow, "%3u.%3u.%3u.%3u%c", + &byte1,&byte2,&byte3,&byte4,&more) != 4) + return 0; + + if (byte1 > 255 || byte2 > 255 || byte3 > 255 || byte4 > 255) + return 0; + + words[6] = (byte1<<8) | byte2; + words[7] = (byte3<<8) | byte4; + setWords += 2; + } + + i = 0; + while (src < eow) { + if (i > 7) + return 0; + if (TOR_ISXDIGIT(*src)) { + char *next; + ssize_t len; + long r = strtol(src, &next, 16); + if (next == NULL || next == src) { + /* The 'next == src' error case can happen on versions of openbsd + * which treat "0xfoo" as an error, rather than as "0" followed by + * "xfoo". */ + return 0; + } + + len = *next == '\0' ? eow - src : next - src; + if (len > 4) + return 0; + if (len > 1 && !TOR_ISXDIGIT(src[1])) + return 0; /* 0x is not valid */ + + tor_assert(r >= 0); + tor_assert(r < 65536); + words[i++] = (uint16_t)r; + setWords++; + src = next; + if (*src != ':' && src != eow) + return 0; + ++src; + } else if (*src == ':' && i > 0 && gapPos == -1) { + gapPos = i; + ++src; + } else if (*src == ':' && i == 0 && src+1 < eow && src[1] == ':' && + gapPos == -1) { + gapPos = i; + src += 2; + } else { + return 0; + } + } + + if (setWords > 8 || + (setWords == 8 && gapPos != -1) || + (setWords < 8 && gapPos == -1)) + return 0; + + if (gapPos >= 0) { + int nToMove = setWords - (dot ? 2 : 0) - gapPos; + int gapLen = 8 - setWords; + tor_assert(nToMove >= 0); + memmove(&words[gapPos+gapLen], &words[gapPos], + sizeof(uint16_t)*nToMove); + memset(&words[gapPos], 0, sizeof(uint16_t)*gapLen); + } + for (i = 0; i < 8; ++i) { + out->s6_addr[2*i ] = words[i] >> 8; + out->s6_addr[2*i+1] = words[i] & 0xff; + } + + return 1; + } else { + return -1; + } +} diff --git a/src/lib/net/ipv6.h b/src/lib/net/ipv6.h new file mode 100644 index 0000000000..0a12e046ac --- /dev/null +++ b/src/lib/net/ipv6.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_IPV6_H +#define TOR_IPV6_H + +#include "orconfig.h" +#include <stddef.h> +#ifdef HAVE_NETINET_IN6_H +#include <netinet/in6.h> +#endif +#ifdef _WIN32 +#include <winsock2.h> +#include <ws2tcpip.h> +#include <windows.h> +#endif +#include "lib/cc/torint.h" + +/** Implementation of struct in6_addr for platforms that do not have it. + * Generally, these platforms are ones without IPv6 support, but we want to + * have a working in6_addr there anyway, so we can use it to parse IPv6 + * addresses. */ +#if !defined(HAVE_STRUCT_IN6_ADDR) +struct in6_addr +{ + union { + uint8_t u6_addr8[16]; + uint16_t u6_addr16[8]; + uint32_t u6_addr32[4]; + } in6_u; +#define s6_addr in6_u.u6_addr8 +#define s6_addr16 in6_u.u6_addr16 +#define s6_addr32 in6_u.u6_addr32 +}; +#endif /* !defined(HAVE_STRUCT_IN6_ADDR) */ + +/** @{ */ +/** Many BSD variants seem not to define these. */ +#if defined(__APPLE__) || defined(__darwin__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +#ifndef s6_addr16 +#define s6_addr16 __u6_addr.__u6_addr16 +#endif +#ifndef s6_addr32 +#define s6_addr32 __u6_addr.__u6_addr32 +#endif +#endif /* defined(__APPLE__) || defined(__darwin__) || ... */ +/** @} */ + +#ifndef HAVE_SA_FAMILY_T +typedef uint16_t sa_family_t; +#endif + +/** @{ */ +/** Apparently, MS and Solaris don't define s6_addr16 or s6_addr32; these + * macros get you a pointer to s6_addr32 or local equivalent. */ +#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR32 +#define S6_ADDR32(x) ((uint32_t*)(x).s6_addr32) +#else +#define S6_ADDR32(x) ((uint32_t*)((char*)&(x).s6_addr)) +#endif +#ifdef HAVE_STRUCT_IN6_ADDR_S6_ADDR16 +#define S6_ADDR16(x) ((uint16_t*)(x).s6_addr16) +#else +#define S6_ADDR16(x) ((uint16_t*)((char*)&(x).s6_addr)) +#endif +/** @} */ + +/** Implementation of struct sockaddr_in6 on platforms that do not have + * it. See notes on struct in6_addr. */ +#if !defined(HAVE_STRUCT_SOCKADDR_IN6) +struct sockaddr_in6 { + sa_family_t sin6_family; + uint16_t sin6_port; + // uint32_t sin6_flowinfo; + struct in6_addr sin6_addr; + // uint32_t sin6_scope_id; +}; +#endif /* !defined(HAVE_STRUCT_SOCKADDR_IN6) */ + +const char *tor_inet_ntop(int af, const void *src, char *dst, size_t len); +int tor_inet_pton(int af, const char *src, void *dst); + +#endif diff --git a/src/lib/net/nettypes.h b/src/lib/net/nettypes.h new file mode 100644 index 0000000000..f212374368 --- /dev/null +++ b/src/lib/net/nettypes.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_NET_TYPES_H +#define TOR_NET_TYPES_H + +#include "orconfig.h" +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#if (SIZEOF_SOCKLEN_T == 0) +typedef int socklen_t; +#endif + +#ifdef _WIN32 +/* XXX Actually, this should arguably be SOCKET; we use intptr_t here so that + * any inadvertent checks for the socket being <= 0 or > 0 will probably + * still work. */ +#define tor_socket_t intptr_t +#define TOR_SOCKET_T_FORMAT "%"PRIuPTR +#define SOCKET_OK(s) ((SOCKET)(s) != INVALID_SOCKET) +#define TOR_INVALID_SOCKET INVALID_SOCKET +#else /* !(defined(_WIN32)) */ +/** Type used for a network socket. */ +#define tor_socket_t int +#define TOR_SOCKET_T_FORMAT "%d" +/** Macro: true iff 's' is a possible value for a valid initialized socket. */ +#define SOCKET_OK(s) ((s) >= 0) +/** Error/uninitialized value for a tor_socket_t. */ +#define TOR_INVALID_SOCKET (-1) +#endif /* defined(_WIN32) */ + +#endif diff --git a/src/lib/net/resolve.c b/src/lib/net/resolve.c new file mode 100644 index 0000000000..cbe368ccfb --- /dev/null +++ b/src/lib/net/resolve.c @@ -0,0 +1,236 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/net/resolve.h" +#include "lib/net/address.h" +#include "lib/malloc/util_malloc.h" + +#include "siphash.h" +#include "ht.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +#include <string.h> + +/** Similar behavior to Unix gethostbyname: resolve <b>name</b>, and set + * *<b>addr</b> to the proper IP address, in host byte order. Returns 0 + * on success, -1 on failure; 1 on transient failure. + * + * (This function exists because standard windows gethostbyname + * doesn't treat raw IP addresses properly.) + */ + +MOCK_IMPL(int, +tor_lookup_hostname,(const char *name, uint32_t *addr)) +{ + tor_addr_t myaddr; + int ret; + + if ((ret = tor_addr_lookup(name, AF_INET, &myaddr))) + return ret; + + if (tor_addr_family(&myaddr) == AF_INET) { + *addr = tor_addr_to_ipv4h(&myaddr); + return ret; + } + + return -1; +} + +#ifdef USE_SANDBOX_GETADDRINFO +/** True if we should only return cached values */ +static int sandbox_getaddrinfo_is_active = 0; + +/** Cache entry for getaddrinfo results; used when sandboxing is implemented + * so that we can consult the cache when the sandbox prevents us from doing + * getaddrinfo. + * + * We support only a limited range of getaddrinfo calls, where servname is null + * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC. + */ +typedef struct cached_getaddrinfo_item_t { + HT_ENTRY(cached_getaddrinfo_item_t) node; + char *name; + int family; + /** set if no error; otherwise NULL */ + struct addrinfo *res; + /** 0 for no error; otherwise an EAI_* value */ + int err; +} cached_getaddrinfo_item_t; + +static unsigned +cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item) +{ + return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family; +} + +static unsigned +cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a, + const cached_getaddrinfo_item_t *b) +{ + return (a->family == b->family) && 0 == strcmp(a->name, b->name); +} + +#define cached_getaddrinfo_item_free(item) \ + FREE_AND_NULL(cached_getaddrinfo_item_t, \ + cached_getaddrinfo_item_free_, (item)) + +static void +cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item) +{ + if (item == NULL) + return; + + tor_free(item->name); + if (item->res) + freeaddrinfo(item->res); + tor_free(item); +} + +static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t) + getaddrinfo_cache = HT_INITIALIZER(); + +HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node, + cached_getaddrinfo_item_hash, + cached_getaddrinfo_items_eq) +HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node, + cached_getaddrinfo_item_hash, + cached_getaddrinfo_items_eq, + 0.6, tor_reallocarray_, tor_free_) + +/** If true, don't try to cache getaddrinfo results. */ +static int sandbox_getaddrinfo_cache_disabled = 0; + +/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in + * tor-resolve, when we have no intention of initializing crypto or of + * installing the sandbox.*/ +void +sandbox_disable_getaddrinfo_cache(void) +{ + sandbox_getaddrinfo_cache_disabled = 1; +} + +void +tor_freeaddrinfo(struct addrinfo *ai) +{ + if (sandbox_getaddrinfo_cache_disabled) + freeaddrinfo(ai); +} + +int +tor_getaddrinfo(const char *name, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res) +{ + int err; + struct cached_getaddrinfo_item_t search, *item; + + if (sandbox_getaddrinfo_cache_disabled) { + return getaddrinfo(name, NULL, hints, res); + } + + if (servname != NULL) { + log_warn(LD_BUG, "called with non-NULL servname"); + return EAI_NONAME; + } + if (name == NULL) { + log_warn(LD_BUG, "called with NULL name"); + return EAI_NONAME; + } + + *res = NULL; + + memset(&search, 0, sizeof(search)); + search.name = (char *) name; + search.family = hints ? hints->ai_family : AF_UNSPEC; + item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search); + + if (! sandbox_getaddrinfo_is_active) { + /* If the sandbox is not turned on yet, then getaddrinfo and store the + result. */ + + err = getaddrinfo(name, NULL, hints, res); + log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded"); + + if (! item) { + item = tor_malloc_zero(sizeof(*item)); + item->name = tor_strdup(name); + item->family = hints ? hints->ai_family : AF_UNSPEC; + HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item); + } + + if (item->res) { + freeaddrinfo(item->res); + item->res = NULL; + } + item->res = *res; + item->err = err; + return err; + } + + /* Otherwise, the sandbox is on. If we have an item, yield its cached + result. */ + if (item) { + *res = item->res; + return item->err; + } + + /* getting here means something went wrong */ + log_err(LD_BUG,"(Sandbox) failed to get address %s!", name); + return EAI_NONAME; +} + +int +tor_add_addrinfo(const char *name) +{ + struct addrinfo *res; + struct addrinfo hints; + int i; + static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC }; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + for (i = 0; i < 3; ++i) { + hints.ai_family = families[i]; + + res = NULL; + (void) tor_getaddrinfo(name, NULL, &hints, &res); + if (res) + tor_freeaddrinfo(res); + } + + return 0; +} + +void +tor_free_getaddrinfo_cache(void) +{ + cached_getaddrinfo_item_t **next, **item, *this; + + for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache); + item; + item = next) { + this = *item; + next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item); + cached_getaddrinfo_item_free(this); + } + + HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache); +} + +void +tor_make_getaddrinfo_cache_active(void) +{ + sandbox_getaddrinfo_is_active = 1; +} +#endif diff --git a/src/lib/net/resolve.h b/src/lib/net/resolve.h new file mode 100644 index 0000000000..f2280ae7e8 --- /dev/null +++ b/src/lib/net/resolve.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_RESOLVE_H +#define TOR_RESOLVE_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#ifdef _WIN32 +#include <winsock2.h> +#endif + +#if defined(HAVE_SECCOMP_H) && defined(__linux__) +#define USE_SANDBOX_GETADDRINFO +#endif + +MOCK_DECL(int,tor_lookup_hostname,(const char *name, uint32_t *addr)); + +struct addrinfo; +#ifdef USE_SANDBOX_GETADDRINFO +/** Pre-calls getaddrinfo in order to pre-record result. */ +int tor_add_addrinfo(const char *addr); + +struct addrinfo; +/** Replacement for getaddrinfo(), using pre-recorded results. */ +int tor_getaddrinfo(const char *name, const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); +void tor_freeaddrinfo(struct addrinfo *addrinfo); +void tor_free_getaddrinfo_cache(void); +void tor_make_getaddrinfo_cache_active(void); +#else /* !(defined(USE_SANDBOX_GETADDRINFO)) */ +#define tor_getaddrinfo(name, servname, hints, res) \ + getaddrinfo((name),(servname), (hints),(res)) +#define tor_add_addrinfo(name) \ + ((void)(name)) +#define tor_freeaddrinfo(addrinfo) \ + freeaddrinfo((addrinfo)) +#define tor_free_getaddrinfo_cache() +#endif /* defined(USE_SANDBOX_GETADDRINFO) */ + +void sandbox_disable_getaddrinfo_cache(void); + +#endif diff --git a/src/lib/net/socket.c b/src/lib/net/socket.c new file mode 100644 index 0000000000..dc3d1531ff --- /dev/null +++ b/src/lib/net/socket.c @@ -0,0 +1,824 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define SOCKET_PRIVATE +#include "lib/net/socket.h" +#include "lib/net/address.h" +#include "lib/cc/compat_compiler.h" +#include "lib/err/torerr.h" +#include "lib/lock/compat_mutex.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#ifdef _WIN32 +#include <winsock2.h> +#include <windows.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <stddef.h> +#include <string.h> + +/** Called before we make any calls to network-related functions. + * (Some operating systems require their network libraries to be + * initialized.) */ +int +network_init(void) +{ +#ifdef _WIN32 + /* This silly exercise is necessary before windows will allow + * gethostbyname to work. */ + WSADATA WSAData; + int r; + r = WSAStartup(0x101,&WSAData); + if (r) { + log_warn(LD_NET,"Error initializing windows network layer: code was %d",r); + return -1; + } + if (sizeof(SOCKET) != sizeof(tor_socket_t)) { + log_warn(LD_BUG,"The tor_socket_t type does not match SOCKET in size; Tor " + "might not work. (Sizes are %d and %d respectively.)", + (int)sizeof(tor_socket_t), (int)sizeof(SOCKET)); + } + /* WSAData.iMaxSockets might show the max sockets we're allowed to use. + * We might use it to complain if we're trying to be a server but have + * too few sockets available. */ +#endif /* defined(_WIN32) */ + return 0; +} + +/* When set_max_file_sockets() is called, update this with the max file + * descriptor value so we can use it to check the limit when opening a new + * socket. Default value is what Debian sets as the default hard limit. */ +static int max_sockets = 1024; + +/** Return the maximum number of allowed sockets. */ +int +get_max_sockets(void) +{ + return max_sockets; +} + +/** Set the maximum number of allowed sockets to <b>n</b> */ +void +set_max_sockets(int n) +{ + max_sockets = n; +} + +#undef DEBUG_SOCKET_COUNTING +#ifdef DEBUG_SOCKET_COUNTING +#include "lib/container/bitarray.h" + +/** A bitarray of all fds that should be passed to tor_socket_close(). Only + * used if DEBUG_SOCKET_COUNTING is defined. */ +static bitarray_t *open_sockets = NULL; +/** The size of <b>open_sockets</b>, in bits. */ +static int max_socket = -1; +#endif /* defined(DEBUG_SOCKET_COUNTING) */ + +/** Count of number of sockets currently open. (Undercounts sockets opened by + * eventdns and libevent.) */ +static int n_sockets_open = 0; + +/** Mutex to protect open_sockets, max_socket, and n_sockets_open. */ +static tor_mutex_t *socket_accounting_mutex = NULL; + +/** Helper: acquire the socket accounting lock. */ +static inline void +socket_accounting_lock(void) +{ + if (PREDICT_UNLIKELY(!socket_accounting_mutex)) + socket_accounting_mutex = tor_mutex_new(); + tor_mutex_acquire(socket_accounting_mutex); +} + +/** Helper: release the socket accounting lock. */ +static inline void +socket_accounting_unlock(void) +{ + tor_mutex_release(socket_accounting_mutex); +} + +/** As close(), but guaranteed to work for sockets across platforms (including + * Windows, where close()ing a socket doesn't work. Returns 0 on success and + * the socket error code on failure. */ +int +tor_close_socket_simple(tor_socket_t s) +{ + int r = 0; + + /* On Windows, you have to call close() on fds returned by open(), + * and closesocket() on fds returned by socket(). On Unix, everything + * gets close()'d. We abstract this difference by always using + * tor_close_socket to close sockets, and always using close() on + * files. + */ + #if defined(_WIN32) + r = closesocket(s); + #else + r = close(s); + #endif + + if (r != 0) { + int err = tor_socket_errno(-1); + log_info(LD_NET, "Close returned an error: %s", tor_socket_strerror(err)); + return err; + } + + return r; +} + +/** As tor_close_socket_simple(), but keeps track of the number + * of open sockets. Returns 0 on success, -1 on failure. */ +MOCK_IMPL(int, +tor_close_socket,(tor_socket_t s)) +{ + int r = tor_close_socket_simple(s); + + socket_accounting_lock(); +#ifdef DEBUG_SOCKET_COUNTING + if (s > max_socket || ! bitarray_is_set(open_sockets, s)) { + log_warn(LD_BUG, "Closing a socket (%d) that wasn't returned by tor_open_" + "socket(), or that was already closed or something.", s); + } else { + tor_assert(open_sockets && s <= max_socket); + bitarray_clear(open_sockets, s); + } +#endif /* defined(DEBUG_SOCKET_COUNTING) */ + if (r == 0) { + --n_sockets_open; + } else { +#ifdef _WIN32 + if (r != WSAENOTSOCK) + --n_sockets_open; +#else + if (r != EBADF) + --n_sockets_open; // LCOV_EXCL_LINE -- EIO and EINTR too hard to force. +#endif /* defined(_WIN32) */ + r = -1; + } + + tor_assert_nonfatal(n_sockets_open >= 0); + socket_accounting_unlock(); + return r; +} + +/** @{ */ +#ifdef DEBUG_SOCKET_COUNTING +/** Helper: if DEBUG_SOCKET_COUNTING is enabled, remember that <b>s</b> is + * now an open socket. */ +static inline void +mark_socket_open(tor_socket_t s) +{ + /* XXXX This bitarray business will NOT work on windows: sockets aren't + small ints there. */ + if (s > max_socket) { + if (max_socket == -1) { + open_sockets = bitarray_init_zero(s+128); + max_socket = s+128; + } else { + open_sockets = bitarray_expand(open_sockets, max_socket, s+128); + max_socket = s+128; + } + } + if (bitarray_is_set(open_sockets, s)) { + log_warn(LD_BUG, "I thought that %d was already open, but socket() just " + "gave it to me!", s); + } + bitarray_set(open_sockets, s); +} +#else /* !(defined(DEBUG_SOCKET_COUNTING)) */ +#define mark_socket_open(s) ((void) (s)) +#endif /* defined(DEBUG_SOCKET_COUNTING) */ +/** @} */ + +/** As socket(), but counts the number of open sockets. */ +MOCK_IMPL(tor_socket_t, +tor_open_socket,(int domain, int type, int protocol)) +{ + return tor_open_socket_with_extensions(domain, type, protocol, 1, 0); +} + +/** Mockable wrapper for connect(). */ +MOCK_IMPL(tor_socket_t, +tor_connect_socket,(tor_socket_t sock, const struct sockaddr *address, + socklen_t address_len)) +{ + return connect(sock,address,address_len); +} + +/** As socket(), but creates a nonblocking socket and + * counts the number of open sockets. */ +tor_socket_t +tor_open_socket_nonblocking(int domain, int type, int protocol) +{ + return tor_open_socket_with_extensions(domain, type, protocol, 1, 1); +} + +/** As socket(), but counts the number of open sockets and handles + * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. + * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate + * if the corresponding extension should be used.*/ +tor_socket_t +tor_open_socket_with_extensions(int domain, int type, int protocol, + int cloexec, int nonblock) +{ + tor_socket_t s; + + /* We are about to create a new file descriptor so make sure we have + * enough of them. */ + if (get_n_open_sockets() >= max_sockets - 1) { +#ifdef _WIN32 + WSASetLastError(WSAEMFILE); +#else + errno = EMFILE; +#endif + return TOR_INVALID_SOCKET; + } + +#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) + int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | + (nonblock ? SOCK_NONBLOCK : 0); + s = socket(domain, type|ext_flags, protocol); + if (SOCKET_OK(s)) + goto socket_ok; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with SOCK_CLOEXEC and SOCK_NONBLOCK + * support, we are running on one without. */ + if (errno != EINVAL) + return s; +#endif /* defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK) */ + + s = socket(domain, type, protocol); + if (! SOCKET_OK(s)) + return s; + +#if defined(FD_CLOEXEC) + if (cloexec) { + if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_FS,"Couldn't set FD_CLOEXEC: %s", strerror(errno)); + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } +#else /* !(defined(FD_CLOEXEC)) */ + (void)cloexec; +#endif /* defined(FD_CLOEXEC) */ + + if (nonblock) { + if (set_socket_nonblocking(s) == -1) { + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } + + goto socket_ok; /* So that socket_ok will not be unused. */ + + socket_ok: + tor_take_socket_ownership(s); + return s; +} + +/** + * For socket accounting: remember that we are the owner of the socket + * <b>s</b>. This will prevent us from overallocating sockets, and prevent us + * from asserting later when we close the socket <b>s</b>. + */ +void +tor_take_socket_ownership(tor_socket_t s) +{ + socket_accounting_lock(); + ++n_sockets_open; + mark_socket_open(s); + socket_accounting_unlock(); +} + +/** As accept(), but counts the number of open sockets. */ +tor_socket_t +tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, socklen_t *len) +{ + return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 0); +} + +/** As accept(), but returns a nonblocking socket and + * counts the number of open sockets. */ +tor_socket_t +tor_accept_socket_nonblocking(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len) +{ + return tor_accept_socket_with_extensions(sockfd, addr, len, 1, 1); +} + +/** As accept(), but counts the number of open sockets and handles + * socket creation with either of SOCK_CLOEXEC and SOCK_NONBLOCK specified. + * <b>cloexec</b> and <b>nonblock</b> should be either 0 or 1 to indicate + * if the corresponding extension should be used.*/ +tor_socket_t +tor_accept_socket_with_extensions(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len, int cloexec, int nonblock) +{ + tor_socket_t s; + + /* We are about to create a new file descriptor so make sure we have + * enough of them. */ + if (get_n_open_sockets() >= max_sockets - 1) { +#ifdef _WIN32 + WSASetLastError(WSAEMFILE); +#else + errno = EMFILE; +#endif + return TOR_INVALID_SOCKET; + } + +#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) \ + && defined(SOCK_NONBLOCK) + int ext_flags = (cloexec ? SOCK_CLOEXEC : 0) | + (nonblock ? SOCK_NONBLOCK : 0); + s = accept4(sockfd, addr, len, ext_flags); + if (SOCKET_OK(s)) + goto socket_ok; + /* If we got an error, see if it is ENOSYS. ENOSYS indicates that, + * even though we were built on a system with accept4 support, we + * are running on one without. Also, check for EINVAL, which indicates that + * we are missing SOCK_CLOEXEC/SOCK_NONBLOCK support. */ + if (errno != EINVAL && errno != ENOSYS) + return s; +#endif /* defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) ... */ + + s = accept(sockfd, addr, len); + if (!SOCKET_OK(s)) + return s; + +#if defined(FD_CLOEXEC) + if (cloexec) { + if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) { + log_warn(LD_NET, "Couldn't set FD_CLOEXEC: %s", strerror(errno)); + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } +#else /* !(defined(FD_CLOEXEC)) */ + (void)cloexec; +#endif /* defined(FD_CLOEXEC) */ + + if (nonblock) { + if (set_socket_nonblocking(s) == -1) { + tor_close_socket_simple(s); + return TOR_INVALID_SOCKET; + } + } + + goto socket_ok; /* So that socket_ok will not be unused. */ + + socket_ok: + tor_take_socket_ownership(s); + return s; +} + +/** Return the number of sockets we currently have opened. */ +int +get_n_open_sockets(void) +{ + int n; + socket_accounting_lock(); + n = n_sockets_open; + socket_accounting_unlock(); + return n; +} + +/** + * Allocate a pair of connected sockets. (Like socketpair(family, + * type,protocol,fd), but works on systems that don't have + * socketpair.) + * + * Currently, only (AF_UNIX, SOCK_STREAM, 0) sockets are supported. + * + * Note that on systems without socketpair, this call will fail if + * localhost is inaccessible (for example, if the networking + * stack is down). And even if it succeeds, the socket pair will not + * be able to read while localhost is down later (the socket pair may + * even close, depending on OS-specific timeouts). + * + * Returns 0 on success and -errno on failure; do not rely on the value + * of errno or WSAGetLastError(). + **/ +/* It would be nicer just to set errno, but that won't work for windows. */ +int +tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) +{ +//don't use win32 socketpairs (they are always bad) +#if defined(HAVE_SOCKETPAIR) && !defined(_WIN32) + int r; + +#ifdef SOCK_CLOEXEC + r = socketpair(family, type|SOCK_CLOEXEC, protocol, fd); + if (r == 0) + goto sockets_ok; + /* If we got an error, see if it is EINVAL. EINVAL might indicate that, + * even though we were built on a system with SOCK_CLOEXEC support, we + * are running on one without. */ + if (errno != EINVAL) + return -errno; +#endif /* defined(SOCK_CLOEXEC) */ + + r = socketpair(family, type, protocol, fd); + if (r < 0) + return -errno; + +#if defined(FD_CLOEXEC) + if (SOCKET_OK(fd[0])) { + r = fcntl(fd[0], F_SETFD, FD_CLOEXEC); + if (r == -1) { + close(fd[0]); + close(fd[1]); + return -errno; + } + } + if (SOCKET_OK(fd[1])) { + r = fcntl(fd[1], F_SETFD, FD_CLOEXEC); + if (r == -1) { + close(fd[0]); + close(fd[1]); + return -errno; + } + } +#endif /* defined(FD_CLOEXEC) */ + goto sockets_ok; /* So that sockets_ok will not be unused. */ + + sockets_ok: + socket_accounting_lock(); + if (SOCKET_OK(fd[0])) { + ++n_sockets_open; + mark_socket_open(fd[0]); + } + if (SOCKET_OK(fd[1])) { + ++n_sockets_open; + mark_socket_open(fd[1]); + } + socket_accounting_unlock(); + + return 0; +#else /* !(defined(HAVE_SOCKETPAIR) && !defined(_WIN32)) */ + return tor_ersatz_socketpair(family, type, protocol, fd); +#endif /* defined(HAVE_SOCKETPAIR) && !defined(_WIN32) */ +} + +#ifdef NEED_ERSATZ_SOCKETPAIR + +static inline socklen_t +SIZEOF_SOCKADDR(int domain) +{ + switch (domain) { + case AF_INET: + return sizeof(struct sockaddr_in); + case AF_INET6: + return sizeof(struct sockaddr_in6); + default: + return 0; + } +} + +/** + * Helper used to implement socketpair on systems that lack it, by + * making a direct connection to localhost. + */ +STATIC int +tor_ersatz_socketpair(int family, int type, int protocol, tor_socket_t fd[2]) +{ + /* This socketpair does not work when localhost is down. So + * it's really not the same thing at all. But it's close enough + * for now, and really, when localhost is down sometimes, we + * have other problems too. + */ + tor_socket_t listener = TOR_INVALID_SOCKET; + tor_socket_t connector = TOR_INVALID_SOCKET; + tor_socket_t acceptor = TOR_INVALID_SOCKET; + tor_addr_t listen_tor_addr; + struct sockaddr_storage connect_addr_ss, listen_addr_ss; + struct sockaddr *listen_addr = (struct sockaddr *) &listen_addr_ss; + uint16_t listen_port = 0; + tor_addr_t connect_tor_addr; + uint16_t connect_port = 0; + struct sockaddr *connect_addr = (struct sockaddr *) &connect_addr_ss; + socklen_t size; + int saved_errno = -1; + int ersatz_domain = AF_INET; + + memset(&connect_tor_addr, 0, sizeof(connect_tor_addr)); + memset(&connect_addr_ss, 0, sizeof(connect_addr_ss)); + memset(&listen_tor_addr, 0, sizeof(listen_tor_addr)); + memset(&listen_addr_ss, 0, sizeof(listen_addr_ss)); + + if (protocol +#ifdef AF_UNIX + || family != AF_UNIX +#endif + ) { +#ifdef _WIN32 + return -WSAEAFNOSUPPORT; +#else + return -EAFNOSUPPORT; +#endif + } + if (!fd) { + return -EINVAL; + } + + listener = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(listener)) { + int first_errno = tor_socket_errno(-1); + if (first_errno == SOCK_ERRNO(EPROTONOSUPPORT) + && ersatz_domain == AF_INET) { + /* Assume we're on an IPv6-only system */ + ersatz_domain = AF_INET6; + listener = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(listener)) { + /* Keep the previous behaviour, which was to return the IPv4 error. + * (This may be less informative on IPv6-only systems.) + * XX/teor - is there a better way to decide which errno to return? + * (I doubt we care much either way, once there is an error.) + */ + return -first_errno; + } + } + } + /* If there is no 127.0.0.1 or ::1, this will and must fail. Otherwise, we + * risk exposing a socketpair on a routable IP address. (Some BSD jails + * use a routable address for localhost. Fortunately, they have the real + * AF_UNIX socketpair.) */ + if (ersatz_domain == AF_INET) { + tor_addr_from_ipv4h(&listen_tor_addr, INADDR_LOOPBACK); + } else { + tor_addr_parse(&listen_tor_addr, "[::1]"); + } + tor_assert(tor_addr_is_loopback(&listen_tor_addr)); + size = tor_addr_to_sockaddr(&listen_tor_addr, + 0 /* kernel chooses port. */, + listen_addr, + sizeof(listen_addr_ss)); + if (bind(listener, listen_addr, size) == -1) + goto tidy_up_and_fail; + if (listen(listener, 1) == -1) + goto tidy_up_and_fail; + + connector = tor_open_socket(ersatz_domain, type, 0); + if (!SOCKET_OK(connector)) + goto tidy_up_and_fail; + /* We want to find out the port number to connect to. */ + size = sizeof(connect_addr_ss); + if (getsockname(listener, connect_addr, &size) == -1) + goto tidy_up_and_fail; + if (size != SIZEOF_SOCKADDR (connect_addr->sa_family)) + goto abort_tidy_up_and_fail; + if (connect(connector, connect_addr, size) == -1) + goto tidy_up_and_fail; + + size = sizeof(listen_addr_ss); + acceptor = tor_accept_socket(listener, listen_addr, &size); + if (!SOCKET_OK(acceptor)) + goto tidy_up_and_fail; + if (size != SIZEOF_SOCKADDR(listen_addr->sa_family)) + goto abort_tidy_up_and_fail; + /* Now check we are talking to ourself by matching port and host on the + two sockets. */ + if (getsockname(connector, connect_addr, &size) == -1) + goto tidy_up_and_fail; + /* Set *_tor_addr and *_port to the address and port that was used */ + tor_addr_from_sockaddr(&listen_tor_addr, listen_addr, &listen_port); + tor_addr_from_sockaddr(&connect_tor_addr, connect_addr, &connect_port); + if (size != SIZEOF_SOCKADDR (connect_addr->sa_family) + || tor_addr_compare(&listen_tor_addr, &connect_tor_addr, CMP_SEMANTIC) + || listen_port != connect_port) { + goto abort_tidy_up_and_fail; + } + tor_close_socket(listener); + fd[0] = connector; + fd[1] = acceptor; + + return 0; + + abort_tidy_up_and_fail: +#ifdef _WIN32 + saved_errno = WSAECONNABORTED; +#else + saved_errno = ECONNABORTED; /* I hope this is portable and appropriate. */ +#endif + tidy_up_and_fail: + if (saved_errno < 0) + saved_errno = errno; + if (SOCKET_OK(listener)) + tor_close_socket(listener); + if (SOCKET_OK(connector)) + tor_close_socket(connector); + if (SOCKET_OK(acceptor)) + tor_close_socket(acceptor); + return -saved_errno; +} + +#endif /* defined(NEED_ERSATZ_SOCKETPAIR) */ + +/** Mockable wrapper for getsockname(). */ +MOCK_IMPL(int, +tor_getsockname,(tor_socket_t sock, struct sockaddr *address, + socklen_t *address_len)) +{ + return getsockname(sock, address, address_len); +} + +/** + * Find the local address associated with the socket <b>sock</b>, and + * place it in *<b>addr_out</b>. Return 0 on success, -1 on failure. + * + * (As tor_getsockname, but instead places the result in a tor_addr_t.) */ +int +tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock) +{ + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + memset(&ss, 0, sizeof(ss)); + + if (tor_getsockname(sock, (struct sockaddr *) &ss, &ss_len) < 0) + return -1; + + return tor_addr_from_sockaddr(addr_out, (struct sockaddr *)&ss, NULL); +} + +/** Turn <b>socket</b> into a nonblocking socket. Return 0 on success, -1 + * on failure. + */ +int +set_socket_nonblocking(tor_socket_t sock) +{ +#if defined(_WIN32) + unsigned long nonblocking = 1; + ioctlsocket(sock, FIONBIO, (unsigned long*) &nonblocking); +#else + int flags; + + flags = fcntl(sock, F_GETFL, 0); + if (flags == -1) { + log_warn(LD_NET, "Couldn't get file status flags: %s", strerror(errno)); + return -1; + } + flags |= O_NONBLOCK; + if (fcntl(sock, F_SETFL, flags) == -1) { + log_warn(LD_NET, "Couldn't set file status flags: %s", strerror(errno)); + return -1; + } +#endif /* defined(_WIN32) */ + + return 0; +} + +/** Read from <b>sock</b> to <b>buf</b>, until we get <b>count</b> bytes or + * reach the end of the file. Return the number of bytes read, or -1 on + * error. Only use if fd is a blocking fd. */ +ssize_t +read_all_from_socket(tor_socket_t sock, char *buf, size_t count) +{ + size_t numread = 0; + ssize_t result; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) { + errno = EINVAL; + return -1; + } + + while (numread < count) { + result = tor_socket_recv(sock, buf+numread, count-numread, 0); + if (result<0) + return -1; + else if (result == 0) + break; + numread += result; + } + return (ssize_t)numread; +} + +/** Write <b>count</b> bytes from <b>buf</b> to <b>sock</b>. Return the number + * of bytes written, or -1 on error. Only use if fd is a blocking fd. */ +ssize_t +write_all_to_socket(tor_socket_t fd, const char *buf, size_t count) +{ + size_t written = 0; + ssize_t result; + raw_assert(count < SSIZE_MAX); + + while (written != count) { + result = tor_socket_send(fd, buf+written, count-written, 0); + if (result<0) + return -1; + written += result; + } + return (ssize_t)count; +} + +/** + * On Windows, WSAEWOULDBLOCK is not always correct: when you see it, + * you need to ask the socket for its actual errno. Also, you need to + * get your errors from WSAGetLastError, not errno. (If you supply a + * socket of -1, we check WSAGetLastError, but don't correct + * WSAEWOULDBLOCKs.) + * + * The upshot of all of this is that when a socket call fails, you + * should call tor_socket_errno <em>at most once</em> on the failing + * socket to get the error. + */ +#if defined(_WIN32) +int +tor_socket_errno(tor_socket_t sock) +{ + int optval, optvallen=sizeof(optval); + int err = WSAGetLastError(); + if (err == WSAEWOULDBLOCK && SOCKET_OK(sock)) { + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval, &optvallen)) + return err; + if (optval) + return optval; + } + return err; +} +#endif /* defined(_WIN32) */ + +#if defined(_WIN32) +#define E(code, s) { code, (s " [" #code " ]") } +struct { int code; const char *msg; } windows_socket_errors[] = { + E(WSAEINTR, "Interrupted function call"), + E(WSAEACCES, "Permission denied"), + E(WSAEFAULT, "Bad address"), + E(WSAEINVAL, "Invalid argument"), + E(WSAEMFILE, "Too many open files"), + E(WSAEWOULDBLOCK, "Resource temporarily unavailable"), + E(WSAEINPROGRESS, "Operation now in progress"), + E(WSAEALREADY, "Operation already in progress"), + E(WSAENOTSOCK, "Socket operation on nonsocket"), + E(WSAEDESTADDRREQ, "Destination address required"), + E(WSAEMSGSIZE, "Message too long"), + E(WSAEPROTOTYPE, "Protocol wrong for socket"), + E(WSAENOPROTOOPT, "Bad protocol option"), + E(WSAEPROTONOSUPPORT, "Protocol not supported"), + E(WSAESOCKTNOSUPPORT, "Socket type not supported"), + /* What's the difference between NOTSUPP and NOSUPPORT? :) */ + E(WSAEOPNOTSUPP, "Operation not supported"), + E(WSAEPFNOSUPPORT, "Protocol family not supported"), + E(WSAEAFNOSUPPORT, "Address family not supported by protocol family"), + E(WSAEADDRINUSE, "Address already in use"), + E(WSAEADDRNOTAVAIL, "Cannot assign requested address"), + E(WSAENETDOWN, "Network is down"), + E(WSAENETUNREACH, "Network is unreachable"), + E(WSAENETRESET, "Network dropped connection on reset"), + E(WSAECONNABORTED, "Software caused connection abort"), + E(WSAECONNRESET, "Connection reset by peer"), + E(WSAENOBUFS, "No buffer space available"), + E(WSAEISCONN, "Socket is already connected"), + E(WSAENOTCONN, "Socket is not connected"), + E(WSAESHUTDOWN, "Cannot send after socket shutdown"), + E(WSAETIMEDOUT, "Connection timed out"), + E(WSAECONNREFUSED, "Connection refused"), + E(WSAEHOSTDOWN, "Host is down"), + E(WSAEHOSTUNREACH, "No route to host"), + E(WSAEPROCLIM, "Too many processes"), + /* Yes, some of these start with WSA, not WSAE. No, I don't know why. */ + E(WSASYSNOTREADY, "Network subsystem is unavailable"), + E(WSAVERNOTSUPPORTED, "Winsock.dll out of range"), + E(WSANOTINITIALISED, "Successful WSAStartup not yet performed"), + E(WSAEDISCON, "Graceful shutdown now in progress"), +#ifdef WSATYPE_NOT_FOUND + E(WSATYPE_NOT_FOUND, "Class type not found"), +#endif + E(WSAHOST_NOT_FOUND, "Host not found"), + E(WSATRY_AGAIN, "Nonauthoritative host not found"), + E(WSANO_RECOVERY, "This is a nonrecoverable error"), + E(WSANO_DATA, "Valid name, no data record of requested type)"), + + /* There are some more error codes whose numeric values are marked + * <b>OS dependent</b>. They start with WSA_, apparently for the same + * reason that practitioners of some craft traditions deliberately + * introduce imperfections into their baskets and rugs "to allow the + * evil spirits to escape." If we catch them, then our binaries + * might not report consistent results across versions of Windows. + * Thus, I'm going to let them all fall through. + */ + { -1, NULL }, +}; +/** There does not seem to be a strerror equivalent for Winsock errors. + * Naturally, we have to roll our own. + */ +const char * +tor_socket_strerror(int e) +{ + int i; + for (i=0; windows_socket_errors[i].code >= 0; ++i) { + if (e == windows_socket_errors[i].code) + return windows_socket_errors[i].msg; + } + return strerror(e); +} +#endif /* defined(_WIN32) */ diff --git a/src/lib/net/socket.h b/src/lib/net/socket.h new file mode 100644 index 0000000000..cb0ccbe817 --- /dev/null +++ b/src/lib/net/socket.h @@ -0,0 +1,120 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SOCKET_H +#define TOR_SOCKET_H + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/net/nettypes.h" +#include "lib/testsupport/testsupport.h" + +#include <errno.h> + +struct sockaddr; + +int tor_close_socket_simple(tor_socket_t s); +MOCK_DECL(int, tor_close_socket, (tor_socket_t s)); +void tor_take_socket_ownership(tor_socket_t s); +tor_socket_t tor_open_socket_with_extensions( + int domain, int type, int protocol, + int cloexec, int nonblock); +MOCK_DECL(tor_socket_t,tor_open_socket,(int domain, int type, int protocol)); +tor_socket_t tor_open_socket_nonblocking(int domain, int type, int protocol); +tor_socket_t tor_accept_socket(tor_socket_t sockfd, struct sockaddr *addr, + socklen_t *len); +tor_socket_t tor_accept_socket_nonblocking(tor_socket_t sockfd, + struct sockaddr *addr, + socklen_t *len); +tor_socket_t tor_accept_socket_with_extensions(tor_socket_t sockfd, + struct sockaddr *addr, + socklen_t *len, + int cloexec, int nonblock); +MOCK_DECL(tor_socket_t, tor_connect_socket,(tor_socket_t socket, + const struct sockaddr *address, + socklen_t address_len)); +int get_n_open_sockets(void); + +MOCK_DECL(int,tor_getsockname,(tor_socket_t socket, struct sockaddr *address, + socklen_t *address_len)); +struct tor_addr_t; +int tor_addr_from_getsockname(struct tor_addr_t *addr_out, tor_socket_t sock); + +#define tor_socket_send(s, buf, len, flags) send(s, buf, len, flags) +#define tor_socket_recv(s, buf, len, flags) recv(s, buf, len, flags) + +int set_socket_nonblocking(tor_socket_t socket); +int tor_socketpair(int family, int type, int protocol, tor_socket_t fd[2]); +int network_init(void); + +int get_max_sockets(void); +void set_max_sockets(int); + +ssize_t write_all_to_socket(tor_socket_t fd, const char *buf, size_t count); +ssize_t read_all_from_socket(tor_socket_t fd, char *buf, size_t count); + +/* For stupid historical reasons, windows sockets have an independent + * set of errnos, and an independent way to get them. Also, you can't + * always believe WSAEWOULDBLOCK. Use the macros below to compare + * errnos against expected values, and use tor_socket_errno to find + * the actual errno after a socket operation fails. + */ +#if defined(_WIN32) +/** Expands to WSA<b>e</b> on Windows, and to <b>e</b> elsewhere. */ +#define SOCK_ERRNO(e) WSA##e +/** Return true if e is EAGAIN or the local equivalent. */ +#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == WSAEWOULDBLOCK) +/** Return true if e is EINPROGRESS or the local equivalent. */ +#define ERRNO_IS_EINPROGRESS(e) ((e) == WSAEINPROGRESS) +/** Return true if e is EINPROGRESS or the local equivalent as returned by + * a call to connect(). */ +#define ERRNO_IS_CONN_EINPROGRESS(e) \ + ((e) == WSAEINPROGRESS || (e)== WSAEINVAL || (e) == WSAEWOULDBLOCK) +/** Return true if e is EAGAIN or another error indicating that a call to + * accept() has no pending connections to return. */ +#define ERRNO_IS_ACCEPT_EAGAIN(e) ERRNO_IS_EAGAIN(e) +/** Return true if e is EMFILE or another error indicating that a call to + * accept() has failed because we're out of fds or something. */ +#define ERRNO_IS_RESOURCE_LIMIT(e) \ + ((e) == WSAEMFILE || (e) == WSAENOBUFS) +/** Return true if e is EADDRINUSE or the local equivalent. */ +#define ERRNO_IS_EADDRINUSE(e) ((e) == WSAEADDRINUSE) +/** Return true if e is EINTR or the local equivalent */ +#define ERRNO_IS_EINTR(e) ((e) == WSAEINTR || 0) +int tor_socket_errno(tor_socket_t sock); +const char *tor_socket_strerror(int e); +#else /* !(defined(_WIN32)) */ +#define SOCK_ERRNO(e) e +#if EAGAIN == EWOULDBLOCK +/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */ +#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || 0) +#else +#define ERRNO_IS_EAGAIN(e) ((e) == EAGAIN || (e) == EWOULDBLOCK) +#endif /* EAGAIN == EWOULDBLOCK */ +#define ERRNO_IS_EINTR(e) ((e) == EINTR || 0) +#define ERRNO_IS_EINPROGRESS(e) ((e) == EINPROGRESS || 0) +#define ERRNO_IS_CONN_EINPROGRESS(e) ((e) == EINPROGRESS || 0) +#define ERRNO_IS_ACCEPT_EAGAIN(e) \ + (ERRNO_IS_EAGAIN(e) || (e) == ECONNABORTED) +#define ERRNO_IS_RESOURCE_LIMIT(e) \ + ((e) == EMFILE || (e) == ENFILE || (e) == ENOBUFS || (e) == ENOMEM) +#define ERRNO_IS_EADDRINUSE(e) (((e) == EADDRINUSE) || 0) +#define tor_socket_errno(sock) (errno) +#define tor_socket_strerror(e) strerror(e) +#endif /* defined(_WIN32) */ + +#ifdef SOCKET_PRIVATE +#if !defined(HAVE_SOCKETPAIR) || defined(_WIN32) || defined(TOR_UNIT_TESTS) +#define NEED_ERSATZ_SOCKETPAIR +STATIC int tor_ersatz_socketpair(int family, int type, int protocol, + tor_socket_t fd[2]); +#endif +#endif /* defined(COMPAT_PRIVATE) */ + +#if defined(_WIN32) && !defined(SIO_IDEAL_SEND_BACKLOG_QUERY) +#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747b +#endif + +#endif diff --git a/src/lib/net/socks5_status.h b/src/lib/net/socks5_status.h new file mode 100644 index 0000000000..74b9c91023 --- /dev/null +++ b/src/lib/net/socks5_status.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SOCKS5_STATUS_H +#define TOR_SOCKS5_STATUS_H + +/** Specified SOCKS5 status codes. */ +typedef enum { + SOCKS5_SUCCEEDED = 0x00, + SOCKS5_GENERAL_ERROR = 0x01, + SOCKS5_NOT_ALLOWED = 0x02, + SOCKS5_NET_UNREACHABLE = 0x03, + SOCKS5_HOST_UNREACHABLE = 0x04, + SOCKS5_CONNECTION_REFUSED = 0x05, + SOCKS5_TTL_EXPIRED = 0x06, + SOCKS5_COMMAND_NOT_SUPPORTED = 0x07, + SOCKS5_ADDRESS_TYPE_NOT_SUPPORTED = 0x08, +} socks5_reply_status_t; + +#endif diff --git a/src/lib/osinfo/.may_include b/src/lib/osinfo/.may_include new file mode 100644 index 0000000000..058f6eb89c --- /dev/null +++ b/src/lib/osinfo/.may_include @@ -0,0 +1,5 @@ +orconfig.h + +lib/osinfo/*.h +lib/string/*.h +lib/testsupport/*.h diff --git a/src/lib/osinfo/include.am b/src/lib/osinfo/include.am new file mode 100644 index 0000000000..16c5812604 --- /dev/null +++ b/src/lib/osinfo/include.am @@ -0,0 +1,17 @@ + +noinst_LIBRARIES += src/lib/libtor-osinfo.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-osinfo-testing.a +endif + +src_lib_libtor_osinfo_a_SOURCES = \ + src/lib/osinfo/uname.c + +src_lib_libtor_osinfo_testing_a_SOURCES = \ + $(src_lib_libtor_osinfo_a_SOURCES) +src_lib_libtor_osinfo_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_osinfo_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/osinfo/uname.h diff --git a/src/lib/osinfo/uname.c b/src/lib/osinfo/uname.c new file mode 100644 index 0000000000..a0fa26d1d2 --- /dev/null +++ b/src/lib/osinfo/uname.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/osinfo/uname.h" + +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" + +#ifdef HAVE_UNAME +#include <sys/utsname.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif +#include <string.h> + +/** Hold the result of our call to <b>uname</b>. */ +static char uname_result[256]; +/** True iff uname_result is set. */ +static int uname_result_is_set = 0; + +/** Return a pointer to a description of our platform. + */ +MOCK_IMPL(const char *, +get_uname,(void)) +{ +#ifdef HAVE_UNAME + struct utsname u; +#endif + if (!uname_result_is_set) { +#ifdef HAVE_UNAME + if (uname(&u) != -1) { + /* (Linux says 0 is success, Solaris says 1 is success) */ + strlcpy(uname_result, u.sysname, sizeof(uname_result)); + } else +#endif /* defined(HAVE_UNAME) */ + { +#ifdef _WIN32 + OSVERSIONINFOEX info; + int i; + const char *plat = NULL; + static struct { + unsigned major; unsigned minor; const char *version; + } win_version_table[] = { + { 6, 2, "Windows 8" }, + { 6, 1, "Windows 7" }, + { 6, 0, "Windows Vista" }, + { 5, 2, "Windows Server 2003" }, + { 5, 1, "Windows XP" }, + { 5, 0, "Windows 2000" }, + /* { 4, 0, "Windows NT 4.0" }, */ + { 4, 90, "Windows Me" }, + { 4, 10, "Windows 98" }, + /* { 4, 0, "Windows 95" } */ + { 3, 51, "Windows NT 3.51" }, + { 0, 0, NULL } + }; + memset(&info, 0, sizeof(info)); + info.dwOSVersionInfoSize = sizeof(info); + if (! GetVersionEx((LPOSVERSIONINFO)&info)) { + strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx" + " doesn't work.", sizeof(uname_result)); + uname_result_is_set = 1; + return uname_result; + } + if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) { + if (info.dwPlatformId == VER_PLATFORM_WIN32_NT) + plat = "Windows NT 4.0"; + else + plat = "Windows 95"; + } else { + for (i=0; win_version_table[i].major>0; ++i) { + if (win_version_table[i].major == info.dwMajorVersion && + win_version_table[i].minor == info.dwMinorVersion) { + plat = win_version_table[i].version; + break; + } + } + } + if (plat) { + strlcpy(uname_result, plat, sizeof(uname_result)); + } else { + if (info.dwMajorVersion > 6 || + (info.dwMajorVersion==6 && info.dwMinorVersion>2)) + tor_snprintf(uname_result, sizeof(uname_result), + "Very recent version of Windows [major=%d,minor=%d]", + (int)info.dwMajorVersion,(int)info.dwMinorVersion); + else + tor_snprintf(uname_result, sizeof(uname_result), + "Unrecognized version of Windows [major=%d,minor=%d]", + (int)info.dwMajorVersion,(int)info.dwMinorVersion); + } +#ifdef VER_NT_SERVER + if (info.wProductType == VER_NT_SERVER || + info.wProductType == VER_NT_DOMAIN_CONTROLLER) { + strlcat(uname_result, " [server]", sizeof(uname_result)); + } +#endif /* defined(VER_NT_SERVER) */ +#else /* !(defined(_WIN32)) */ + /* LCOV_EXCL_START -- can't provoke uname failure */ + strlcpy(uname_result, "Unknown platform", sizeof(uname_result)); + /* LCOV_EXCL_STOP */ +#endif /* defined(_WIN32) */ + } + uname_result_is_set = 1; + } + return uname_result; +} diff --git a/src/lib/osinfo/uname.h b/src/lib/osinfo/uname.h new file mode 100644 index 0000000000..1f0b78385f --- /dev/null +++ b/src/lib/osinfo/uname.h @@ -0,0 +1,9 @@ + +#ifndef HAVE_TOR_UNAME_H +#define HAVE_TOR_UNAME_H + +#include "lib/testsupport/testsupport.h" + +MOCK_DECL(const char *, get_uname,(void)); + +#endif diff --git a/src/lib/process/.may_include b/src/lib/process/.may_include new file mode 100644 index 0000000000..05414d2a96 --- /dev/null +++ b/src/lib/process/.may_include @@ -0,0 +1,17 @@ +orconfig.h + +lib/cc/*.h +lib/container/*.h +lib/ctime/*.h +lib/err/*.h +lib/intmath/*.h +lib/fs/*.h +lib/log/*.h +lib/malloc/*.h +lib/net/*.h +lib/process/*.h +lib/string/*.h +lib/testsupport/*.h +lib/thread/*.h + +ht.h
\ No newline at end of file diff --git a/src/lib/process/daemon.c b/src/lib/process/daemon.c new file mode 100644 index 0000000000..edffb04683 --- /dev/null +++ b/src/lib/process/daemon.c @@ -0,0 +1,159 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/daemon.h" + +#ifndef _WIN32 + +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/thread/threads.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/* Based on code contributed by christian grothoff */ +/** True iff we've called start_daemon(). */ +static int start_daemon_called = 0; +/** True iff we've called finish_daemon(). */ +static int finish_daemon_called = 0; +/** Socketpair used to communicate between parent and child process while + * daemonizing. */ +static int daemon_filedes[2]; +/** Start putting the process into daemon mode: fork and drop all resources + * except standard fds. The parent process never returns, but stays around + * until finish_daemon is called. (Note: it's safe to call this more + * than once: calls after the first are ignored.) + */ +void +start_daemon(void) +{ + pid_t pid; + + if (start_daemon_called) + return; + start_daemon_called = 1; + + if (pipe(daemon_filedes)) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"pipe failed; exiting. Error was %s", strerror(errno)); + exit(1); // exit ok: during daemonize, pipe failed. + /* LCOV_EXCL_STOP */ + } + pid = fork(); + if (pid < 0) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"fork failed. Exiting."); + exit(1); // exit ok: during daemonize, fork failed + /* LCOV_EXCL_STOP */ + } + if (pid) { /* Parent */ + int ok; + char c; + + close(daemon_filedes[1]); /* we only read */ + ok = -1; + while (0 < read(daemon_filedes[0], &c, sizeof(char))) { + if (c == '.') + ok = 1; + } + fflush(stdout); + if (ok == 1) + exit(0); // exit ok: during daemonize, daemonizing. + else + exit(1); /* child reported error. exit ok: daemonize failed. */ + } else { /* Child */ + close(daemon_filedes[0]); /* we only write */ + + (void) setsid(); /* Detach from controlling terminal */ + /* + * Fork one more time, so the parent (the session group leader) can exit. + * This means that we, as a non-session group leader, can never regain a + * controlling terminal. This part is recommended by Stevens's + * _Advanced Programming in the Unix Environment_. + */ + if (fork() != 0) { + exit(0); // exit ok: during daemonize, fork failed (2) + } + set_main_thread(); /* We are now the main thread. */ + + return; + } +} + +/** Finish putting the process into daemon mode: drop standard fds, and tell + * the parent process to exit. (Note: it's safe to call this more than once: + * calls after the first are ignored. Calls start_daemon first if it hasn't + * been called already.) + */ +void +finish_daemon(const char *desired_cwd) +{ + int nullfd; + char c = '.'; + if (finish_daemon_called) + return; + if (!start_daemon_called) + start_daemon(); + finish_daemon_called = 1; + + if (!desired_cwd) + desired_cwd = "/"; + /* Don't hold the wrong FS mounted */ + if (chdir(desired_cwd) < 0) { + log_err(LD_GENERAL,"chdir to \"%s\" failed. Exiting.",desired_cwd); + exit(1); // exit ok: during daemonize, chdir failed. + } + + nullfd = tor_open_cloexec("/dev/null", O_RDWR, 0); + if (nullfd < 0) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"/dev/null can't be opened. Exiting."); + exit(1); // exit ok: during daemonize, couldn't open /dev/null + /* LCOV_EXCL_STOP */ + } + /* close fds linking to invoking terminal, but + * close usual incoming fds, but redirect them somewhere + * useful so the fds don't get reallocated elsewhere. + */ + if (dup2(nullfd,0) < 0 || + dup2(nullfd,1) < 0 || + dup2(nullfd,2) < 0) { + /* LCOV_EXCL_START */ + log_err(LD_GENERAL,"dup2 failed. Exiting."); + exit(1); // exit ok: during daemonize, dup2 failed. + /* LCOV_EXCL_STOP */ + } + if (nullfd > 2) + close(nullfd); + /* signal success */ + if (write(daemon_filedes[1], &c, sizeof(char)) != sizeof(char)) { + log_err(LD_GENERAL,"write failed. Exiting."); + } + close(daemon_filedes[1]); +} +#else /* !(!defined(_WIN32)) */ +/* defined(_WIN32) */ +void +start_daemon(void) +{ +} +void +finish_daemon(const char *cp) +{ + (void)cp; +} +#endif /* !defined(_WIN32) */ diff --git a/src/lib/process/daemon.h b/src/lib/process/daemon.h new file mode 100644 index 0000000000..48a65b22e6 --- /dev/null +++ b/src/lib/process/daemon.h @@ -0,0 +1,12 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_DAEMON_H +#define TOR_DAEMON_H + +void start_daemon(void); +void finish_daemon(const char *desired_cwd); + +#endif diff --git a/src/lib/process/env.c b/src/lib/process/env.c new file mode 100644 index 0000000000..731f609ac1 --- /dev/null +++ b/src/lib/process/env.c @@ -0,0 +1,219 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/env.h" + +#include "lib/malloc/util_malloc.h" +#include "lib/ctime/di_ops.h" +#include "lib/container/smartlist.h" +#include "lib/log/util_bug.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> +#ifdef HAVE_CRT_EXTERNS_H +/* For _NSGetEnviron on macOS */ +#include <crt_externs.h> +#endif + +#ifndef HAVE__NSGETENVIRON +#ifndef HAVE_EXTERN_ENVIRON_DECLARED +/* Some platforms declare environ under some circumstances, others don't. */ +#ifndef RUNNING_DOXYGEN +extern char **environ; +#endif +#endif /* !defined(HAVE_EXTERN_ENVIRON_DECLARED) */ +#endif /* !defined(HAVE__NSGETENVIRON) */ + +/** Return the current environment. This is a portable replacement for + * 'environ'. */ +char ** +get_environment(void) +{ +#ifdef HAVE__NSGETENVIRON + /* This is for compatibility between OSX versions. Otherwise (for example) + * when we do a mostly-static build on OSX 10.7, the resulting binary won't + * work on OSX 10.6. */ + return *_NSGetEnviron(); +#else /* !(defined(HAVE__NSGETENVIRON)) */ + return environ; +#endif /* defined(HAVE__NSGETENVIRON) */ +} + +/** Helper: return the number of characters in <b>s</b> preceding the first + * occurrence of <b>ch</b>. If <b>ch</b> does not occur in <b>s</b>, return + * the length of <b>s</b>. Should be equivalent to strspn(s, "ch"). */ +static inline size_t +str_num_before(const char *s, char ch) +{ + const char *cp = strchr(s, ch); + if (cp) + return cp - s; + else + return strlen(s); +} + +/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b> + * to have the same name as strings in a process's environment. */ +int +environment_variable_names_equal(const char *s1, const char *s2) +{ + size_t s1_name_len = str_num_before(s1, '='); + size_t s2_name_len = str_num_before(s2, '='); + + return (s1_name_len == s2_name_len && + tor_memeq(s1, s2, s1_name_len)); +} + +/** Free <b>env</b> (assuming it was produced by + * process_environment_make). */ +void +process_environment_free_(process_environment_t *env) +{ + if (env == NULL) return; + + /* As both an optimization hack to reduce consing on Unixoid systems + * and a nice way to ensure that some otherwise-Windows-specific + * code will always get tested before changes to it get merged, the + * strings which env->unixoid_environment_block points to are packed + * into env->windows_environment_block. */ + tor_free(env->unixoid_environment_block); + tor_free(env->windows_environment_block); + + tor_free(env); +} + +/** Make a process_environment_t containing the environment variables + * specified in <b>env_vars</b> (as C strings of the form + * "NAME=VALUE"). */ +process_environment_t * +process_environment_make(struct smartlist_t *env_vars) +{ + process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t)); + int n_env_vars = smartlist_len(env_vars); + int i; + size_t total_env_length; + smartlist_t *env_vars_sorted; + + tor_assert(n_env_vars + 1 != 0); + env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *)); + /* env->unixoid_environment_block is already NULL-terminated, + * because we assume that NULL == 0 (and check that during compilation). */ + + total_env_length = 1; /* terminating NUL of terminating empty string */ + for (i = 0; i < n_env_vars; ++i) { + const char *s = smartlist_get(env_vars, (int)i); + size_t slen = strlen(s); + + tor_assert(slen + 1 != 0); + tor_assert(slen + 1 < SIZE_MAX - total_env_length); + total_env_length += slen + 1; + } + + env->windows_environment_block = tor_malloc_zero(total_env_length); + /* env->windows_environment_block is already + * (NUL-terminated-empty-string)-terminated. */ + + /* Some versions of Windows supposedly require that environment + * blocks be sorted. Or maybe some Windows programs (or their + * runtime libraries) fail to look up strings in non-sorted + * environment blocks. + * + * Also, sorting strings makes it easy to find duplicate environment + * variables and environment-variable strings without an '=' on all + * OSes, and they can cause badness. Let's complain about those. */ + env_vars_sorted = smartlist_new(); + smartlist_add_all(env_vars_sorted, env_vars); + smartlist_sort_strings(env_vars_sorted); + + /* Now copy the strings into the environment blocks. */ + { + char *cp = env->windows_environment_block; + const char *prev_env_var = NULL; + + for (i = 0; i < n_env_vars; ++i) { + const char *s = smartlist_get(env_vars_sorted, (int)i); + size_t slen = strlen(s); + size_t s_name_len = str_num_before(s, '='); + + if (s_name_len == slen) { + log_warn(LD_GENERAL, + "Preparing an environment containing a variable " + "without a value: %s", + s); + } + if (prev_env_var != NULL && + environment_variable_names_equal(s, prev_env_var)) { + log_warn(LD_GENERAL, + "Preparing an environment containing two variables " + "with the same name: %s and %s", + prev_env_var, s); + } + + prev_env_var = s; + + /* Actually copy the string into the environment. */ + memcpy(cp, s, slen+1); + env->unixoid_environment_block[i] = cp; + cp += slen+1; + } + + tor_assert(cp == env->windows_environment_block + total_env_length - 1); + } + + smartlist_free(env_vars_sorted); + + return env; +} + +/** Return a newly allocated smartlist containing every variable in + * this process's environment, as a NUL-terminated string of the form + * "NAME=VALUE". Note that on some/many/most/all OSes, the parent + * process can put strings not of that form in our environment; + * callers should try to not get crashed by that. + * + * The returned strings are heap-allocated, and must be freed by the + * caller. */ +struct smartlist_t * +get_current_process_environment_variables(void) +{ + smartlist_t *sl = smartlist_new(); + + char **environ_tmp; /* Not const char ** ? Really? */ + for (environ_tmp = get_environment(); *environ_tmp; ++environ_tmp) { + smartlist_add_strdup(sl, *environ_tmp); + } + + return sl; +} + +/** For each string s in <b>env_vars</b> such that + * environment_variable_names_equal(s, <b>new_var</b>), remove it; if + * <b>free_p</b> is non-zero, call <b>free_old</b>(s). If + * <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */ +void +set_environment_variable_in_smartlist(struct smartlist_t *env_vars, + const char *new_var, + void (*free_old)(void*), + int free_p) +{ + SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) { + if (environment_variable_names_equal(s, new_var)) { + SMARTLIST_DEL_CURRENT(env_vars, s); + if (free_p) { + free_old((void *)s); + } + } + } SMARTLIST_FOREACH_END(s); + + if (strchr(new_var, '=') != NULL) { + smartlist_add(env_vars, (void *)new_var); + } +} diff --git a/src/lib/process/env.h b/src/lib/process/env.h new file mode 100644 index 0000000000..f22599355d --- /dev/null +++ b/src/lib/process/env.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_ENV_H +#define TOR_ENV_H + +char **get_environment(void); + +struct smartlist_t; + +int environment_variable_names_equal(const char *s1, const char *s2); + +/* DOCDOC process_environment_t */ +typedef struct process_environment_t { + /** A pointer to a sorted empty-string-terminated sequence of + * NUL-terminated strings of the form "NAME=VALUE". */ + char *windows_environment_block; + /** A pointer to a NULL-terminated array of pointers to + * NUL-terminated strings of the form "NAME=VALUE". */ + char **unixoid_environment_block; +} process_environment_t; + +process_environment_t *process_environment_make(struct smartlist_t *env_vars); +void process_environment_free_(process_environment_t *env); +#define process_environment_free(env) \ + FREE_AND_NULL(process_environment_t, process_environment_free_, (env)) + +struct smartlist_t *get_current_process_environment_variables(void); + +void set_environment_variable_in_smartlist(struct smartlist_t *env_vars, + const char *new_var, + void (*free_old)(void*), + int free_p); +#endif diff --git a/src/lib/process/include.am b/src/lib/process/include.am new file mode 100644 index 0000000000..c6cc3a6699 --- /dev/null +++ b/src/lib/process/include.am @@ -0,0 +1,29 @@ + +noinst_LIBRARIES += src/lib/libtor-process.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-process-testing.a +endif + +src_lib_libtor_process_a_SOURCES = \ + src/lib/process/daemon.c \ + src/lib/process/env.c \ + src/lib/process/pidfile.c \ + src/lib/process/restrict.c \ + src/lib/process/setuid.c \ + src/lib/process/subprocess.c \ + src/lib/process/waitpid.c + +src_lib_libtor_process_testing_a_SOURCES = \ + $(src_lib_libtor_process_a_SOURCES) +src_lib_libtor_process_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_process_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/process/daemon.h \ + src/lib/process/env.h \ + src/lib/process/pidfile.h \ + src/lib/process/restrict.h \ + src/lib/process/setuid.h \ + src/lib/process/subprocess.h \ + src/lib/process/waitpid.h diff --git a/src/lib/process/pidfile.c b/src/lib/process/pidfile.c new file mode 100644 index 0000000000..f016f21697 --- /dev/null +++ b/src/lib/process/pidfile.c @@ -0,0 +1,47 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/pidfile.h" + +#include "lib/log/torlog.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <errno.h> +#include <stdio.h> +#include <string.h> + +/** Write the current process ID, followed by NL, into <b>filename</b>. + * Return 0 on success, -1 on failure. + */ +int +write_pidfile(const char *filename) +{ + FILE *pidfile; + + if ((pidfile = fopen(filename, "w")) == NULL) { + log_warn(LD_FS, "Unable to open \"%s\" for writing: %s", filename, + strerror(errno)); + return -1; + } else { +#ifdef _WIN32 + int pid = (int)_getpid(); +#else + int pid = (int)getpid(); +#endif + int rv = 0; + if (fprintf(pidfile, "%d\n", pid) < 0) + rv = -1; + if (fclose(pidfile) < 0) + rv = -1; + return rv; + } +} diff --git a/src/lib/process/pidfile.h b/src/lib/process/pidfile.h new file mode 100644 index 0000000000..c85cd1905e --- /dev/null +++ b/src/lib/process/pidfile.h @@ -0,0 +1,11 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_PIDFILE_H +#define TOR_PIDFILE_H + +int write_pidfile(const char *filename); + +#endif diff --git a/src/lib/process/restrict.c b/src/lib/process/restrict.c new file mode 100644 index 0000000000..bb44cc3d15 --- /dev/null +++ b/src/lib/process/restrict.c @@ -0,0 +1,280 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/restrict.h" +#include "lib/intmath/cmp.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/net/socket.h" + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/* We only use the linux prctl for now. There is no Win32 support; this may + * also work on various BSD systems and Mac OS X - send testing feedback! + * + * On recent Gnu/Linux kernels it is possible to create a system-wide policy + * that will prevent non-root processes from attaching to other processes + * unless they are the parent process; thus gdb can attach to programs that + * they execute but they cannot attach to other processes running as the same + * user. The system wide policy may be set with the sysctl + * kernel.yama.ptrace_scope or by inspecting + * /proc/sys/kernel/yama/ptrace_scope and it is 1 by default on Ubuntu 11.04. + * + * This ptrace scope will be ignored on Gnu/Linux for users with + * CAP_SYS_PTRACE and so it is very likely that root will still be able to + * attach to the Tor process. + */ +/** Attempt to disable debugger attachment: return 1 on success, -1 on + * failure, and 0 if we don't know how to try on this platform. */ +int +tor_disable_debugger_attach(void) +{ + int r = -1; + log_debug(LD_CONFIG, + "Attemping to disable debugger attachment to Tor for " + "unprivileged users."); +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) \ + && defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) +#define TRIED_TO_DISABLE + r = prctl(PR_SET_DUMPABLE, 0); +#elif defined(__APPLE__) && defined(PT_DENY_ATTACH) +#define TRIED_TO_ATTACH + r = ptrace(PT_DENY_ATTACH, 0, 0, 0); +#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) ... || ... */ + + // XXX: TODO - Mac OS X has dtrace and this may be disabled. + // XXX: TODO - Windows probably has something similar +#ifdef TRIED_TO_DISABLE + if (r == 0) { + log_debug(LD_CONFIG,"Debugger attachment disabled for " + "unprivileged users."); + return 1; + } else { + log_warn(LD_CONFIG, "Unable to disable debugger attaching: %s", + strerror(errno)); + } +#endif /* defined(TRIED_TO_DISABLE) */ +#undef TRIED_TO_DISABLE + return r; +} + +#if defined(HAVE_MLOCKALL) && HAVE_DECL_MLOCKALL && defined(RLIMIT_MEMLOCK) +#define HAVE_UNIX_MLOCKALL +#endif + +#ifdef HAVE_UNIX_MLOCKALL +/** Attempt to raise the current and max rlimit to infinity for our process. + * This only needs to be done once and can probably only be done when we have + * not already dropped privileges. + */ +static int +tor_set_max_memlock(void) +{ + /* Future consideration for Windows is probably SetProcessWorkingSetSize + * This is similar to setting the memory rlimit of RLIMIT_MEMLOCK + * http://msdn.microsoft.com/en-us/library/ms686234(VS.85).aspx + */ + + struct rlimit limit; + + /* RLIM_INFINITY is -1 on some platforms. */ + limit.rlim_cur = RLIM_INFINITY; + limit.rlim_max = RLIM_INFINITY; + + if (setrlimit(RLIMIT_MEMLOCK, &limit) == -1) { + if (errno == EPERM) { + log_warn(LD_GENERAL, "You appear to lack permissions to change memory " + "limits. Are you root?"); + } + log_warn(LD_GENERAL, "Unable to raise RLIMIT_MEMLOCK: %s", + strerror(errno)); + return -1; + } + + return 0; +} +#endif /* defined(HAVE_UNIX_MLOCKALL) */ + +/** Attempt to lock all current and all future memory pages. + * This should only be called once and while we're privileged. + * Like mlockall() we return 0 when we're successful and -1 when we're not. + * Unlike mlockall() we return 1 if we've already attempted to lock memory. + */ +int +tor_mlockall(void) +{ + static int memory_lock_attempted = 0; + + if (memory_lock_attempted) { + return 1; + } + + memory_lock_attempted = 1; + + /* + * Future consideration for Windows may be VirtualLock + * VirtualLock appears to implement mlock() but not mlockall() + * + * http://msdn.microsoft.com/en-us/library/aa366895(VS.85).aspx + */ + +#ifdef HAVE_UNIX_MLOCKALL + if (tor_set_max_memlock() == 0) { + log_debug(LD_GENERAL, "RLIMIT_MEMLOCK is now set to RLIM_INFINITY."); + } + + if (mlockall(MCL_CURRENT|MCL_FUTURE) == 0) { + log_info(LD_GENERAL, "Insecure OS paging is effectively disabled."); + return 0; + } else { + if (errno == ENOSYS) { + /* Apple - it's 2009! I'm looking at you. Grrr. */ + log_notice(LD_GENERAL, "It appears that mlockall() is not available on " + "your platform."); + } else if (errno == EPERM) { + log_notice(LD_GENERAL, "It appears that you lack the permissions to " + "lock memory. Are you root?"); + } + log_notice(LD_GENERAL, "Unable to lock all current and future memory " + "pages: %s", strerror(errno)); + return -1; + } +#else /* !(defined(HAVE_UNIX_MLOCKALL)) */ + log_warn(LD_GENERAL, "Unable to lock memory pages. mlockall() unsupported?"); + return -1; +#endif /* defined(HAVE_UNIX_MLOCKALL) */ +} + +/** Number of extra file descriptors to keep in reserve beyond those that we + * tell Tor it's allowed to use. */ +#define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */ + +/** Learn the maximum allowed number of file descriptors, and tell the + * system we want to use up to that number. (Some systems have a low soft + * limit, and let us set it higher.) We compute this by finding the largest + * number that we can use. + * + * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER), + * return -1 and <b>max_out</b> is untouched. + * + * If we can't find a number greater than or equal to <b>limit</b>, then we + * fail by returning -1 and <b>max_out</b> is untouched. + * + * If we are unable to set the limit value because of setrlimit() failing, + * return 0 and <b>max_out</b> is set to the current maximum value returned + * by getrlimit(). + * + * Otherwise, return 0 and store the maximum we found inside <b>max_out</b> + * and set <b>max_sockets</b> with that value as well.*/ +int +set_max_file_descriptors(rlim_t limit, int *max_out) +{ + if (limit < ULIMIT_BUFFER) { + log_warn(LD_CONFIG, + "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER); + return -1; + } + + /* Define some maximum connections values for systems where we cannot + * automatically determine a limit. Re Cygwin, see + * http://archives.seul.org/or/talk/Aug-2006/msg00210.html + * For an iPhone, 9999 should work. For Windows and all other unknown + * systems we use 15000 as the default. */ +#ifndef HAVE_GETRLIMIT +#if defined(CYGWIN) || defined(__CYGWIN__) + const char *platform = "Cygwin"; + const unsigned long MAX_CONNECTIONS = 3200; +#elif defined(_WIN32) + const char *platform = "Windows"; + const unsigned long MAX_CONNECTIONS = 15000; +#else + const char *platform = "unknown platforms with no getrlimit()"; + const unsigned long MAX_CONNECTIONS = 15000; +#endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */ + log_fn(LOG_INFO, LD_NET, + "This platform is missing getrlimit(). Proceeding."); + if (limit > MAX_CONNECTIONS) { + log_warn(LD_CONFIG, + "We do not support more than %lu file descriptors " + "on %s. Tried to raise to %lu.", + (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit); + return -1; + } + limit = MAX_CONNECTIONS; +#else /* !(!defined(HAVE_GETRLIMIT)) */ + struct rlimit rlim; + + if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { + log_warn(LD_NET, "Could not get maximum number of file descriptors: %s", + strerror(errno)); + return -1; + } + if (rlim.rlim_max < limit) { + log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're " + "limited to %lu. Please change your ulimit -n.", + (unsigned long)limit, (unsigned long)rlim.rlim_max); + return -1; + } + + if (rlim.rlim_max > rlim.rlim_cur) { + log_info(LD_NET,"Raising max file descriptors from %lu to %lu.", + (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max); + } + /* Set the current limit value so if the attempt to set the limit to the + * max fails at least we'll have a valid value of maximum sockets. */ + *max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER; + set_max_sockets(*max_out); + rlim.rlim_cur = rlim.rlim_max; + + if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) { + int couldnt_set = 1; + const int setrlimit_errno = errno; +#ifdef OPEN_MAX + uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER; + if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) { + /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is + * full of nasty lies. I'm looking at you, OSX 10.5.... */ + rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur); + if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) { + if (rlim.rlim_cur < (rlim_t)limit) { + log_warn(LD_CONFIG, "We are limited to %lu file descriptors by " + "OPEN_MAX (%lu), and ConnLimit is %lu. Changing " + "ConnLimit; sorry.", + (unsigned long)try_limit, (unsigned long)OPEN_MAX, + (unsigned long)limit); + } else { + log_info(LD_CONFIG, "Dropped connection limit to %lu based on " + "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit " + "lied to us.", + (unsigned long)try_limit, (unsigned long)OPEN_MAX, + (unsigned long)rlim.rlim_max); + } + couldnt_set = 0; + } + } +#endif /* defined(OPEN_MAX) */ + if (couldnt_set) { + log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s", + strerror(setrlimit_errno)); + } + } + /* leave some overhead for logs, etc, */ + limit = rlim.rlim_cur; +#endif /* !defined(HAVE_GETRLIMIT) */ + + if (limit > INT_MAX) + limit = INT_MAX; + tor_assert(max_out); + *max_out = (int)limit - ULIMIT_BUFFER; + set_max_sockets(*max_out); + + return 0; +} diff --git a/src/lib/process/restrict.h b/src/lib/process/restrict.h new file mode 100644 index 0000000000..c7f76f8233 --- /dev/null +++ b/src/lib/process/restrict.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file waitpid.h + * \brief Headers for waitpid.c + **/ + +#ifndef TOR_RESTRICT_H +#define TOR_RESTRICT_H + +#include "orconfig.h" +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +int tor_disable_debugger_attach(void); +int tor_mlockall(void); + +#if !defined(HAVE_RLIM_T) +typedef unsigned long rlim_t; +#endif +int set_max_file_descriptors(rlim_t limit, int *max_out); + +#endif /* !defined(TOR_RESTRICT_H) */ diff --git a/src/lib/process/setuid.c b/src/lib/process/setuid.c new file mode 100644 index 0000000000..fa1cdc0f3f --- /dev/null +++ b/src/lib/process/setuid.c @@ -0,0 +1,381 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/process/setuid.h" + +#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_CAP_SET_PROC) +#define HAVE_LINUX_CAPABILITIES +#endif + +#include "lib/container/smartlist.h" +#include "lib/fs/userdb.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_GRP_H +#include <grp.h> +#endif +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#ifdef HAVE_SYS_CAPABILITY_H +#include <sys/capability.h> +#endif +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif + +#include <errno.h> +#include <string.h> + +#ifndef _WIN32 +/** Log details of current user and group credentials. Return 0 on + * success. Logs and return -1 on failure. + */ +static int +log_credential_status(void) +{ +/** Log level to use when describing non-error UID/GID status. */ +#define CREDENTIAL_LOG_LEVEL LOG_INFO + /* Real, effective and saved UIDs */ + uid_t ruid, euid, suid; + /* Read, effective and saved GIDs */ + gid_t rgid, egid, sgid; + /* Supplementary groups */ + gid_t *sup_gids = NULL; + int sup_gids_size; + /* Number of supplementary groups */ + int ngids; + + /* log UIDs */ +#ifdef HAVE_GETRESUID + if (getresuid(&ruid, &euid, &suid) != 0 ) { + log_warn(LD_GENERAL, "Error getting changed UIDs: %s", strerror(errno)); + return -1; + } else { + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "UID is %u (real), %u (effective), %u (saved)", + (unsigned)ruid, (unsigned)euid, (unsigned)suid); + } +#else /* !(defined(HAVE_GETRESUID)) */ + /* getresuid is not present on MacOS X, so we can't get the saved (E)UID */ + ruid = getuid(); + euid = geteuid(); + (void)suid; + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "UID is %u (real), %u (effective), unknown (saved)", + (unsigned)ruid, (unsigned)euid); +#endif /* defined(HAVE_GETRESUID) */ + + /* log GIDs */ +#ifdef HAVE_GETRESGID + if (getresgid(&rgid, &egid, &sgid) != 0 ) { + log_warn(LD_GENERAL, "Error getting changed GIDs: %s", strerror(errno)); + return -1; + } else { + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "GID is %u (real), %u (effective), %u (saved)", + (unsigned)rgid, (unsigned)egid, (unsigned)sgid); + } +#else /* !(defined(HAVE_GETRESGID)) */ + /* getresgid is not present on MacOS X, so we can't get the saved (E)GID */ + rgid = getgid(); + egid = getegid(); + (void)sgid; + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, + "GID is %u (real), %u (effective), unknown (saved)", + (unsigned)rgid, (unsigned)egid); +#endif /* defined(HAVE_GETRESGID) */ + + /* log supplementary groups */ + sup_gids_size = 64; + sup_gids = tor_calloc(64, sizeof(gid_t)); + while ((ngids = getgroups(sup_gids_size, sup_gids)) < 0 && + errno == EINVAL && + sup_gids_size < NGROUPS_MAX) { + sup_gids_size *= 2; + sup_gids = tor_reallocarray(sup_gids, sizeof(gid_t), sup_gids_size); + } + + if (ngids < 0) { + log_warn(LD_GENERAL, "Error getting supplementary GIDs: %s", + strerror(errno)); + tor_free(sup_gids); + return -1; + } else { + int i, retval = 0; + char *s = NULL; + smartlist_t *elts = smartlist_new(); + + for (i = 0; i<ngids; i++) { + smartlist_add_asprintf(elts, "%u", (unsigned)sup_gids[i]); + } + + s = smartlist_join_strings(elts, " ", 0, NULL); + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Supplementary groups are: %s",s); + + tor_free(s); + SMARTLIST_FOREACH(elts, char *, cp, tor_free(cp)); + smartlist_free(elts); + tor_free(sup_gids); + + return retval; + } + + return 0; +} +#endif /* !defined(_WIN32) */ + +/** Return true iff we were compiled with capability support, and capabilities + * seem to work. **/ +int +have_capability_support(void) +{ +#ifdef HAVE_LINUX_CAPABILITIES + cap_t caps = cap_get_proc(); + if (caps == NULL) + return 0; + cap_free(caps); + return 1; +#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ + return 0; +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ +} + +#ifdef HAVE_LINUX_CAPABILITIES +/** Helper. Drop all capabilities but a small set, and set PR_KEEPCAPS as + * appropriate. + * + * If pre_setuid, retain only CAP_NET_BIND_SERVICE, CAP_SETUID, and + * CAP_SETGID, and use PR_KEEPCAPS to ensure that capabilities persist across + * setuid(). + * + * If not pre_setuid, retain only CAP_NET_BIND_SERVICE, and disable + * PR_KEEPCAPS. + * + * Return 0 on success, and -1 on failure. + */ +static int +drop_capabilities(int pre_setuid) +{ + /* We keep these three capabilities, and these only, as we setuid. + * After we setuid, we drop all but the first. */ + const cap_value_t caplist[] = { + CAP_NET_BIND_SERVICE, CAP_SETUID, CAP_SETGID + }; + const char *where = pre_setuid ? "pre-setuid" : "post-setuid"; + const int n_effective = pre_setuid ? 3 : 1; + const int n_permitted = pre_setuid ? 3 : 1; + const int n_inheritable = 1; + const int keepcaps = pre_setuid ? 1 : 0; + + /* Sets whether we keep capabilities across a setuid. */ + if (prctl(PR_SET_KEEPCAPS, keepcaps) < 0) { + log_warn(LD_CONFIG, "Unable to call prctl() %s: %s", + where, strerror(errno)); + return -1; + } + + cap_t caps = cap_get_proc(); + if (!caps) { + log_warn(LD_CONFIG, "Unable to call cap_get_proc() %s: %s", + where, strerror(errno)); + return -1; + } + cap_clear(caps); + + cap_set_flag(caps, CAP_EFFECTIVE, n_effective, caplist, CAP_SET); + cap_set_flag(caps, CAP_PERMITTED, n_permitted, caplist, CAP_SET); + cap_set_flag(caps, CAP_INHERITABLE, n_inheritable, caplist, CAP_SET); + + int r = cap_set_proc(caps); + cap_free(caps); + if (r < 0) { + log_warn(LD_CONFIG, "No permission to set capabilities %s: %s", + where, strerror(errno)); + return -1; + } + + return 0; +} +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ + +/** Call setuid and setgid to run as <b>user</b> and switch to their + * primary group. Return 0 on success. On failure, log and return -1. + * + * If SWITCH_ID_KEEP_BINDLOW is set in 'flags', try to use the capability + * system to retain the abilitity to bind low ports. + * + * If SWITCH_ID_WARN_IF_NO_CAPS is set in flags, also warn if we have + * don't have capability support. + */ +int +switch_id(const char *user, const unsigned flags) +{ +#ifndef _WIN32 + const struct passwd *pw = NULL; + uid_t old_uid; + gid_t old_gid; + static int have_already_switched_id = 0; + const int keep_bindlow = !!(flags & SWITCH_ID_KEEP_BINDLOW); + const int warn_if_no_caps = !!(flags & SWITCH_ID_WARN_IF_NO_CAPS); + + tor_assert(user); + + if (have_already_switched_id) + return 0; + + /* Log the initial credential state */ + if (log_credential_status()) + return -1; + + log_fn(CREDENTIAL_LOG_LEVEL, LD_GENERAL, "Changing user and groups"); + + /* Get old UID/GID to check if we changed correctly */ + old_uid = getuid(); + old_gid = getgid(); + + /* Lookup the user and group information, if we have a problem, bail out. */ + pw = tor_getpwnam(user); + if (pw == NULL) { + log_warn(LD_CONFIG, "Error setting configured user: %s not found", user); + return -1; + } + +#ifdef HAVE_LINUX_CAPABILITIES + (void) warn_if_no_caps; + if (keep_bindlow) { + if (drop_capabilities(1)) + return -1; + } +#else /* !(defined(HAVE_LINUX_CAPABILITIES)) */ + (void) keep_bindlow; + if (warn_if_no_caps) { + log_warn(LD_CONFIG, "KeepBindCapabilities set, but no capability support " + "on this system."); + } +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ + + /* Properly switch egid,gid,euid,uid here or bail out */ + if (setgroups(1, &pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting groups to gid %d: \"%s\".", + (int)pw->pw_gid, strerror(errno)); + if (old_uid == pw->pw_uid) { + log_warn(LD_GENERAL, "Tor is already running as %s. You do not need " + "the \"User\" option if you are already running as the user " + "you want to be. (If you did not set the User option in your " + "torrc, check whether it was specified on the command line " + "by a startup script.)", user); + } else { + log_warn(LD_GENERAL, "If you set the \"User\" option, you must start Tor" + " as root."); + } + return -1; + } + + if (setegid(pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting egid to %d: %s", + (int)pw->pw_gid, strerror(errno)); + return -1; + } + + if (setgid(pw->pw_gid)) { + log_warn(LD_GENERAL, "Error setting gid to %d: %s", + (int)pw->pw_gid, strerror(errno)); + return -1; + } + + if (setuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured uid to %s (%d): %s", + user, (int)pw->pw_uid, strerror(errno)); + return -1; + } + + if (seteuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured euid to %s (%d): %s", + user, (int)pw->pw_uid, strerror(errno)); + return -1; + } + + /* This is how OpenBSD rolls: + if (setgroups(1, &pw->pw_gid) || setegid(pw->pw_gid) || + setgid(pw->pw_gid) || setuid(pw->pw_uid) || seteuid(pw->pw_uid)) { + setgid(pw->pw_gid) || seteuid(pw->pw_uid) || setuid(pw->pw_uid)) { + log_warn(LD_GENERAL, "Error setting configured UID/GID: %s", + strerror(errno)); + return -1; + } + */ + + /* We've properly switched egid, gid, euid, uid, and supplementary groups if + * we're here. */ +#ifdef HAVE_LINUX_CAPABILITIES + if (keep_bindlow) { + if (drop_capabilities(0)) + return -1; + } +#endif /* defined(HAVE_LINUX_CAPABILITIES) */ + +#if !defined(CYGWIN) && !defined(__CYGWIN__) + /* If we tried to drop privilege to a group/user other than root, attempt to + * restore root (E)(U|G)ID, and abort if the operation succeeds */ + + /* Only check for privilege dropping if we were asked to be non-root */ + if (pw->pw_uid) { + /* Try changing GID/EGID */ + if (pw->pw_gid != old_gid && + (setgid(old_gid) != -1 || setegid(old_gid) != -1)) { + log_warn(LD_GENERAL, "Was able to restore group credentials even after " + "switching GID: this means that the setgid code didn't work."); + return -1; + } + + /* Try changing UID/EUID */ + if (pw->pw_uid != old_uid && + (setuid(old_uid) != -1 || seteuid(old_uid) != -1)) { + log_warn(LD_GENERAL, "Was able to restore user credentials even after " + "switching UID: this means that the setuid code didn't work."); + return -1; + } + } +#endif /* !defined(CYGWIN) && !defined(__CYGWIN__) */ + + /* Check what really happened */ + if (log_credential_status()) { + return -1; + } + + have_already_switched_id = 1; /* mark success so we never try again */ + +#if defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && \ + defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE) + if (pw->pw_uid) { + /* Re-enable core dumps if we're not running as root. */ + log_info(LD_CONFIG, "Re-enabling coredumps"); + if (prctl(PR_SET_DUMPABLE, 1)) { + log_warn(LD_CONFIG, "Unable to re-enable coredumps: %s",strerror(errno)); + } + } +#endif /* defined(__linux__) && defined(HAVE_SYS_PRCTL_H) && ... */ + return 0; + +#else /* !(!defined(_WIN32)) */ + (void)user; + (void)flags; + + log_warn(LD_CONFIG, "Switching users is unsupported on your OS."); + return -1; +#endif /* !defined(_WIN32) */ +} diff --git a/src/lib/process/setuid.h b/src/lib/process/setuid.h new file mode 100644 index 0000000000..61aeefe1b7 --- /dev/null +++ b/src/lib/process/setuid.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SETUID_H +#define TOR_SETUID_H + +int have_capability_support(void); + +/** Flag for switch_id; see switch_id() for documentation */ +#define SWITCH_ID_KEEP_BINDLOW (1<<0) +/** Flag for switch_id; see switch_id() for documentation */ +#define SWITCH_ID_WARN_IF_NO_CAPS (1<<1) +int switch_id(const char *user, unsigned flags); + +#endif diff --git a/src/lib/process/subprocess.c b/src/lib/process/subprocess.c new file mode 100644 index 0000000000..516494d105 --- /dev/null +++ b/src/lib/process/subprocess.c @@ -0,0 +1,1231 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#define SUBPROCESS_PRIVATE +#include "lib/process/subprocess.h" + +#include "lib/container/smartlist.h" +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" +#include "lib/malloc/util_malloc.h" +#include "lib/process/env.h" +#include "lib/process/waitpid.h" +#include "lib/string/compat_ctype.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_PRCTL_H +#include <sys/prctl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#include <errno.h> +#include <string.h> + +/** Format a single argument for being put on a Windows command line. + * Returns a newly allocated string */ +static char * +format_win_cmdline_argument(const char *arg) +{ + char *formatted_arg; + char need_quotes; + const char *c; + int i; + int bs_counter = 0; + /* Backslash we can point to when one is inserted into the string */ + const char backslash = '\\'; + + /* Smartlist of *char */ + smartlist_t *arg_chars; + arg_chars = smartlist_new(); + + /* Quote string if it contains whitespace or is empty */ + need_quotes = (strchr(arg, ' ') || strchr(arg, '\t') || '\0' == arg[0]); + + /* Build up smartlist of *chars */ + for (c=arg; *c != '\0'; c++) { + if ('"' == *c) { + /* Double up backslashes preceding a quote */ + for (i=0; i<(bs_counter*2); i++) + smartlist_add(arg_chars, (void*)&backslash); + bs_counter = 0; + /* Escape the quote */ + smartlist_add(arg_chars, (void*)&backslash); + smartlist_add(arg_chars, (void*)c); + } else if ('\\' == *c) { + /* Count backslashes until we know whether to double up */ + bs_counter++; + } else { + /* Don't double up slashes preceding a non-quote */ + for (i=0; i<bs_counter; i++) + smartlist_add(arg_chars, (void*)&backslash); + bs_counter = 0; + smartlist_add(arg_chars, (void*)c); + } + } + /* Don't double up trailing backslashes */ + for (i=0; i<bs_counter; i++) + smartlist_add(arg_chars, (void*)&backslash); + + /* Allocate space for argument, quotes (if needed), and terminator */ + const size_t formatted_arg_len = smartlist_len(arg_chars) + + (need_quotes ? 2 : 0) + 1; + formatted_arg = tor_malloc_zero(formatted_arg_len); + + /* Add leading quote */ + i=0; + if (need_quotes) + formatted_arg[i++] = '"'; + + /* Add characters */ + SMARTLIST_FOREACH(arg_chars, char*, ch, + { + formatted_arg[i++] = *ch; + }); + + /* Add trailing quote */ + if (need_quotes) + formatted_arg[i++] = '"'; + formatted_arg[i] = '\0'; + + smartlist_free(arg_chars); + return formatted_arg; +} + +/** Format a command line for use on Windows, which takes the command as a + * string rather than string array. Follows the rules from "Parsing C++ + * Command-Line Arguments" in MSDN. Algorithm based on list2cmdline in the + * Python subprocess module. Returns a newly allocated string */ +char * +tor_join_win_cmdline(const char *argv[]) +{ + smartlist_t *argv_list; + char *joined_argv; + int i; + + /* Format each argument and put the result in a smartlist */ + argv_list = smartlist_new(); + for (i=0; argv[i] != NULL; i++) { + smartlist_add(argv_list, (void *)format_win_cmdline_argument(argv[i])); + } + + /* Join the arguments with whitespace */ + joined_argv = smartlist_join_strings(argv_list, " ", 0, NULL); + + /* Free the newly allocated arguments, and the smartlist */ + SMARTLIST_FOREACH(argv_list, char *, arg, + { + tor_free(arg); + }); + smartlist_free(argv_list); + + return joined_argv; +} + +#ifndef _WIN32 +/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in + * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler + * safe. + * + * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE+1 bytes available. + * + * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded + * with spaces. CHILD_STATE indicates where + * in the process of starting the child process did the failure occur (see + * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of + * errno when the failure occurred. + * + * On success return the number of characters added to hex_errno, not counting + * the terminating NUL; return -1 on error. + */ +STATIC int +format_helper_exit_status(unsigned char child_state, int saved_errno, + char *hex_errno) +{ + unsigned int unsigned_errno; + int written, left; + char *cur; + size_t i; + int res = -1; + + /* Fill hex_errno with spaces, and a trailing newline (memset may + not be signal handler safe, so we can't use it) */ + for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++) + hex_errno[i] = ' '; + hex_errno[HEX_ERRNO_SIZE - 1] = '\n'; + + /* Convert errno to be unsigned for hex conversion */ + if (saved_errno < 0) { + // Avoid overflow on the cast to unsigned int when result is INT_MIN + // by adding 1 to the signed int negative value, + // then, after it has been negated and cast to unsigned, + // adding the original 1 back (the double-addition is intentional). + // Otherwise, the cast to signed could cause a temporary int + // to equal INT_MAX + 1, which is undefined. + unsigned_errno = ((unsigned int) -(saved_errno + 1)) + 1; + } else { + unsigned_errno = (unsigned int) saved_errno; + } + + /* + * Count how many chars of space we have left, and keep a pointer into the + * current point in the buffer. + */ + left = HEX_ERRNO_SIZE+1; + cur = hex_errno; + + /* Emit child_state */ + written = format_hex_number_sigsafe(child_state, cur, left); + + if (written <= 0) + goto err; + + /* Adjust left and cur */ + left -= written; + cur += written; + if (left <= 0) + goto err; + + /* Now the '/' */ + *cur = '/'; + + /* Adjust left and cur */ + ++cur; + --left; + if (left <= 0) + goto err; + + /* Need minus? */ + if (saved_errno < 0) { + *cur = '-'; + ++cur; + --left; + if (left <= 0) + goto err; + } + + /* Emit unsigned_errno */ + written = format_hex_number_sigsafe(unsigned_errno, cur, left); + + if (written <= 0) + goto err; + + /* Adjust left and cur */ + left -= written; + cur += written; + + /* Check that we have enough space left for a newline and a NUL */ + if (left <= 1) + goto err; + + /* Emit the newline and NUL */ + *cur++ = '\n'; + *cur++ = '\0'; + + res = (int)(cur - hex_errno - 1); + + goto done; + + err: + /* + * In error exit, just write a '\0' in the first char so whatever called + * this at least won't fall off the end. + */ + *hex_errno = '\0'; + + done: + return res; +} +#endif /* !defined(_WIN32) */ + +/* Maximum number of file descriptors, if we cannot get it via sysconf() */ +#define DEFAULT_MAX_FD 256 + +/** Terminate the process of <b>process_handle</b>, if that process has not + * already exited. + * + * Return 0 if we succeeded in terminating the process (or if the process + * already exited), and -1 if we tried to kill the process but failed. + * + * Based on code originally borrowed from Python's os.kill. */ +int +tor_terminate_process(process_handle_t *process_handle) +{ +#ifdef _WIN32 + if (tor_get_exit_code(process_handle, 0, NULL) == PROCESS_EXIT_RUNNING) { + HANDLE handle = process_handle->pid.hProcess; + + if (!TerminateProcess(handle, 0)) + return -1; + else + return 0; + } +#else /* !(defined(_WIN32)) */ + if (process_handle->waitpid_cb) { + /* We haven't got a waitpid yet, so we can just kill off the process. */ + return kill(process_handle->pid, SIGTERM); + } +#endif /* defined(_WIN32) */ + + return 0; /* We didn't need to kill the process, so report success */ +} + +/** Return the Process ID of <b>process_handle</b>. */ +int +tor_process_get_pid(process_handle_t *process_handle) +{ +#ifdef _WIN32 + return (int) process_handle->pid.dwProcessId; +#else + return (int) process_handle->pid; +#endif +} + +#ifdef _WIN32 +HANDLE +tor_process_get_stdout_pipe(process_handle_t *process_handle) +{ + return process_handle->stdout_pipe; +} +#else /* !(defined(_WIN32)) */ +/* DOCDOC tor_process_get_stdout_pipe */ +int +tor_process_get_stdout_pipe(process_handle_t *process_handle) +{ + return process_handle->stdout_pipe; +} +#endif /* defined(_WIN32) */ + +/* DOCDOC process_handle_new */ +static process_handle_t * +process_handle_new(void) +{ + process_handle_t *out = tor_malloc_zero(sizeof(process_handle_t)); + +#ifdef _WIN32 + out->stdin_pipe = INVALID_HANDLE_VALUE; + out->stdout_pipe = INVALID_HANDLE_VALUE; + out->stderr_pipe = INVALID_HANDLE_VALUE; +#else + out->stdin_pipe = -1; + out->stdout_pipe = -1; + out->stderr_pipe = -1; +#endif /* defined(_WIN32) */ + + return out; +} + +#ifndef _WIN32 +/** Invoked when a process that we've launched via tor_spawn_background() has + * been found to have terminated. + */ +static void +process_handle_waitpid_cb(int status, void *arg) +{ + process_handle_t *process_handle = arg; + + process_handle->waitpid_exit_status = status; + clear_waitpid_callback(process_handle->waitpid_cb); + if (process_handle->status == PROCESS_STATUS_RUNNING) + process_handle->status = PROCESS_STATUS_NOTRUNNING; + process_handle->waitpid_cb = 0; +} +#endif /* !defined(_WIN32) */ + +/** + * @name child-process states + * + * Each of these values represents a possible state that a child process can + * be in. They're used to determine what to say when telling the parent how + * far along we were before failure. + * + * @{ + */ +#define CHILD_STATE_INIT 0 +#define CHILD_STATE_PIPE 1 +#define CHILD_STATE_MAXFD 2 +#define CHILD_STATE_FORK 3 +#define CHILD_STATE_DUPOUT 4 +#define CHILD_STATE_DUPERR 5 +#define CHILD_STATE_DUPIN 6 +#define CHILD_STATE_CLOSEFD 7 +#define CHILD_STATE_EXEC 8 +#define CHILD_STATE_FAILEXEC 9 +/** @} */ +/** + * Boolean. If true, then Tor may call execve or CreateProcess via + * tor_spawn_background. + **/ +static int may_spawn_background_process = 1; +/** + * Turn off may_spawn_background_process, so that all future calls to + * tor_spawn_background are guaranteed to fail. + **/ +void +tor_disable_spawning_background_processes(void) +{ + may_spawn_background_process = 0; +} +/** Start a program in the background. If <b>filename</b> contains a '/', then + * it will be treated as an absolute or relative path. Otherwise, on + * non-Windows systems, the system path will be searched for <b>filename</b>. + * On Windows, only the current directory will be searched. Here, to search the + * system path (as well as the application directory, current working + * directory, and system directories), set filename to NULL. + * + * The strings in <b>argv</b> will be passed as the command line arguments of + * the child program (following convention, argv[0] should normally be the + * filename of the executable, and this must be the case if <b>filename</b> is + * NULL). The last element of argv must be NULL. A handle to the child process + * will be returned in process_handle (which must be non-NULL). Read + * process_handle.status to find out if the process was successfully launched. + * For convenience, process_handle.status is returned by this function. + * + * Some parts of this code are based on the POSIX subprocess module from + * Python, and example code from + * http://msdn.microsoft.com/en-us/library/ms682499%28v=vs.85%29.aspx. + */ +int +tor_spawn_background(const char *const filename, const char **argv, + process_environment_t *env, + process_handle_t **process_handle_out) +{ + if (BUG(may_spawn_background_process == 0)) { + /* We should never reach this point if we're forbidden to spawn + * processes. Instead we should have caught the attempt earlier. */ + return PROCESS_STATUS_ERROR; + } + +#ifdef _WIN32 + HANDLE stdout_pipe_read = NULL; + HANDLE stdout_pipe_write = NULL; + HANDLE stderr_pipe_read = NULL; + HANDLE stderr_pipe_write = NULL; + HANDLE stdin_pipe_read = NULL; + HANDLE stdin_pipe_write = NULL; + process_handle_t *process_handle; + int status; + + STARTUPINFOA siStartInfo; + BOOL retval = FALSE; + + SECURITY_ATTRIBUTES saAttr; + char *joined_argv; + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + /* TODO: should we set explicit security attributes? (#2046, comment 5) */ + saAttr.lpSecurityDescriptor = NULL; + + /* Assume failure to start process */ + status = PROCESS_STATUS_ERROR; + + /* Set up pipe for stdout */ + if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, &saAttr, 0)) { + log_warn(LD_GENERAL, + "Failed to create pipe for stdout communication with child process: %s", + format_win32_error(GetLastError())); + return status; + } + if (!SetHandleInformation(stdout_pipe_read, HANDLE_FLAG_INHERIT, 0)) { + log_warn(LD_GENERAL, + "Failed to configure pipe for stdout communication with child " + "process: %s", format_win32_error(GetLastError())); + return status; + } + + /* Set up pipe for stderr */ + if (!CreatePipe(&stderr_pipe_read, &stderr_pipe_write, &saAttr, 0)) { + log_warn(LD_GENERAL, + "Failed to create pipe for stderr communication with child process: %s", + format_win32_error(GetLastError())); + return status; + } + if (!SetHandleInformation(stderr_pipe_read, HANDLE_FLAG_INHERIT, 0)) { + log_warn(LD_GENERAL, + "Failed to configure pipe for stderr communication with child " + "process: %s", format_win32_error(GetLastError())); + return status; + } + + /* Set up pipe for stdin */ + if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, &saAttr, 0)) { + log_warn(LD_GENERAL, + "Failed to create pipe for stdin communication with child process: %s", + format_win32_error(GetLastError())); + return status; + } + if (!SetHandleInformation(stdin_pipe_write, HANDLE_FLAG_INHERIT, 0)) { + log_warn(LD_GENERAL, + "Failed to configure pipe for stdin communication with child " + "process: %s", format_win32_error(GetLastError())); + return status; + } + + /* Create the child process */ + + /* Windows expects argv to be a whitespace delimited string, so join argv up + */ + joined_argv = tor_join_win_cmdline(argv); + + process_handle = process_handle_new(); + process_handle->status = status; + + ZeroMemory(&(process_handle->pid), sizeof(PROCESS_INFORMATION)); + ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = stderr_pipe_write; + siStartInfo.hStdOutput = stdout_pipe_write; + siStartInfo.hStdInput = stdin_pipe_read; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + /* Create the child process */ + + retval = CreateProcessA(filename, // module name + joined_argv, // command line + /* TODO: should we set explicit security attributes? (#2046, comment 5) */ + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess() + * work?) */ + CREATE_NO_WINDOW, // creation flags + (env==NULL) ? NULL : env->windows_environment_block, + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &(process_handle->pid)); // receives PROCESS_INFORMATION + + tor_free(joined_argv); + + if (!retval) { + log_warn(LD_GENERAL, + "Failed to create child process %s: %s", filename?filename:argv[0], + format_win32_error(GetLastError())); + tor_free(process_handle); + } else { + /* TODO: Close hProcess and hThread in process_handle->pid? */ + process_handle->stdout_pipe = stdout_pipe_read; + process_handle->stderr_pipe = stderr_pipe_read; + process_handle->stdin_pipe = stdin_pipe_write; + status = process_handle->status = PROCESS_STATUS_RUNNING; + } + + /* TODO: Close pipes on exit */ + *process_handle_out = process_handle; + return status; +#else /* !(defined(_WIN32)) */ + pid_t pid; + int stdout_pipe[2]; + int stderr_pipe[2]; + int stdin_pipe[2]; + int fd, retval; + process_handle_t *process_handle; + int status; + + const char *error_message = SPAWN_ERROR_MESSAGE; + size_t error_message_length; + + /* Represents where in the process of spawning the program is; + this is used for printing out the error message */ + unsigned char child_state = CHILD_STATE_INIT; + + char hex_errno[HEX_ERRNO_SIZE + 2]; /* + 1 should be sufficient actually */ + + static int max_fd = -1; + + status = PROCESS_STATUS_ERROR; + + /* We do the strlen here because strlen() is not signal handler safe, + and we are not allowed to use unsafe functions between fork and exec */ + error_message_length = strlen(error_message); + + // child_state = CHILD_STATE_PIPE; + + /* Set up pipe for redirecting stdout, stderr, and stdin of child */ + retval = pipe(stdout_pipe); + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to set up pipe for stdout communication with child process: %s", + strerror(errno)); + return status; + } + + retval = pipe(stderr_pipe); + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to set up pipe for stderr communication with child process: %s", + strerror(errno)); + + close(stdout_pipe[0]); + close(stdout_pipe[1]); + + return status; + } + + retval = pipe(stdin_pipe); + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to set up pipe for stdin communication with child process: %s", + strerror(errno)); + + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[0]); + close(stderr_pipe[1]); + + return status; + } + + // child_state = CHILD_STATE_MAXFD; + +#ifdef _SC_OPEN_MAX + if (-1 == max_fd) { + max_fd = (int) sysconf(_SC_OPEN_MAX); + if (max_fd == -1) { + max_fd = DEFAULT_MAX_FD; + log_warn(LD_GENERAL, + "Cannot find maximum file descriptor, assuming %d", max_fd); + } + } +#else /* !(defined(_SC_OPEN_MAX)) */ + max_fd = DEFAULT_MAX_FD; +#endif /* defined(_SC_OPEN_MAX) */ + + // child_state = CHILD_STATE_FORK; + + pid = fork(); + if (0 == pid) { + /* In child */ + +#if defined(HAVE_SYS_PRCTL_H) && defined(__linux__) + /* Attempt to have the kernel issue a SIGTERM if the parent + * goes away. Certain attributes of the binary being execve()ed + * will clear this during the execve() call, but it's better + * than nothing. + */ + prctl(PR_SET_PDEATHSIG, SIGTERM); +#endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) */ + + child_state = CHILD_STATE_DUPOUT; + + /* Link child stdout to the write end of the pipe */ + retval = dup2(stdout_pipe[1], STDOUT_FILENO); + if (-1 == retval) + goto error; + + child_state = CHILD_STATE_DUPERR; + + /* Link child stderr to the write end of the pipe */ + retval = dup2(stderr_pipe[1], STDERR_FILENO); + if (-1 == retval) + goto error; + + child_state = CHILD_STATE_DUPIN; + + /* Link child stdin to the read end of the pipe */ + retval = dup2(stdin_pipe[0], STDIN_FILENO); + if (-1 == retval) + goto error; + + // child_state = CHILD_STATE_CLOSEFD; + + close(stderr_pipe[0]); + close(stderr_pipe[1]); + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stdin_pipe[0]); + close(stdin_pipe[1]); + + /* Close all other fds, including the read end of the pipe */ + /* XXX: We should now be doing enough FD_CLOEXEC setting to make + * this needless. */ + for (fd = STDERR_FILENO + 1; fd < max_fd; fd++) { + close(fd); + } + + // child_state = CHILD_STATE_EXEC; + + /* Call the requested program. We need the cast because + execvp doesn't define argv as const, even though it + does not modify the arguments */ + if (env) + execve(filename, (char *const *) argv, env->unixoid_environment_block); + else { + static char *new_env[] = { NULL }; + execve(filename, (char *const *) argv, new_env); + } + + /* If we got here, the exec or open(/dev/null) failed */ + + child_state = CHILD_STATE_FAILEXEC; + + error: + { + /* XXX: are we leaking fds from the pipe? */ + int n, err=0; + ssize_t nbytes; + + n = format_helper_exit_status(child_state, errno, hex_errno); + + if (n >= 0) { + /* Write the error message. GCC requires that we check the return + value, but there is nothing we can do if it fails */ + /* TODO: Don't use STDOUT, use a pipe set up just for this purpose */ + nbytes = write(STDOUT_FILENO, error_message, error_message_length); + err = (nbytes < 0); + nbytes = write(STDOUT_FILENO, hex_errno, n); + err += (nbytes < 0); + } + + _exit(err?254:255); // exit ok: in child. + } + + /* Never reached, but avoids compiler warning */ + return status; // LCOV_EXCL_LINE + } + + /* In parent */ + + if (-1 == pid) { + log_warn(LD_GENERAL, "Failed to fork child process: %s", strerror(errno)); + close(stdin_pipe[0]); + close(stdin_pipe[1]); + close(stdout_pipe[0]); + close(stdout_pipe[1]); + close(stderr_pipe[0]); + close(stderr_pipe[1]); + return status; + } + + process_handle = process_handle_new(); + process_handle->status = status; + process_handle->pid = pid; + + /* TODO: If the child process forked but failed to exec, waitpid it */ + + /* Return read end of the pipes to caller, and close write end */ + process_handle->stdout_pipe = stdout_pipe[0]; + retval = close(stdout_pipe[1]); + + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to close write end of stdout pipe in parent process: %s", + strerror(errno)); + } + + process_handle->waitpid_cb = set_waitpid_callback(pid, + process_handle_waitpid_cb, + process_handle); + + process_handle->stderr_pipe = stderr_pipe[0]; + retval = close(stderr_pipe[1]); + + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to close write end of stderr pipe in parent process: %s", + strerror(errno)); + } + + /* Return write end of the stdin pipe to caller, and close the read end */ + process_handle->stdin_pipe = stdin_pipe[1]; + retval = close(stdin_pipe[0]); + + if (-1 == retval) { + log_warn(LD_GENERAL, + "Failed to close read end of stdin pipe in parent process: %s", + strerror(errno)); + } + + status = process_handle->status = PROCESS_STATUS_RUNNING; + /* Set stdin/stdout/stderr pipes to be non-blocking */ + if (fcntl(process_handle->stdout_pipe, F_SETFL, O_NONBLOCK) < 0 || + fcntl(process_handle->stderr_pipe, F_SETFL, O_NONBLOCK) < 0 || + fcntl(process_handle->stdin_pipe, F_SETFL, O_NONBLOCK) < 0) { + log_warn(LD_GENERAL, "Failed to set stderror/stdout/stdin pipes " + "nonblocking in parent process: %s", strerror(errno)); + } + + *process_handle_out = process_handle; + return status; +#endif /* defined(_WIN32) */ +} + +/** Destroy all resources allocated by the process handle in + * <b>process_handle</b>. + * If <b>also_terminate_process</b> is true, also terminate the + * process of the process handle. */ +MOCK_IMPL(void, +tor_process_handle_destroy,(process_handle_t *process_handle, + int also_terminate_process)) +{ + if (!process_handle) + return; + + if (also_terminate_process) { + if (tor_terminate_process(process_handle) < 0) { + const char *errstr = +#ifdef _WIN32 + format_win32_error(GetLastError()); +#else + strerror(errno); +#endif + log_notice(LD_GENERAL, "Failed to terminate process with " + "PID '%d' ('%s').", tor_process_get_pid(process_handle), + errstr); + } else { + log_info(LD_GENERAL, "Terminated process with PID '%d'.", + tor_process_get_pid(process_handle)); + } + } + + process_handle->status = PROCESS_STATUS_NOTRUNNING; + +#ifdef _WIN32 + if (process_handle->stdout_pipe) + CloseHandle(process_handle->stdout_pipe); + + if (process_handle->stderr_pipe) + CloseHandle(process_handle->stderr_pipe); + + if (process_handle->stdin_pipe) + CloseHandle(process_handle->stdin_pipe); +#else /* !(defined(_WIN32)) */ + close(process_handle->stdout_pipe); + close(process_handle->stderr_pipe); + close(process_handle->stdin_pipe); + + clear_waitpid_callback(process_handle->waitpid_cb); +#endif /* defined(_WIN32) */ + + memset(process_handle, 0x0f, sizeof(process_handle_t)); + tor_free(process_handle); +} + +/** Get the exit code of a process specified by <b>process_handle</b> and store + * it in <b>exit_code</b>, if set to a non-NULL value. If <b>block</b> is set + * to true, the call will block until the process has exited. Otherwise if + * the process is still running, the function will return + * PROCESS_EXIT_RUNNING, and exit_code will be left unchanged. Returns + * PROCESS_EXIT_EXITED if the process did exit. If there is a failure, + * PROCESS_EXIT_ERROR will be returned and the contents of exit_code (if + * non-NULL) will be undefined. N.B. Under *nix operating systems, this will + * probably not work in Tor, because waitpid() is called in main.c to reap any + * terminated child processes.*/ +int +tor_get_exit_code(process_handle_t *process_handle, + int block, int *exit_code) +{ +#ifdef _WIN32 + DWORD retval; + BOOL success; + + if (block) { + /* Wait for the process to exit */ + retval = WaitForSingleObject(process_handle->pid.hProcess, INFINITE); + if (retval != WAIT_OBJECT_0) { + log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", + (int)retval, format_win32_error(GetLastError())); + return PROCESS_EXIT_ERROR; + } + } else { + retval = WaitForSingleObject(process_handle->pid.hProcess, 0); + if (WAIT_TIMEOUT == retval) { + /* Process has not exited */ + return PROCESS_EXIT_RUNNING; + } else if (retval != WAIT_OBJECT_0) { + log_warn(LD_GENERAL, "WaitForSingleObject() failed (%d): %s", + (int)retval, format_win32_error(GetLastError())); + return PROCESS_EXIT_ERROR; + } + } + + if (exit_code != NULL) { + success = GetExitCodeProcess(process_handle->pid.hProcess, + (PDWORD)exit_code); + if (!success) { + log_warn(LD_GENERAL, "GetExitCodeProcess() failed: %s", + format_win32_error(GetLastError())); + return PROCESS_EXIT_ERROR; + } + } +#else /* !(defined(_WIN32)) */ + int stat_loc; + int retval; + + if (process_handle->waitpid_cb) { + /* We haven't processed a SIGCHLD yet. */ + retval = waitpid(process_handle->pid, &stat_loc, block?0:WNOHANG); + if (retval == process_handle->pid) { + clear_waitpid_callback(process_handle->waitpid_cb); + process_handle->waitpid_cb = NULL; + process_handle->waitpid_exit_status = stat_loc; + } + } else { + /* We already got a SIGCHLD for this process, and handled it. */ + retval = process_handle->pid; + stat_loc = process_handle->waitpid_exit_status; + } + + if (!block && 0 == retval) { + /* Process has not exited */ + return PROCESS_EXIT_RUNNING; + } else if (retval != process_handle->pid) { + log_warn(LD_GENERAL, "waitpid() failed for PID %d: %s", + (int)process_handle->pid, strerror(errno)); + return PROCESS_EXIT_ERROR; + } + + if (!WIFEXITED(stat_loc)) { + log_warn(LD_GENERAL, "Process %d did not exit normally", + (int)process_handle->pid); + return PROCESS_EXIT_ERROR; + } + + if (exit_code != NULL) + *exit_code = WEXITSTATUS(stat_loc); +#endif /* defined(_WIN32) */ + + return PROCESS_EXIT_EXITED; +} + +#ifdef _WIN32 +/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If + * <b>hProcess</b> is NULL, the function will return immediately if there is + * nothing more to read. Otherwise <b>hProcess</b> should be set to the handle + * to the process owning the <b>h</b>. In this case, the function will exit + * only once the process has exited, or <b>count</b> bytes are read. Returns + * the number of bytes read, or -1 on error. */ +ssize_t +tor_read_all_handle(HANDLE h, char *buf, size_t count, + const process_handle_t *process) +{ + size_t numread = 0; + BOOL retval; + DWORD byte_count; + BOOL process_exited = FALSE; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) + return -1; + + while (numread < count) { + /* Check if there is anything to read */ + retval = PeekNamedPipe(h, NULL, 0, NULL, &byte_count, NULL); + if (!retval) { + log_warn(LD_GENERAL, + "Failed to peek from handle: %s", + format_win32_error(GetLastError())); + return -1; + } else if (0 == byte_count) { + /* Nothing available: process exited or it is busy */ + + /* Exit if we don't know whether the process is running */ + if (NULL == process) + break; + + /* The process exited and there's nothing left to read from it */ + if (process_exited) + break; + + /* If process is not running, check for output one more time in case + it wrote something after the peek was performed. Otherwise keep on + waiting for output */ + tor_assert(process != NULL); + byte_count = WaitForSingleObject(process->pid.hProcess, 0); + if (WAIT_TIMEOUT != byte_count) + process_exited = TRUE; + + continue; + } + + /* There is data to read; read it */ + retval = ReadFile(h, buf+numread, count-numread, &byte_count, NULL); + tor_assert(byte_count + numread <= count); + if (!retval) { + log_warn(LD_GENERAL, "Failed to read from handle: %s", + format_win32_error(GetLastError())); + return -1; + } else if (0 == byte_count) { + /* End of file */ + break; + } + numread += byte_count; + } + return (ssize_t)numread; +} +#else /* !(defined(_WIN32)) */ +/** Read from a handle <b>fd</b> into <b>buf</b>, up to <b>count</b> bytes. If + * <b>process</b> is NULL, the function will return immediately if there is + * nothing more to read. Otherwise data will be read until end of file, or + * <b>count</b> bytes are read. Returns the number of bytes read, or -1 on + * error. Sets <b>eof</b> to true if <b>eof</b> is not NULL and the end of the + * file has been reached. */ +ssize_t +tor_read_all_handle(int fd, char *buf, size_t count, + const process_handle_t *process, + int *eof) +{ + size_t numread = 0; + ssize_t result; + + if (eof) + *eof = 0; + + if (count > SIZE_T_CEILING || count > SSIZE_MAX) + return -1; + + while (numread < count) { + result = read(fd, buf+numread, count-numread); + + if (result == 0) { + log_debug(LD_GENERAL, "read() reached end of file"); + if (eof) + *eof = 1; + break; + } else if (result < 0 && errno == EAGAIN) { + if (process) + continue; + else + break; + } else if (result < 0) { + log_warn(LD_GENERAL, "read() failed: %s", strerror(errno)); + return -1; + } + + numread += result; + } + + log_debug(LD_GENERAL, "read() read %d bytes from handle", (int)numread); + return (ssize_t)numread; +} +#endif /* defined(_WIN32) */ + +/** Read from stdout of a process until the process exits. */ +ssize_t +tor_read_all_from_process_stdout(const process_handle_t *process_handle, + char *buf, size_t count) +{ +#ifdef _WIN32 + return tor_read_all_handle(process_handle->stdout_pipe, buf, count, + process_handle); +#else + return tor_read_all_handle(process_handle->stdout_pipe, buf, count, + process_handle, NULL); +#endif /* defined(_WIN32) */ +} + +/** Read from stdout of a process until the process exits. */ +ssize_t +tor_read_all_from_process_stderr(const process_handle_t *process_handle, + char *buf, size_t count) +{ +#ifdef _WIN32 + return tor_read_all_handle(process_handle->stderr_pipe, buf, count, + process_handle); +#else + return tor_read_all_handle(process_handle->stderr_pipe, buf, count, + process_handle, NULL); +#endif /* defined(_WIN32) */ +} + +/** Return a string corresponding to <b>stream_status</b>. */ +const char * +stream_status_to_string(enum stream_status stream_status) +{ + switch (stream_status) { + case IO_STREAM_OKAY: + return "okay"; + case IO_STREAM_EAGAIN: + return "temporarily unavailable"; + case IO_STREAM_TERM: + return "terminated"; + case IO_STREAM_CLOSED: + return "closed"; + default: + tor_fragile_assert(); + return "unknown"; + } +} + +/** Split buf into lines, and add to smartlist. The buffer <b>buf</b> will be + * modified. The resulting smartlist will consist of pointers to buf, so there + * is no need to free the contents of sl. <b>buf</b> must be a NUL-terminated + * string. <b>len</b> should be set to the length of the buffer excluding the + * NUL. Non-printable characters (including NUL) will be replaced with "." */ +int +tor_split_lines(smartlist_t *sl, char *buf, int len) +{ + /* Index in buf of the start of the current line */ + int start = 0; + /* Index in buf of the current character being processed */ + int cur = 0; + /* Are we currently in a line */ + char in_line = 0; + + /* Loop over string */ + while (cur < len) { + /* Loop until end of line or end of string */ + for (; cur < len; cur++) { + if (in_line) { + if ('\r' == buf[cur] || '\n' == buf[cur]) { + /* End of line */ + buf[cur] = '\0'; + /* Point cur to the next line */ + cur++; + /* Line starts at start and ends with a nul */ + break; + } else { + if (!TOR_ISPRINT(buf[cur])) + buf[cur] = '.'; + } + } else { + if ('\r' == buf[cur] || '\n' == buf[cur]) { + /* Skip leading vertical space */ + ; + } else { + in_line = 1; + start = cur; + if (!TOR_ISPRINT(buf[cur])) + buf[cur] = '.'; + } + } + } + /* We are at the end of the line or end of string. If in_line is true there + * is a line which starts at buf+start and ends at a NUL. cur points to + * the character after the NUL. */ + if (in_line) + smartlist_add(sl, (void *)(buf+start)); + in_line = 0; + } + return smartlist_len(sl); +} + +#ifdef _WIN32 + +/** Return a smartlist containing lines outputted from + * <b>handle</b>. Return NULL on error, and set + * <b>stream_status_out</b> appropriately. */ +MOCK_IMPL(smartlist_t *, +tor_get_lines_from_handle, (HANDLE *handle, + enum stream_status *stream_status_out)) +{ + int pos; + char stdout_buf[600] = {0}; + smartlist_t *lines = NULL; + + tor_assert(stream_status_out); + + *stream_status_out = IO_STREAM_TERM; + + pos = tor_read_all_handle(handle, stdout_buf, sizeof(stdout_buf) - 1, NULL); + if (pos < 0) { + *stream_status_out = IO_STREAM_TERM; + return NULL; + } + if (pos == 0) { + *stream_status_out = IO_STREAM_EAGAIN; + return NULL; + } + + /* End with a null even if there isn't a \r\n at the end */ + /* TODO: What if this is a partial line? */ + stdout_buf[pos] = '\0'; + + /* Split up the buffer */ + lines = smartlist_new(); + tor_split_lines(lines, stdout_buf, pos); + + /* Currently 'lines' is populated with strings residing on the + stack. Replace them with their exact copies on the heap: */ + SMARTLIST_FOREACH(lines, char *, line, + SMARTLIST_REPLACE_CURRENT(lines, line, tor_strdup(line))); + + *stream_status_out = IO_STREAM_OKAY; + + return lines; +} + +#else /* !(defined(_WIN32)) */ + +/** Return a smartlist containing lines outputted from + * <b>fd</b>. Return NULL on error, and set + * <b>stream_status_out</b> appropriately. */ +MOCK_IMPL(smartlist_t *, +tor_get_lines_from_handle, (int fd, enum stream_status *stream_status_out)) +{ + enum stream_status stream_status; + char stdout_buf[400]; + smartlist_t *lines = NULL; + + while (1) { + memset(stdout_buf, 0, sizeof(stdout_buf)); + + stream_status = get_string_from_pipe(fd, + stdout_buf, sizeof(stdout_buf) - 1); + if (stream_status != IO_STREAM_OKAY) + goto done; + + if (!lines) lines = smartlist_new(); + smartlist_split_string(lines, stdout_buf, "\n", 0, 0); + } + + done: + *stream_status_out = stream_status; + return lines; +} + +#endif /* defined(_WIN32) */ + +/** Reads from <b>fd</b> and stores input in <b>buf_out</b> making + * sure it's below <b>count</b> bytes. + * If the string has a trailing newline, we strip it off. + * + * This function is specifically created to handle input from managed + * proxies, according to the pluggable transports spec. Make sure it + * fits your needs before using it. + * + * Returns: + * IO_STREAM_CLOSED: If the stream is closed. + * IO_STREAM_EAGAIN: If there is nothing to read and we should check back + * later. + * IO_STREAM_TERM: If something is wrong with the stream. + * IO_STREAM_OKAY: If everything went okay and we got a string + * in <b>buf_out</b>. */ +enum stream_status +get_string_from_pipe(int fd, char *buf_out, size_t count) +{ + ssize_t ret; + + tor_assert(count <= INT_MAX); + + ret = read(fd, buf_out, count); + + if (ret == 0) + return IO_STREAM_CLOSED; + else if (ret < 0 && errno == EAGAIN) + return IO_STREAM_EAGAIN; + else if (ret < 0) + return IO_STREAM_TERM; + + if (buf_out[ret - 1] == '\n') { + /* Remove the trailing newline */ + buf_out[ret - 1] = '\0'; + } else + buf_out[ret] = '\0'; + + return IO_STREAM_OKAY; +} diff --git a/src/lib/process/subprocess.h b/src/lib/process/subprocess.h new file mode 100644 index 0000000000..a319b3505c --- /dev/null +++ b/src/lib/process/subprocess.h @@ -0,0 +1,129 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SUBPROCESS_H +#define TOR_SUBPROCESS_H + +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#include <stddef.h> +#ifdef _WIN32 +#include <windows.h> +#endif + +struct smartlist_t; + +void tor_disable_spawning_background_processes(void); + +typedef struct process_handle_t process_handle_t; +struct process_environment_t; +int tor_spawn_background(const char *const filename, const char **argv, + struct process_environment_t *env, + process_handle_t **process_handle_out); + +#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " + +/** Status of an I/O stream. */ +enum stream_status { + IO_STREAM_OKAY, + IO_STREAM_EAGAIN, + IO_STREAM_TERM, + IO_STREAM_CLOSED +}; + +const char *stream_status_to_string(enum stream_status stream_status); + +enum stream_status get_string_from_pipe(int fd, char *buf, size_t count); + +/* Values of process_handle_t.status. */ +#define PROCESS_STATUS_NOTRUNNING 0 +#define PROCESS_STATUS_RUNNING 1 +#define PROCESS_STATUS_ERROR -1 + +#ifdef SUBPROCESS_PRIVATE +struct waitpid_callback_t; + +/** Structure to represent the state of a process with which Tor is + * communicating. The contents of this structure are private to util.c */ +struct process_handle_t { + /** One of the PROCESS_STATUS_* values */ + int status; +#ifdef _WIN32 + HANDLE stdin_pipe; + HANDLE stdout_pipe; + HANDLE stderr_pipe; + PROCESS_INFORMATION pid; +#else /* !(defined(_WIN32)) */ + int stdin_pipe; + int stdout_pipe; + int stderr_pipe; + pid_t pid; + /** If the process has not given us a SIGCHLD yet, this has the + * waitpid_callback_t that gets invoked once it has. Otherwise this + * contains NULL. */ + struct waitpid_callback_t *waitpid_cb; + /** The exit status reported by waitpid. */ + int waitpid_exit_status; +#endif /* defined(_WIN32) */ +}; +#endif /* defined(SUBPROCESS_PRIVATE) */ + +/* Return values of tor_get_exit_code() */ +#define PROCESS_EXIT_RUNNING 1 +#define PROCESS_EXIT_EXITED 0 +#define PROCESS_EXIT_ERROR -1 +int tor_get_exit_code(process_handle_t *process_handle, + int block, int *exit_code); +int tor_split_lines(struct smartlist_t *sl, char *buf, int len); +#ifdef _WIN32 +ssize_t tor_read_all_handle(HANDLE h, char *buf, size_t count, + const process_handle_t *process); +#else +ssize_t tor_read_all_handle(int fd, char *buf, size_t count, + const process_handle_t *process, + int *eof); +#endif /* defined(_WIN32) */ +ssize_t tor_read_all_from_process_stdout( + const process_handle_t *process_handle, char *buf, size_t count); +ssize_t tor_read_all_from_process_stderr( + const process_handle_t *process_handle, char *buf, size_t count); +char *tor_join_win_cmdline(const char *argv[]); + +int tor_process_get_pid(process_handle_t *process_handle); +#ifdef _WIN32 +HANDLE tor_process_get_stdout_pipe(process_handle_t *process_handle); +#else +int tor_process_get_stdout_pipe(process_handle_t *process_handle); +#endif + +#ifdef _WIN32 +MOCK_DECL(struct smartlist_t *, tor_get_lines_from_handle,(HANDLE *handle, + enum stream_status *stream_status)); +#else +MOCK_DECL(struct smartlist_t *, tor_get_lines_from_handle,(int fd, + enum stream_status *stream_status)); +#endif /* defined(_WIN32) */ + +int tor_terminate_process(process_handle_t *process_handle); + +MOCK_DECL(void, tor_process_handle_destroy,(process_handle_t *process_handle, + int also_terminate_process)); + +#ifdef SUBPROCESS_PRIVATE +/* Prototypes for private functions only used by util.c (and unit tests) */ + +#ifndef _WIN32 +STATIC int format_helper_exit_status(unsigned char child_state, + int saved_errno, char *hex_errno); + +/* Space for hex values of child state, a slash, saved_errno (with + leading minus) and newline (no null) */ +#define HEX_ERRNO_SIZE (sizeof(char) * 2 + 1 + \ + 1 + sizeof(int) * 2 + 1) +#endif /* !defined(_WIN32) */ + +#endif /* defined(SUBPROCESS_PRIVATE) */ + +#endif diff --git a/src/common/util_process.c b/src/lib/process/waitpid.c index c2826152e9..66c77b05f3 100644 --- a/src/common/util_process.c +++ b/src/lib/process/waitpid.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,18 +12,19 @@ #include "orconfig.h" -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif +#ifndef _WIN32 + +#include "lib/process/waitpid.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" +#include "ht.h" + #ifdef HAVE_SYS_WAIT_H #include <sys/wait.h> #endif -#include "compat.h" -#include "util.h" -#include "torlog.h" -#include "util_process.h" -#include "ht.h" +#include <string.h> /* ================================================== */ /* Convenience structures for handlers for waitpid(). @@ -32,8 +33,6 @@ * monitoring a non-child process. */ -#ifndef _WIN32 - /** Mapping from a PID to a userfn/userdata pair. */ struct waitpid_callback_t { HT_ENTRY(waitpid_callback_t) node; @@ -155,4 +154,3 @@ notify_pending_waitpid_callbacks(void) } #endif /* !defined(_WIN32) */ - diff --git a/src/common/util_process.h b/src/lib/process/waitpid.h index c9aa771b77..85905da6bf 100644 --- a/src/common/util_process.h +++ b/src/lib/process/waitpid.h @@ -1,15 +1,19 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** - * \file util_process.h - * \brief Headers for util_process.c + * \file waitpid.h + * \brief Headers for waitpid.c **/ -#ifndef TOR_UTIL_PROCESS_H -#define TOR_UTIL_PROCESS_H +#ifndef TOR_WAITPID_H +#define TOR_WAITPID_H #ifndef _WIN32 +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + /** A callback structure waiting for us to get a SIGCHLD informing us that a * PID has been closed. Created by set_waitpid_callback. Cancelled or cleaned- * up from clear_waitpid_callback(). Do not access outside of the main thread; @@ -22,5 +26,4 @@ void clear_waitpid_callback(waitpid_callback_t *ent); void notify_pending_waitpid_callbacks(void); #endif /* !defined(_WIN32) */ -#endif /* !defined(TOR_UTIL_PROCESS_H) */ - +#endif /* !defined(TOR_WAITPID_H) */ diff --git a/src/lib/sandbox/.may_include b/src/lib/sandbox/.may_include new file mode 100644 index 0000000000..84906dfb3d --- /dev/null +++ b/src/lib/sandbox/.may_include @@ -0,0 +1,15 @@ +orconfig.h + +lib/cc/*.h +lib/container/*.h +lib/err/*.h +lib/log/*.h +lib/malloc/*.h +lib/net/*.h +lib/sandbox/*.h +lib/sandbox/*.inc +lib/string/*.h + +ht.h +siphash.h +tor_queue.h diff --git a/src/lib/sandbox/include.am b/src/lib/sandbox/include.am new file mode 100644 index 0000000000..adfda6bde5 --- /dev/null +++ b/src/lib/sandbox/include.am @@ -0,0 +1,18 @@ + +noinst_LIBRARIES += src/lib/libtor-sandbox.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-sandbox-testing.a +endif + +src_lib_libtor_sandbox_a_SOURCES = \ + src/lib/sandbox/sandbox.c + +src_lib_libtor_sandbox_testing_a_SOURCES = \ + $(src_lib_libtor_sandbox_a_SOURCES) +src_lib_libtor_sandbox_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_sandbox_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/sandbox/linux_syscalls.inc \ + src/lib/sandbox/sandbox.h diff --git a/src/common/linux_syscalls.inc b/src/lib/sandbox/linux_syscalls.inc index cf47c73809..cf47c73809 100644 --- a/src/common/linux_syscalls.inc +++ b/src/lib/sandbox/linux_syscalls.inc diff --git a/src/common/sandbox.c b/src/lib/sandbox/sandbox.c index 440f8722f2..25dd6d1c26 100644 --- a/src/common/sandbox.c +++ b/src/lib/sandbox/sandbox.c @@ -1,7 +1,7 @@ - /* Copyright (c) 2001 Matej Pfajfar. +/* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,15 +31,20 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <errno.h> -#include "sandbox.h" -#include "container.h" -#include "torlog.h" -#include "torint.h" -#include "util.h" -#include "tor_queue.h" +#include "lib/sandbox/sandbox.h" +#include "lib/container/map.h" +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "lib/cc/torint.h" +#include "lib/net/resolve.h" +#include "lib/malloc/util_malloc.h" +#include "lib/string/scanf.h" +#include "tor_queue.h" #include "ht.h" +#include "siphash.h" #define DEBUGGING_CLOSE @@ -79,7 +84,7 @@ defined(HAVE_BACKTRACE_SYMBOLS_FD) && defined(HAVE_SIGACTION) #define USE_BACKTRACE #define EXPOSE_CLEAN_BACKTRACE -#include "backtrace.h" +#include "lib/err/backtrace.h" #endif /* defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE) && ... */ #ifdef USE_BACKTRACE @@ -1455,183 +1460,6 @@ sandbox_cfg_allow_openat_filename(sandbox_cfg_t **cfg, char *file) return 0; } -/** Cache entry for getaddrinfo results; used when sandboxing is implemented - * so that we can consult the cache when the sandbox prevents us from doing - * getaddrinfo. - * - * We support only a limited range of getaddrinfo calls, where servname is null - * and hints contains only socktype=SOCK_STREAM, family in INET,INET6,UNSPEC. - */ -typedef struct cached_getaddrinfo_item_t { - HT_ENTRY(cached_getaddrinfo_item_t) node; - char *name; - int family; - /** set if no error; otherwise NULL */ - struct addrinfo *res; - /** 0 for no error; otherwise an EAI_* value */ - int err; -} cached_getaddrinfo_item_t; - -static unsigned -cached_getaddrinfo_item_hash(const cached_getaddrinfo_item_t *item) -{ - return (unsigned)siphash24g(item->name, strlen(item->name)) + item->family; -} - -static unsigned -cached_getaddrinfo_items_eq(const cached_getaddrinfo_item_t *a, - const cached_getaddrinfo_item_t *b) -{ - return (a->family == b->family) && 0 == strcmp(a->name, b->name); -} - -#define cached_getaddrinfo_item_free(item) \ - FREE_AND_NULL(cached_getaddrinfo_item_t, \ - cached_getaddrinfo_item_free_, (item)) - -static void -cached_getaddrinfo_item_free_(cached_getaddrinfo_item_t *item) -{ - if (item == NULL) - return; - - tor_free(item->name); - if (item->res) - freeaddrinfo(item->res); - tor_free(item); -} - -static HT_HEAD(getaddrinfo_cache, cached_getaddrinfo_item_t) - getaddrinfo_cache = HT_INITIALIZER(); - -HT_PROTOTYPE(getaddrinfo_cache, cached_getaddrinfo_item_t, node, - cached_getaddrinfo_item_hash, - cached_getaddrinfo_items_eq) -HT_GENERATE2(getaddrinfo_cache, cached_getaddrinfo_item_t, node, - cached_getaddrinfo_item_hash, - cached_getaddrinfo_items_eq, - 0.6, tor_reallocarray_, tor_free_) - -/** If true, don't try to cache getaddrinfo results. */ -static int sandbox_getaddrinfo_cache_disabled = 0; - -/** Tell the sandbox layer not to try to cache getaddrinfo results. Used as in - * tor-resolve, when we have no intention of initializing crypto or of - * installing the sandbox.*/ -void -sandbox_disable_getaddrinfo_cache(void) -{ - sandbox_getaddrinfo_cache_disabled = 1; -} - -void -sandbox_freeaddrinfo(struct addrinfo *ai) -{ - if (sandbox_getaddrinfo_cache_disabled) - freeaddrinfo(ai); -} - -int -sandbox_getaddrinfo(const char *name, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res) -{ - int err; - struct cached_getaddrinfo_item_t search, *item; - - if (sandbox_getaddrinfo_cache_disabled) { - return getaddrinfo(name, NULL, hints, res); - } - - if (servname != NULL) { - log_warn(LD_BUG, "called with non-NULL servname"); - return EAI_NONAME; - } - if (name == NULL) { - log_warn(LD_BUG, "called with NULL name"); - return EAI_NONAME; - } - - *res = NULL; - - memset(&search, 0, sizeof(search)); - search.name = (char *) name; - search.family = hints ? hints->ai_family : AF_UNSPEC; - item = HT_FIND(getaddrinfo_cache, &getaddrinfo_cache, &search); - - if (! sandbox_is_active()) { - /* If the sandbox is not turned on yet, then getaddrinfo and store the - result. */ - - err = getaddrinfo(name, NULL, hints, res); - log_info(LD_NET,"(Sandbox) getaddrinfo %s.", err ? "failed" : "succeeded"); - - if (! item) { - item = tor_malloc_zero(sizeof(*item)); - item->name = tor_strdup(name); - item->family = hints ? hints->ai_family : AF_UNSPEC; - HT_INSERT(getaddrinfo_cache, &getaddrinfo_cache, item); - } - - if (item->res) { - freeaddrinfo(item->res); - item->res = NULL; - } - item->res = *res; - item->err = err; - return err; - } - - /* Otherwise, the sandbox is on. If we have an item, yield its cached - result. */ - if (item) { - *res = item->res; - return item->err; - } - - /* getting here means something went wrong */ - log_err(LD_BUG,"(Sandbox) failed to get address %s!", name); - return EAI_NONAME; -} - -int -sandbox_add_addrinfo(const char *name) -{ - struct addrinfo *res; - struct addrinfo hints; - int i; - static const int families[] = { AF_INET, AF_INET6, AF_UNSPEC }; - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - for (i = 0; i < 3; ++i) { - hints.ai_family = families[i]; - - res = NULL; - (void) sandbox_getaddrinfo(name, NULL, &hints, &res); - if (res) - sandbox_freeaddrinfo(res); - } - - return 0; -} - -void -sandbox_free_getaddrinfo_cache(void) -{ - cached_getaddrinfo_item_t **next, **item, *this; - - for (item = HT_START(getaddrinfo_cache, &getaddrinfo_cache); - item; - item = next) { - this = *item; - next = HT_NEXT_RMV(getaddrinfo_cache, &getaddrinfo_cache, item); - cached_getaddrinfo_item_free(this); - } - - HT_CLEAR(getaddrinfo_cache, &getaddrinfo_cache); -} - /** * Function responsible for going through the parameter syscall filters and * call each function pointer in the list. @@ -1724,13 +1552,15 @@ install_syscall_filter(sandbox_cfg_t* cfg) // marking the sandbox as active sandbox_active = 1; + tor_make_getaddrinfo_cache_active(); end: seccomp_release(ctx); return (rc < 0 ? -rc : rc); } -#include "linux_syscalls.inc" +#include "lib/sandbox/linux_syscalls.inc" + static const char * get_syscall_name(int syscall_num) { @@ -1974,4 +1804,3 @@ sandbox_disable_getaddrinfo_cache(void) { } #endif /* !defined(USE_LIBSECCOMP) */ - diff --git a/src/common/sandbox.h b/src/lib/sandbox/sandbox.h index d0f85570f4..60d8e8816a 100644 --- a/src/common/sandbox.h +++ b/src/lib/sandbox/sandbox.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -13,7 +13,7 @@ #define SANDBOX_H_ #include "orconfig.h" -#include "torint.h" +#include "lib/cc/torint.h" #ifndef SYS_SECCOMP @@ -104,27 +104,6 @@ typedef struct { #endif /* defined(USE_LIBSECCOMP) */ #ifdef USE_LIBSECCOMP -/** Pre-calls getaddrinfo in order to pre-record result. */ -int sandbox_add_addrinfo(const char *addr); - -struct addrinfo; -/** Replacement for getaddrinfo(), using pre-recorded results. */ -int sandbox_getaddrinfo(const char *name, const char *servname, - const struct addrinfo *hints, - struct addrinfo **res); -void sandbox_freeaddrinfo(struct addrinfo *addrinfo); -void sandbox_free_getaddrinfo_cache(void); -#else /* !(defined(USE_LIBSECCOMP)) */ -#define sandbox_getaddrinfo(name, servname, hints, res) \ - getaddrinfo((name),(servname), (hints),(res)) -#define sandbox_add_addrinfo(name) \ - ((void)(name)) -#define sandbox_freeaddrinfo(addrinfo) \ - freeaddrinfo((addrinfo)) -#define sandbox_free_getaddrinfo_cache() -#endif /* defined(USE_LIBSECCOMP) */ - -#ifdef USE_LIBSECCOMP /** Returns a registered protected string used with the sandbox, given that * it matches the parameter. */ @@ -168,7 +147,4 @@ int sandbox_init(sandbox_cfg_t* cfg); /** Return true iff the sandbox is turned on. */ int sandbox_is_active(void); -void sandbox_disable_getaddrinfo_cache(void); - #endif /* !defined(SANDBOX_H_) */ - diff --git a/src/lib/smartlist_core/.may_include b/src/lib/smartlist_core/.may_include new file mode 100644 index 0000000000..a8507761a4 --- /dev/null +++ b/src/lib/smartlist_core/.may_include @@ -0,0 +1,7 @@ +orconfig.h +lib/cc/*.h +lib/malloc/*.h +lib/err/*.h +lib/string/*.h +lib/smartlist_core/*.h +lib/testsupport/testsupport.h diff --git a/src/lib/smartlist_core/include.am b/src/lib/smartlist_core/include.am new file mode 100644 index 0000000000..99d65f0b23 --- /dev/null +++ b/src/lib/smartlist_core/include.am @@ -0,0 +1,21 @@ + +noinst_LIBRARIES += src/lib/libtor-smartlist-core.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-smartlist-core-testing.a +endif + +src_lib_libtor_smartlist_core_a_SOURCES = \ + src/lib/smartlist_core/smartlist_core.c \ + src/lib/smartlist_core/smartlist_split.c + +src_lib_libtor_smartlist_core_testing_a_SOURCES = \ + $(src_lib_libtor_smartlist_core_a_SOURCES) +src_lib_libtor_smartlist_core_testing_a_CPPFLAGS = \ + $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_smartlist_core_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/smartlist_core/smartlist_core.h \ + src/lib/smartlist_core/smartlist_foreach.h \ + src/lib/smartlist_core/smartlist_split.h diff --git a/src/lib/smartlist_core/smartlist_core.c b/src/lib/smartlist_core/smartlist_core.c new file mode 100644 index 0000000000..b9c5f728ce --- /dev/null +++ b/src/lib/smartlist_core/smartlist_core.c @@ -0,0 +1,234 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file smartlist_core.c + * \brief Implements the core functionality of a smartlist (a resizeable + * dynamic array). For more functionality and helper functions, see the + * container library. + **/ + +#include "lib/err/torerr.h" +#include "lib/malloc/util_malloc.h" +#include "lib/smartlist_core/smartlist_core.h" + +#include <stdlib.h> +#include <string.h> + +/** All newly allocated smartlists have this capacity. */ +#define SMARTLIST_DEFAULT_CAPACITY 16 + +/** Allocate and return an empty smartlist. + */ +MOCK_IMPL(smartlist_t *, +smartlist_new,(void)) +{ + smartlist_t *sl = tor_malloc(sizeof(smartlist_t)); + sl->num_used = 0; + sl->capacity = SMARTLIST_DEFAULT_CAPACITY; + sl->list = tor_calloc(sizeof(void *), sl->capacity); + return sl; +} + +/** Deallocate a smartlist. Does not release storage associated with the + * list's elements. + */ +MOCK_IMPL(void, +smartlist_free_,(smartlist_t *sl)) +{ + if (!sl) + return; + tor_free(sl->list); + tor_free(sl); +} + +/** Remove all elements from the list. + */ +void +smartlist_clear(smartlist_t *sl) +{ + memset(sl->list, 0, sizeof(void *) * sl->num_used); + sl->num_used = 0; +} + +#if SIZE_MAX < INT_MAX +#error "We don't support systems where size_t is smaller than int." +#endif + +/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */ +static inline void +smartlist_ensure_capacity(smartlist_t *sl, size_t size) +{ + /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */ +#if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX +#define MAX_CAPACITY (INT_MAX) +#else +#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*)))) +#endif + + raw_assert(size <= MAX_CAPACITY); + + if (size > (size_t) sl->capacity) { + size_t higher = (size_t) sl->capacity; + if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) { + higher = MAX_CAPACITY; + } else { + while (size > higher) + higher *= 2; + } + sl->list = tor_reallocarray(sl->list, sizeof(void *), + ((size_t)higher)); + memset(sl->list + sl->capacity, 0, + sizeof(void *) * (higher - sl->capacity)); + sl->capacity = (int) higher; + } +#undef ASSERT_CAPACITY +#undef MAX_CAPACITY +} + +/** Append element to the end of the list. */ +void +smartlist_add(smartlist_t *sl, void *element) +{ + smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); + sl->list[sl->num_used++] = element; +} + +/** Append each element from S2 to the end of S1. */ +void +smartlist_add_all(smartlist_t *s1, const smartlist_t *s2) +{ + size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used; + raw_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */ + smartlist_ensure_capacity(s1, new_size); + memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*)); + raw_assert(new_size <= INT_MAX); /* redundant. */ + s1->num_used = (int) new_size; +} + +/** Append a copy of string to sl */ +void +smartlist_add_strdup(struct smartlist_t *sl, const char *string) +{ + char *copy; + + copy = tor_strdup(string); + + smartlist_add(sl, copy); +} + +/** Remove all elements E from sl such that E==element. Preserve + * the order of any elements before E, but elements after E can be + * rearranged. + */ +void +smartlist_remove(smartlist_t *sl, const void *element) +{ + int i; + if (element == NULL) + return; + for (i=0; i < sl->num_used; i++) + if (sl->list[i] == element) { + sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */ + i--; /* so we process the new i'th element */ + sl->list[sl->num_used] = NULL; + } +} + +/** As <b>smartlist_remove</b>, but do not change the order of + * any elements not removed */ +void +smartlist_remove_keeporder(smartlist_t *sl, const void *element) +{ + int i, j, num_used_orig = sl->num_used; + if (element == NULL) + return; + + for (i=j=0; j < num_used_orig; ++j) { + if (sl->list[j] == element) { + --sl->num_used; + } else { + sl->list[i++] = sl->list[j]; + } + } +} + +/** If <b>sl</b> is nonempty, remove and return the final element. Otherwise, + * return NULL. */ +void * +smartlist_pop_last(smartlist_t *sl) +{ + raw_assert(sl); + if (sl->num_used) { + void *tmp = sl->list[--sl->num_used]; + sl->list[sl->num_used] = NULL; + return tmp; + } else + return NULL; +} + +/** Return true iff some element E of sl has E==element. + */ +int +smartlist_contains(const smartlist_t *sl, const void *element) +{ + int i; + for (i=0; i < sl->num_used; i++) + if (sl->list[i] == element) + return 1; + return 0; +} + +/** Remove the <b>idx</b>th element of sl; if idx is not the last + * element, swap the last element of sl into the <b>idx</b>th space. + */ +void +smartlist_del(smartlist_t *sl, int idx) +{ + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(idx < sl->num_used); + sl->list[idx] = sl->list[--sl->num_used]; + sl->list[sl->num_used] = NULL; +} + +/** Remove the <b>idx</b>th element of sl; if idx is not the last element, + * moving all subsequent elements back one space. Return the old value + * of the <b>idx</b>th element. + */ +void +smartlist_del_keeporder(smartlist_t *sl, int idx) +{ + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(idx < sl->num_used); + --sl->num_used; + if (idx < sl->num_used) + memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx)); + sl->list[sl->num_used] = NULL; +} + +/** Insert the value <b>val</b> as the new <b>idx</b>th element of + * <b>sl</b>, moving all items previously at <b>idx</b> or later + * forward one space. + */ +void +smartlist_insert(smartlist_t *sl, int idx, void *val) +{ + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(idx <= sl->num_used); + if (idx == sl->num_used) { + smartlist_add(sl, val); + } else { + smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1); + /* Move other elements away */ + if (idx < sl->num_used) + memmove(sl->list + idx + 1, sl->list + idx, + sizeof(void*)*(sl->num_used-idx)); + sl->num_used++; + sl->list[idx] = val; + } +} diff --git a/src/lib/smartlist_core/smartlist_core.h b/src/lib/smartlist_core/smartlist_core.h new file mode 100644 index 0000000000..b1adf2ebdb --- /dev/null +++ b/src/lib/smartlist_core/smartlist_core.h @@ -0,0 +1,95 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_CORE_H +#define TOR_SMARTLIST_CORE_H + +#include <stddef.h> + +#include "lib/cc/compat_compiler.h" +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" + +/** A resizeable list of pointers, with associated helpful functionality. + * + * The members of this struct are exposed only so that macros and inlines can + * use them; all access to smartlist internals should go through the functions + * and macros defined here. + **/ +typedef struct smartlist_t { + /** @{ */ + /** <b>list</b> has enough capacity to store exactly <b>capacity</b> elements + * before it needs to be resized. Only the first <b>num_used</b> (\<= + * capacity) elements point to valid data. + */ + void **list; + int num_used; + int capacity; + /** @} */ +} smartlist_t; + +MOCK_DECL(smartlist_t *, smartlist_new, (void)); +MOCK_DECL(void, smartlist_free_, (smartlist_t *sl)); +#define smartlist_free(sl) FREE_AND_NULL(smartlist_t, smartlist_free_, (sl)) + +void smartlist_clear(smartlist_t *sl); +void smartlist_add(smartlist_t *sl, void *element); +void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2); +void smartlist_add_strdup(struct smartlist_t *sl, const char *string); + +void smartlist_remove(smartlist_t *sl, const void *element); +void smartlist_remove_keeporder(smartlist_t *sl, const void *element); +void *smartlist_pop_last(smartlist_t *sl); + +int smartlist_contains(const smartlist_t *sl, const void *element); + +/* smartlist_choose() is defined in crypto.[ch] */ +#ifdef DEBUG_SMARTLIST +#include "lib/err/torerr.h" +#include <stdlib.h> +/** Return the number of items in sl. + */ +static inline int smartlist_len(const smartlist_t *sl); +static inline int smartlist_len(const smartlist_t *sl) { + raw_assert(sl); + return (sl)->num_used; +} +/** Return the <b>idx</b>th element of sl. + */ +static inline void *smartlist_get(const smartlist_t *sl, int idx); +static inline void *smartlist_get(const smartlist_t *sl, int idx) { + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(sl->num_used > idx); + return sl->list[idx]; +} +static inline void smartlist_set(smartlist_t *sl, int idx, void *val) { + raw_assert(sl); + raw_assert(idx>=0); + raw_assert(sl->num_used > idx); + sl->list[idx] = val; +} +#else /* !(defined(DEBUG_SMARTLIST)) */ +#define smartlist_len(sl) ((sl)->num_used) +#define smartlist_get(sl, idx) ((sl)->list[idx]) +#define smartlist_set(sl, idx, val) ((sl)->list[idx] = (val)) +#endif /* defined(DEBUG_SMARTLIST) */ + +/** Exchange the elements at indices <b>idx1</b> and <b>idx2</b> of the + * smartlist <b>sl</b>. */ +static inline void smartlist_swap(smartlist_t *sl, int idx1, int idx2) +{ + if (idx1 != idx2) { + void *elt = smartlist_get(sl, idx1); + smartlist_set(sl, idx1, smartlist_get(sl, idx2)); + smartlist_set(sl, idx2, elt); + } +} + +void smartlist_del(smartlist_t *sl, int idx); +void smartlist_del_keeporder(smartlist_t *sl, int idx); +void smartlist_insert(smartlist_t *sl, int idx, void *val); + +#endif /* !defined(TOR_CONTAINER_H) */ diff --git a/src/lib/smartlist_core/smartlist_foreach.h b/src/lib/smartlist_core/smartlist_foreach.h new file mode 100644 index 0000000000..4bef36d99c --- /dev/null +++ b/src/lib/smartlist_core/smartlist_foreach.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_FOREACH_H +#define TOR_SMARTLIST_FOREACH_H + +/** Iterate over the items in a smartlist <b>sl</b>, in order. For each item, + * assign it to a new local variable of type <b>type</b> named <b>var</b>, and + * execute the statements inside the loop body. Inside the loop, the loop + * index can be accessed as <b>var</b>_sl_idx and the length of the list can + * be accessed as <b>var</b>_sl_len. + * + * NOTE: Do not change the length of the list while the loop is in progress, + * unless you adjust the _sl_len variable correspondingly. See second example + * below. + * + * Example use: + * <pre> + * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); + * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { + * printf("%d: %s\n", cp_sl_idx, cp); + * tor_free(cp); + * } SMARTLIST_FOREACH_END(cp); + * smartlist_free(list); + * </pre> + * + * Example use (advanced): + * <pre> + * SMARTLIST_FOREACH_BEGIN(list, char *, cp) { + * if (!strcmp(cp, "junk")) { + * tor_free(cp); + * SMARTLIST_DEL_CURRENT(list, cp); + * } + * } SMARTLIST_FOREACH_END(cp); + * </pre> + */ +/* Note: these macros use token pasting, and reach into smartlist internals. + * This can make them a little daunting. Here's the approximate unpacking of + * the above examples, for entertainment value: + * + * <pre> + * smartlist_t *list = smartlist_split("A:B:C", ":", 0, 0); + * { + * int cp_sl_idx, cp_sl_len = smartlist_len(list); + * char *cp; + * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { + * cp = smartlist_get(list, cp_sl_idx); + * printf("%d: %s\n", cp_sl_idx, cp); + * tor_free(cp); + * } + * } + * smartlist_free(list); + * </pre> + * + * <pre> + * { + * int cp_sl_idx, cp_sl_len = smartlist_len(list); + * char *cp; + * for (cp_sl_idx = 0; cp_sl_idx < cp_sl_len; ++cp_sl_idx) { + * cp = smartlist_get(list, cp_sl_idx); + * if (!strcmp(cp, "junk")) { + * tor_free(cp); + * smartlist_del(list, cp_sl_idx); + * --cp_sl_idx; + * --cp_sl_len; + * } + * } + * } + * </pre> + */ +#define SMARTLIST_FOREACH_BEGIN(sl, type, var) \ + STMT_BEGIN \ + int var ## _sl_idx, var ## _sl_len=(sl)->num_used; \ + type var; \ + for (var ## _sl_idx = 0; var ## _sl_idx < var ## _sl_len; \ + ++var ## _sl_idx) { \ + var = (sl)->list[var ## _sl_idx]; + +#define SMARTLIST_FOREACH_END(var) \ + var = NULL; \ + (void) var ## _sl_idx; \ + } STMT_END + +/** + * An alias for SMARTLIST_FOREACH_BEGIN and SMARTLIST_FOREACH_END, using + * <b>cmd</b> as the loop body. This wrapper is here for convenience with + * very short loops. + * + * By convention, we do not use this for loops which nest, or for loops over + * 10 lines or so. Use SMARTLIST_FOREACH_{BEGIN,END} for those. + */ +#define SMARTLIST_FOREACH(sl, type, var, cmd) \ + SMARTLIST_FOREACH_BEGIN(sl,type,var) { \ + cmd; \ + } SMARTLIST_FOREACH_END(var) + +/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed + * with the variable <b>var</b>, remove the current element in a way that + * won't confuse the loop. */ +#define SMARTLIST_DEL_CURRENT(sl, var) \ + STMT_BEGIN \ + smartlist_del(sl, var ## _sl_idx); \ + --var ## _sl_idx; \ + --var ## _sl_len; \ + STMT_END + +/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed + * with the variable <b>var</b>, remove the current element in a way that + * won't confuse the loop. */ +#define SMARTLIST_DEL_CURRENT_KEEPORDER(sl, var) \ + STMT_BEGIN \ + smartlist_del_keeporder(sl, var ## _sl_idx); \ + --var ## _sl_idx; \ + --var ## _sl_len; \ + STMT_END + +/** Helper: While in a SMARTLIST_FOREACH loop over the list <b>sl</b> indexed + * with the variable <b>var</b>, replace the current element with <b>val</b>. + * Does not deallocate the current value of <b>var</b>. + */ +#define SMARTLIST_REPLACE_CURRENT(sl, var, val) \ + STMT_BEGIN \ + smartlist_set(sl, var ## _sl_idx, val); \ + STMT_END + +#endif /* !defined(TOR_SMARTLIST_FOREACH_H) */ diff --git a/src/lib/smartlist_core/smartlist_split.c b/src/lib/smartlist_core/smartlist_split.c new file mode 100644 index 0000000000..b9340e7924 --- /dev/null +++ b/src/lib/smartlist_core/smartlist_split.c @@ -0,0 +1,87 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/smartlist_core/smartlist_core.h" +#include "lib/smartlist_core/smartlist_split.h" + +#include "lib/err/torerr.h" +#include "lib/string/util_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/malloc/util_malloc.h" + +#include <string.h> + +/** + * Split a string <b>str</b> along all occurrences of <b>sep</b>, + * appending the (newly allocated) split strings, in order, to + * <b>sl</b>. Return the number of strings added to <b>sl</b>. + * + * If <b>flags</b>&SPLIT_SKIP_SPACE is true, remove initial and + * trailing space from each entry. + * If <b>flags</b>&SPLIT_IGNORE_BLANK is true, remove any entries + * of length 0. + * If <b>flags</b>&SPLIT_STRIP_SPACE is true, strip spaces from each + * split string. + * + * If <b>max</b>\>0, divide the string into no more than <b>max</b> pieces. If + * <b>sep</b> is NULL, split on any sequence of horizontal space. + */ +int +smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, + int flags, int max) +{ + const char *cp, *end, *next; + int n = 0; + + raw_assert(sl); + raw_assert(str); + + cp = str; + while (1) { + if (flags&SPLIT_SKIP_SPACE) { + while (TOR_ISSPACE(*cp)) ++cp; + } + + if (max>0 && n == max-1) { + end = strchr(cp,'\0'); + } else if (sep) { + end = strstr(cp,sep); + if (!end) + end = strchr(cp,'\0'); + } else { + for (end = cp; *end && *end != '\t' && *end != ' '; ++end) + ; + } + + raw_assert(end); + + if (!*end) { + next = NULL; + } else if (sep) { + next = end+strlen(sep); + } else { + next = end+1; + while (*next == '\t' || *next == ' ') + ++next; + } + + if (flags&SPLIT_SKIP_SPACE) { + while (end > cp && TOR_ISSPACE(*(end-1))) + --end; + } + if (end != cp || !(flags&SPLIT_IGNORE_BLANK)) { + char *string = tor_strndup(cp, end-cp); + if (flags&SPLIT_STRIP_SPACE) + tor_strstrip(string, " "); + smartlist_add(sl, string); + ++n; + } + if (!next) + break; + cp = next; + } + + return n; +} diff --git a/src/lib/smartlist_core/smartlist_split.h b/src/lib/smartlist_core/smartlist_split.h new file mode 100644 index 0000000000..8ed2abafb8 --- /dev/null +++ b/src/lib/smartlist_core/smartlist_split.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_SMARTLIST_SPLIT_H +#define TOR_SMARTLIST_SPLIT_H + +#define SPLIT_SKIP_SPACE 0x01 +#define SPLIT_IGNORE_BLANK 0x02 +#define SPLIT_STRIP_SPACE 0x04 +int smartlist_split_string(smartlist_t *sl, const char *str, const char *sep, + int flags, int max); + +#endif diff --git a/src/lib/string/.may_include b/src/lib/string/.may_include new file mode 100644 index 0000000000..ec5c769831 --- /dev/null +++ b/src/lib/string/.may_include @@ -0,0 +1,10 @@ +orconfig.h +lib/cc/*.h +lib/defs/*.h +lib/err/*.h +lib/malloc/*.h +lib/ctime/*.h +lib/string/*.h + +strlcat.c +strlcpy.c diff --git a/src/lib/string/compat_ctype.c b/src/lib/string/compat_ctype.c new file mode 100644 index 0000000000..d1d4ce0ffc --- /dev/null +++ b/src/lib/string/compat_ctype.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/compat_ctype.h" + +/** + * Tables to implement ctypes-replacement TOR_IS*() functions. Each table + * has 256 bits to look up whether a character is in some set or not. This + * fails on non-ASCII platforms, but it is hard to find a platform whose + * character set is not a superset of ASCII nowadays. */ + +/**@{*/ +const uint32_t TOR_ISALPHA_TABLE[8] = + { 0, 0, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; +const uint32_t TOR_ISALNUM_TABLE[8] = + { 0, 0x3ff0000, 0x7fffffe, 0x7fffffe, 0, 0, 0, 0 }; +const uint32_t TOR_ISSPACE_TABLE[8] = { 0x3e00, 0x1, 0, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISXDIGIT_TABLE[8] = + { 0, 0x3ff0000, 0x7e, 0x7e, 0, 0, 0, 0 }; +const uint32_t TOR_ISDIGIT_TABLE[8] = { 0, 0x3ff0000, 0, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISPRINT_TABLE[8] = + { 0, 0xffffffff, 0xffffffff, 0x7fffffff, 0, 0, 0, 0x0 }; +const uint32_t TOR_ISUPPER_TABLE[8] = { 0, 0, 0x7fffffe, 0, 0, 0, 0, 0 }; +const uint32_t TOR_ISLOWER_TABLE[8] = { 0, 0, 0, 0x7fffffe, 0, 0, 0, 0 }; + +/** Upper-casing and lowercasing tables to map characters to upper/lowercase + * equivalents. Used by tor_toupper() and tor_tolower(). */ +/**@{*/ +const uint8_t TOR_TOUPPER_TABLE[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95, + 96,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79, + 80,81,82,83,84,85,86,87,88,89,90,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, +}; +const uint8_t TOR_TOLOWER_TABLE[256] = { + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, + 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47, + 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, + 64,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,95, + 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111, + 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, + 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, + 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, + 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, + 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, + 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255, +}; +/**@}*/ diff --git a/src/lib/string/compat_ctype.h b/src/lib/string/compat_ctype.h new file mode 100644 index 0000000000..530a10270f --- /dev/null +++ b/src/lib/string/compat_ctype.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_CTYPE_H +#define TOR_COMPAT_CTYPE_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +/* Much of the time when we're checking ctypes, we're doing spec compliance, + * which all assumes we're doing ASCII. */ +#define DECLARE_CTYPE_FN(name) \ + static int TOR_##name(char c); \ + extern const uint32_t TOR_##name##_TABLE[]; \ + static inline int TOR_##name(char c) { \ + uint8_t u = c; \ + return !!(TOR_##name##_TABLE[(u >> 5) & 7] & (1u << (u & 31))); \ + } +DECLARE_CTYPE_FN(ISALPHA) +DECLARE_CTYPE_FN(ISALNUM) +DECLARE_CTYPE_FN(ISSPACE) +DECLARE_CTYPE_FN(ISDIGIT) +DECLARE_CTYPE_FN(ISXDIGIT) +DECLARE_CTYPE_FN(ISPRINT) +DECLARE_CTYPE_FN(ISLOWER) +DECLARE_CTYPE_FN(ISUPPER) +extern const uint8_t TOR_TOUPPER_TABLE[]; +extern const uint8_t TOR_TOLOWER_TABLE[]; +#define TOR_TOLOWER(c) (TOR_TOLOWER_TABLE[(uint8_t)c]) +#define TOR_TOUPPER(c) (TOR_TOUPPER_TABLE[(uint8_t)c]) + +static inline int hex_decode_digit(char c); + +/** Helper: given a hex digit, return its value, or -1 if it isn't hex. */ +static inline int +hex_decode_digit(char c) +{ + switch (c) { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': case 'a': return 10; + case 'B': case 'b': return 11; + case 'C': case 'c': return 12; + case 'D': case 'd': return 13; + case 'E': case 'e': return 14; + case 'F': case 'f': return 15; + default: + return -1; + } +} + +#endif /* !defined(TOR_COMPAT_CTYPE_H) */ diff --git a/src/lib/string/compat_string.c b/src/lib/string/compat_string.c new file mode 100644 index 0000000000..8b063b7242 --- /dev/null +++ b/src/lib/string/compat_string.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/compat_string.h" +#include "lib/err/torerr.h" + +/* Inline the strl functions if the platform doesn't have them. */ +#ifndef HAVE_STRLCPY +#include "strlcpy.c" +#endif +#ifndef HAVE_STRLCAT +#include "strlcat.c" +#endif + +#include <stdlib.h> +#include <string.h> + +/** Helper for tor_strtok_r_impl: Advances cp past all characters in + * <b>sep</b>, and returns its new value. */ +static char * +strtok_helper(char *cp, const char *sep) +{ + if (sep[1]) { + while (*cp && strchr(sep, *cp)) + ++cp; + } else { + while (*cp && *cp == *sep) + ++cp; + } + return cp; +} + +/** Implementation of strtok_r for platforms whose coders haven't figured out + * how to write one. Hey, retrograde libc developers! You can use this code + * here for free! */ +char * +tor_strtok_r_impl(char *str, const char *sep, char **lasts) +{ + char *cp, *start; + raw_assert(*sep); + if (str) { + str = strtok_helper(str, sep); + if (!*str) + return NULL; + start = cp = *lasts = str; + } else if (!*lasts || !**lasts) { + return NULL; + } else { + start = cp = *lasts; + } + + if (sep[1]) { + while (*cp && !strchr(sep, *cp)) + ++cp; + } else { + cp = strchr(cp, *sep); + } + + if (!cp || !*cp) { + *lasts = NULL; + } else { + *cp++ = '\0'; + *lasts = strtok_helper(cp, sep); + } + return start; +} diff --git a/src/lib/string/compat_string.h b/src/lib/string/compat_string.h new file mode 100644 index 0000000000..5879c28fc2 --- /dev/null +++ b/src/lib/string/compat_string.h @@ -0,0 +1,57 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_COMPAT_STRING_H +#define TOR_COMPAT_STRING_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stddef.h> + +/* ===== String compatibility */ +#ifdef _WIN32 +/* Windows doesn't have str(n)casecmp, but mingw defines it: only define it + * ourselves if it's missing. */ +#ifndef HAVE_STRNCASECMP +static inline int strncasecmp(const char *a, const char *b, size_t n); +static inline int strncasecmp(const char *a, const char *b, size_t n) { + return _strnicmp(a,b,n); +} +#endif +#ifndef HAVE_STRCASECMP +static inline int strcasecmp(const char *a, const char *b, size_t n); +static inline int strcasecmp(const char *a, const char *b, size_t n) { + return _stricmp(a,b); +} +#endif +#endif + +#if defined __APPLE__ +/* On OSX 10.9 and later, the overlap-checking code for strlcat would + * appear to have a severe bug that can sometimes cause aborts in Tor. + * Instead, use the non-checking variants. This is sad. + * + * See https://trac.torproject.org/projects/tor/ticket/15205 + */ +#undef strlcat +#undef strlcpy +#endif /* defined __APPLE__ */ + +#ifndef HAVE_STRLCAT +size_t strlcat(char *dst, const char *src, size_t siz); +#endif +#ifndef HAVE_STRLCPY +size_t strlcpy(char *dst, const char *src, size_t siz); +#endif + +char *tor_strtok_r_impl(char *str, const char *sep, char **lasts); +#ifdef HAVE_STRTOK_R +#define tor_strtok_r(str, sep, lasts) strtok_r(str, sep, lasts) +#else +#define tor_strtok_r(str, sep, lasts) tor_strtok_r_impl(str, sep, lasts) +#endif + +#endif diff --git a/src/lib/string/include.am b/src/lib/string/include.am new file mode 100644 index 0000000000..edd74b8a3e --- /dev/null +++ b/src/lib/string/include.am @@ -0,0 +1,27 @@ + +noinst_LIBRARIES += src/lib/libtor-string.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-string-testing.a +endif + +src_lib_libtor_string_a_SOURCES = \ + src/lib/string/compat_ctype.c \ + src/lib/string/compat_string.c \ + src/lib/string/util_string.c \ + src/lib/string/parse_int.c \ + src/lib/string/printf.c \ + src/lib/string/scanf.c + +src_lib_libtor_string_testing_a_SOURCES = \ + $(src_lib_libtor_string_a_SOURCES) +src_lib_libtor_string_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_string_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/string/compat_ctype.h \ + src/lib/string/compat_string.h \ + src/lib/string/util_string.h \ + src/lib/string/parse_int.h \ + src/lib/string/printf.h \ + src/lib/string/scanf.h diff --git a/src/lib/string/parse_int.c b/src/lib/string/parse_int.c new file mode 100644 index 0000000000..e552730cc4 --- /dev/null +++ b/src/lib/string/parse_int.c @@ -0,0 +1,126 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/parse_int.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +/* Helper: common code to check whether the result of a strtol or strtoul or + * strtoll is correct. */ +#define CHECK_STRTOX_RESULT() \ + /* Did an overflow occur? */ \ + if (errno == ERANGE) \ + goto err; \ + /* Was at least one character converted? */ \ + if (endptr == s) \ + goto err; \ + /* Were there unexpected unconverted characters? */ \ + if (!next && *endptr) \ + goto err; \ + /* Illogical (max, min) inputs? */ \ + if (max < min) \ + goto err; \ + /* Is r within limits? */ \ + if (r < min || r > max) \ + goto err; \ + if (ok) *ok = 1; \ + if (next) *next = endptr; \ + return r; \ + err: \ + if (ok) *ok = 0; \ + if (next) *next = endptr; \ + return 0 + +/** Extract a long from the start of <b>s</b>, in the given numeric + * <b>base</b>. If <b>base</b> is 0, <b>s</b> is parsed as a decimal, + * octal, or hex number in the syntax of a C integer literal. If + * there is unconverted data and <b>next</b> is provided, set + * *<b>next</b> to the first unconverted character. An error has + * occurred if no characters are converted; or if there are + * unconverted characters and <b>next</b> is NULL; or if the parsed + * value is not between <b>min</b> and <b>max</b>. When no error + * occurs, return the parsed value and set *<b>ok</b> (if provided) to + * 1. When an error occurs, return 0 and set *<b>ok</b> (if provided) + * to 0. + */ +long +tor_parse_long(const char *s, int base, long min, long max, + int *ok, char **next) +{ + char *endptr; + long r; + + if (base < 0) { + if (ok) + *ok = 0; + return 0; + } + + errno = 0; + r = strtol(s, &endptr, base); + CHECK_STRTOX_RESULT(); +} + +/** As tor_parse_long(), but return an unsigned long. */ +unsigned long +tor_parse_ulong(const char *s, int base, unsigned long min, + unsigned long max, int *ok, char **next) +{ + char *endptr; + unsigned long r; + + if (base < 0) { + if (ok) + *ok = 0; + return 0; + } + + errno = 0; + r = strtoul(s, &endptr, base); + CHECK_STRTOX_RESULT(); +} + +/** As tor_parse_long(), but return a double. */ +double +tor_parse_double(const char *s, double min, double max, int *ok, char **next) +{ + char *endptr; + double r; + + errno = 0; + r = strtod(s, &endptr); + CHECK_STRTOX_RESULT(); +} + +/** As tor_parse_long, but return a uint64_t. Only base 10 is guaranteed to + * work for now. */ +uint64_t +tor_parse_uint64(const char *s, int base, uint64_t min, + uint64_t max, int *ok, char **next) +{ + char *endptr; + uint64_t r; + + if (base < 0) { + if (ok) + *ok = 0; + return 0; + } + + errno = 0; +#ifdef HAVE_STRTOULL + r = (uint64_t)strtoull(s, &endptr, base); +#elif defined(_WIN32) + r = (uint64_t)_strtoui64(s, &endptr, base); +#elif SIZEOF_LONG == 8 + r = (uint64_t)strtoul(s, &endptr, base); +#else +#error "I don't know how to parse 64-bit numbers." +#endif /* defined(HAVE_STRTOULL) || ... */ + + CHECK_STRTOX_RESULT(); +} diff --git a/src/lib/string/parse_int.h b/src/lib/string/parse_int.h new file mode 100644 index 0000000000..6f56fc32a8 --- /dev/null +++ b/src/lib/string/parse_int.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_PARSE_INT_H +#define TOR_PARSE_INT_H + +#include "lib/cc/torint.h" + +long tor_parse_long(const char *s, int base, long min, + long max, int *ok, char **next); +unsigned long tor_parse_ulong(const char *s, int base, unsigned long min, + unsigned long max, int *ok, char **next); +double tor_parse_double(const char *s, double min, double max, int *ok, + char **next); +uint64_t tor_parse_uint64(const char *s, int base, uint64_t min, + uint64_t max, int *ok, char **next); + +#endif diff --git a/src/lib/string/printf.c b/src/lib/string/printf.c new file mode 100644 index 0000000000..4443e25fb4 --- /dev/null +++ b/src/lib/string/printf.c @@ -0,0 +1,152 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/printf.h" +#include "lib/err/torerr.h" +#include "lib/cc/torint.h" +#include "lib/malloc/util_malloc.h" + +#include <stdlib.h> +#include <stdio.h> + +/** Replacement for snprintf. Differs from platform snprintf in two + * ways: First, always NUL-terminates its output. Second, always + * returns -1 if the result is truncated. (Note that this return + * behavior does <i>not</i> conform to C99; it just happens to be + * easier to emulate "return -1" with conformant implementations than + * it is to emulate "return number that would be written" with + * non-conformant implementations.) */ +int +tor_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int r; + va_start(ap,format); + r = tor_vsnprintf(str,size,format,ap); + va_end(ap); + return r; +} + +/** Replacement for vsnprintf; behavior differs as tor_snprintf differs from + * snprintf. + */ +int +tor_vsnprintf(char *str, size_t size, const char *format, va_list args) +{ + int r; + if (size == 0) + return -1; /* no place for the NUL */ + if (size > SIZE_T_CEILING) + return -1; +#ifdef _WIN32 + r = _vsnprintf(str, size, format, args); +#else + r = vsnprintf(str, size, format, args); +#endif + str[size-1] = '\0'; + if (r < 0 || r >= (ssize_t)size) + return -1; + return r; +} + +/** + * Portable asprintf implementation. Does a printf() into a newly malloc'd + * string. Sets *<b>strp</b> to this string, and returns its length (not + * including the terminating NUL character). + * + * You can treat this function as if its implementation were something like + <pre> + char buf[_INFINITY_]; + tor_snprintf(buf, sizeof(buf), fmt, args); + *strp = tor_strdup(buf); + return strlen(*strp): + </pre> + * Where _INFINITY_ is an imaginary constant so big that any string can fit + * into it. + */ +int +tor_asprintf(char **strp, const char *fmt, ...) +{ + int r; + va_list args; + va_start(args, fmt); + r = tor_vasprintf(strp, fmt, args); + va_end(args); + if (!*strp || r < 0) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("Internal error in asprintf"); + /* LCOV_EXCL_STOP */ + } + return r; +} + +/** + * Portable vasprintf implementation. Does a printf() into a newly malloc'd + * string. Differs from regular vasprintf in the same ways that + * tor_asprintf() differs from regular asprintf. + */ +int +tor_vasprintf(char **strp, const char *fmt, va_list args) +{ + /* use a temporary variable in case *strp is in args. */ + char *strp_tmp=NULL; +#ifdef HAVE_VASPRINTF + /* If the platform gives us one, use it. */ + int r = vasprintf(&strp_tmp, fmt, args); + if (r < 0) + *strp = NULL; + else + *strp = strp_tmp; + return r; +#elif defined(HAVE__VSCPRINTF) + /* On Windows, _vsnprintf won't tell us the length of the string if it + * overflows, so we need to use _vcsprintf to tell how much to allocate */ + int len, r; + va_list tmp_args; + va_copy(tmp_args, args); + len = _vscprintf(fmt, tmp_args); + va_end(tmp_args); + if (len < 0) { + *strp = NULL; + return -1; + } + strp_tmp = tor_malloc(len + 1); + r = _vsnprintf(strp_tmp, len+1, fmt, args); + if (r != len) { + tor_free(strp_tmp); + *strp = NULL; + return -1; + } + *strp = strp_tmp; + return len; +#else + /* Everywhere else, we have a decent vsnprintf that tells us how many + * characters we need. We give it a try on a short buffer first, since + * it might be nice to avoid the second vsnprintf call. + */ + char buf[128]; + int len, r; + va_list tmp_args; + va_copy(tmp_args, args); + /* vsnprintf() was properly checked but tor_vsnprintf() available so + * why not use it? */ + len = tor_vsnprintf(buf, sizeof(buf), fmt, tmp_args); + va_end(tmp_args); + if (len < (int)sizeof(buf)) { + *strp = tor_strdup(buf); + return len; + } + strp_tmp = tor_malloc(len+1); + /* use of tor_vsnprintf() will ensure string is null terminated */ + r = tor_vsnprintf(strp_tmp, len+1, fmt, args); + if (r != len) { + tor_free(strp_tmp); + *strp = NULL; + return -1; + } + *strp = strp_tmp; + return len; +#endif /* defined(HAVE_VASPRINTF) || ... */ +} diff --git a/src/lib/string/printf.h b/src/lib/string/printf.h new file mode 100644 index 0000000000..69b724379a --- /dev/null +++ b/src/lib/string/printf.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_UTIL_PRINTF_H +#define TOR_UTIL_PRINTF_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stdarg.h> +#include <stddef.h> + +int tor_snprintf(char *str, size_t size, const char *format, ...) + CHECK_PRINTF(3,4); +int tor_vsnprintf(char *str, size_t size, const char *format, va_list args) + CHECK_PRINTF(3,0); + +int tor_asprintf(char **strp, const char *fmt, ...) + CHECK_PRINTF(2,3); +int tor_vasprintf(char **strp, const char *fmt, va_list args) + CHECK_PRINTF(2,0); + +#endif /* !defined(TOR_UTIL_STRING_H) */ diff --git a/src/lib/string/scanf.c b/src/lib/string/scanf.c new file mode 100644 index 0000000000..0c5082799c --- /dev/null +++ b/src/lib/string/scanf.c @@ -0,0 +1,312 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/scanf.h" +#include "lib/string/compat_ctype.h" +#include "lib/cc/torint.h" +#include "lib/err/torerr.h" + +#include <stdlib.h> + +#define MAX_SCANF_WIDTH 9999 + +/** Helper: given an ASCII-encoded decimal digit, return its numeric value. + * NOTE: requires that its input be in-bounds. */ +static int +digit_to_num(char d) +{ + int num = ((int)d) - (int)'0'; + raw_assert(num <= 9 && num >= 0); + return num; +} + +/** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b> + * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On + * success, store the result in <b>out</b>, advance bufp to the next + * character, and return 0. On failure, return -1. */ +static int +scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base) +{ + unsigned long result = 0; + int scanned_so_far = 0; + const int hex = base==16; + raw_assert(base == 10 || base == 16); + if (!bufp || !*bufp || !out) + return -1; + if (width<0) + width=MAX_SCANF_WIDTH; + + while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp)) + && scanned_so_far < width) { + unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++); + // Check for overflow beforehand, without actually causing any overflow + // This preserves functionality on compilers that don't wrap overflow + // (i.e. that trap or optimise away overflow) + // result * base + digit > ULONG_MAX + // result * base > ULONG_MAX - digit + if (result > (ULONG_MAX - digit)/base) + return -1; /* Processing this digit would overflow */ + result = result * base + digit; + ++scanned_so_far; + } + + if (!scanned_so_far) /* No actual digits scanned */ + return -1; + + *out = result; + return 0; +} + +/** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b> + * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On + * success, store the result in <b>out</b>, advance bufp to the next + * character, and return 0. On failure, return -1. */ +static int +scan_signed(const char **bufp, long *out, int width) +{ + int neg = 0; + unsigned long result = 0; + + if (!bufp || !*bufp || !out) + return -1; + if (width<0) + width=MAX_SCANF_WIDTH; + + if (**bufp == '-') { + neg = 1; + ++*bufp; + --width; + } + + if (scan_unsigned(bufp, &result, width, 10) < 0) + return -1; + + if (neg && result > 0) { + if (result > ((unsigned long)LONG_MAX) + 1) + return -1; /* Underflow */ + else if (result == ((unsigned long)LONG_MAX) + 1) + *out = LONG_MIN; + else { + /* We once had a far more clever no-overflow conversion here, but + * some versions of GCC apparently ran it into the ground. Now + * we just check for LONG_MIN explicitly. + */ + *out = -(long)result; + } + } else { + if (result > LONG_MAX) + return -1; /* Overflow */ + *out = (long)result; + } + + return 0; +} + +/** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to + * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less + * than 0.) On success, store the result in <b>out</b>, advance bufp to the + * next character, and return 0. On failure, return -1. */ +static int +scan_double(const char **bufp, double *out, int width) +{ + int neg = 0; + double result = 0; + int scanned_so_far = 0; + + if (!bufp || !*bufp || !out) + return -1; + if (width<0) + width=MAX_SCANF_WIDTH; + + if (**bufp == '-') { + neg = 1; + ++*bufp; + } + + while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { + const int digit = digit_to_num(*(*bufp)++); + result = result * 10 + digit; + ++scanned_so_far; + } + if (**bufp == '.') { + double fracval = 0, denominator = 1; + ++*bufp; + ++scanned_so_far; + while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) { + const int digit = digit_to_num(*(*bufp)++); + fracval = fracval * 10 + digit; + denominator *= 10; + ++scanned_so_far; + } + result += fracval / denominator; + } + + if (!scanned_so_far) /* No actual digits scanned */ + return -1; + + *out = neg ? -result : result; + return 0; +} + +/** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to + * <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b> + * to the next non-space character or the EOS. */ +static int +scan_string(const char **bufp, char *out, int width) +{ + int scanned_so_far = 0; + if (!bufp || !out || width < 0) + return -1; + while (**bufp && ! TOR_ISSPACE(**bufp) && scanned_so_far < width) { + *out++ = *(*bufp)++; + ++scanned_so_far; + } + *out = '\0'; + return 0; +} + +/** Locale-independent, minimal, no-surprises scanf variant, accepting only a + * restricted pattern format. For more info on what it supports, see + * tor_sscanf() documentation. */ +int +tor_vsscanf(const char *buf, const char *pattern, va_list ap) +{ + int n_matched = 0; + + while (*pattern) { + if (*pattern != '%') { + if (*buf == *pattern) { + ++buf; + ++pattern; + continue; + } else { + return n_matched; + } + } else { + int width = -1; + int longmod = 0; + ++pattern; + if (TOR_ISDIGIT(*pattern)) { + width = digit_to_num(*pattern++); + while (TOR_ISDIGIT(*pattern)) { + width *= 10; + width += digit_to_num(*pattern++); + if (width > MAX_SCANF_WIDTH) + return -1; + } + if (!width) /* No zero-width things. */ + return -1; + } + if (*pattern == 'l') { + longmod = 1; + ++pattern; + } + if (*pattern == 'u' || *pattern == 'x') { + unsigned long u; + const int base = (*pattern == 'u') ? 10 : 16; + if (!*buf) + return n_matched; + if (scan_unsigned(&buf, &u, width, base)<0) + return n_matched; + if (longmod) { + unsigned long *out = va_arg(ap, unsigned long *); + *out = u; + } else { + unsigned *out = va_arg(ap, unsigned *); + if (u > UINT_MAX) + return n_matched; + *out = (unsigned) u; + } + ++pattern; + ++n_matched; + } else if (*pattern == 'f') { + double *d = va_arg(ap, double *); + if (!longmod) + return -1; /* float not supported */ + if (!*buf) + return n_matched; + if (scan_double(&buf, d, width)<0) + return n_matched; + ++pattern; + ++n_matched; + } else if (*pattern == 'd') { + long lng=0; + if (scan_signed(&buf, &lng, width)<0) + return n_matched; + if (longmod) { + long *out = va_arg(ap, long *); + *out = lng; + } else { + int *out = va_arg(ap, int *); +#if LONG_MAX > INT_MAX + if (lng < INT_MIN || lng > INT_MAX) + return n_matched; +#endif + *out = (int)lng; + } + ++pattern; + ++n_matched; + } else if (*pattern == 's') { + char *s = va_arg(ap, char *); + if (longmod) + return -1; + if (width < 0) + return -1; + if (scan_string(&buf, s, width)<0) + return n_matched; + ++pattern; + ++n_matched; + } else if (*pattern == 'c') { + char *ch = va_arg(ap, char *); + if (longmod) + return -1; + if (width != -1) + return -1; + if (!*buf) + return n_matched; + *ch = *buf++; + ++pattern; + ++n_matched; + } else if (*pattern == '%') { + if (*buf != '%') + return n_matched; + if (longmod) + return -1; + ++buf; + ++pattern; + } else { + return -1; /* Unrecognized pattern component. */ + } + } + } + + return n_matched; +} + +/** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b> + * and store the results in the corresponding argument fields. Differs from + * sscanf in that: + * <ul><li>It only handles %u, %lu, %x, %lx, %[NUM]s, %d, %ld, %lf, and %c. + * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1) + * <li>It does not handle arbitrarily long widths. + * <li>Numbers do not consume any space characters. + * <li>It is locale-independent. + * <li>%u and %x do not consume any space. + * <li>It returns -1 on malformed patterns.</ul> + * + * (As with other locale-independent functions, we need this to parse data that + * is in ASCII without worrying that the C library's locale-handling will make + * miscellaneous characters look like numbers, spaces, and so on.) + */ +int +tor_sscanf(const char *buf, const char *pattern, ...) +{ + int r; + va_list ap; + va_start(ap, pattern); + r = tor_vsscanf(buf, pattern, ap); + va_end(ap); + return r; +} diff --git a/src/lib/string/scanf.h b/src/lib/string/scanf.h new file mode 100644 index 0000000000..9cfa9cc6c1 --- /dev/null +++ b/src/lib/string/scanf.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_UTIL_SCANF_H +#define TOR_UTIL_SCANF_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stdarg.h> + +int tor_vsscanf(const char *buf, const char *pattern, va_list ap) \ + CHECK_SCANF(2, 0); +int tor_sscanf(const char *buf, const char *pattern, ...) + CHECK_SCANF(2, 3); + +#endif /* !defined(TOR_UTIL_STRING_H) */ diff --git a/src/lib/string/util_string.c b/src/lib/string/util_string.c new file mode 100644 index 0000000000..e8ed3d4f54 --- /dev/null +++ b/src/lib/string/util_string.c @@ -0,0 +1,448 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/string/util_string.h" +#include "lib/string/compat_ctype.h" +#include "lib/err/torerr.h" +#include "lib/ctime/di_ops.h" +#include "lib/defs/digest_sizes.h" + +#include <string.h> +#include <stdlib.h> + +/** Given <b>hlen</b> bytes at <b>haystack</b> and <b>nlen</b> bytes at + * <b>needle</b>, return a pointer to the first occurrence of the needle + * within the haystack, or NULL if there is no such occurrence. + * + * This function is <em>not</em> timing-safe. + * + * Requires that <b>nlen</b> be greater than zero. + */ +const void * +tor_memmem(const void *_haystack, size_t hlen, + const void *_needle, size_t nlen) +{ +#if defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) + raw_assert(nlen); + return memmem(_haystack, hlen, _needle, nlen); +#else + /* This isn't as fast as the GLIBC implementation, but it doesn't need to + * be. */ + const char *p, *last_possible_start; + const char *haystack = (const char*)_haystack; + const char *needle = (const char*)_needle; + char first; + raw_assert(nlen); + + if (nlen > hlen) + return NULL; + + p = haystack; + /* Last position at which the needle could start. */ + last_possible_start = haystack + hlen - nlen; + first = *(const char*)needle; + while ((p = memchr(p, first, last_possible_start + 1 - p))) { + if (fast_memeq(p, needle, nlen)) + return p; + if (++p > last_possible_start) { + /* This comparison shouldn't be necessary, since if p was previously + * equal to last_possible_start, the next memchr call would be + * "memchr(p, first, 0)", which will return NULL. But it clarifies the + * logic. */ + return NULL; + } + } + return NULL; +#endif /* defined(HAVE_MEMMEM) && (!defined(__GNUC__) || __GNUC__ >= 2) */ +} + +const void * +tor_memstr(const void *haystack, size_t hlen, const char *needle) +{ + return tor_memmem(haystack, hlen, needle, strlen(needle)); +} + +/** Return true iff the 'len' bytes at 'mem' are all zero. */ +int +tor_mem_is_zero(const char *mem, size_t len) +{ + static const char ZERO[] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, + }; + while (len >= sizeof(ZERO)) { + /* It's safe to use fast_memcmp here, since the very worst thing an + * attacker could learn is how many initial bytes of a secret were zero */ + if (fast_memcmp(mem, ZERO, sizeof(ZERO))) + return 0; + len -= sizeof(ZERO); + mem += sizeof(ZERO); + } + /* Deal with leftover bytes. */ + if (len) + return fast_memeq(mem, ZERO, len); + + return 1; +} + +/** Return true iff the DIGEST_LEN bytes in digest are all zero. */ +int +tor_digest_is_zero(const char *digest) +{ + static const uint8_t ZERO_DIGEST[] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 + }; + return tor_memeq(digest, ZERO_DIGEST, DIGEST_LEN); +} + +/** Return true iff the DIGEST256_LEN bytes in digest are all zero. */ +int +tor_digest256_is_zero(const char *digest) +{ + return tor_mem_is_zero(digest, DIGEST256_LEN); +} + +/** Remove from the string <b>s</b> every character which appears in + * <b>strip</b>. */ +void +tor_strstrip(char *s, const char *strip) +{ + char *readp = s; + while (*readp) { + if (strchr(strip, *readp)) { + ++readp; + } else { + *s++ = *readp++; + } + } + *s = '\0'; +} + +/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to + * lowercase. */ +void +tor_strlower(char *s) +{ + while (*s) { + *s = TOR_TOLOWER(*s); + ++s; + } +} + +/** Convert all alphabetic characters in the nul-terminated string <b>s</b> to + * lowercase. */ +void +tor_strupper(char *s) +{ + while (*s) { + *s = TOR_TOUPPER(*s); + ++s; + } +} + +/** Return 1 if every character in <b>s</b> is printable, else return 0. + */ +int +tor_strisprint(const char *s) +{ + while (*s) { + if (!TOR_ISPRINT(*s)) + return 0; + s++; + } + return 1; +} + +/** Return 1 if no character in <b>s</b> is uppercase, else return 0. + */ +int +tor_strisnonupper(const char *s) +{ + while (*s) { + if (TOR_ISUPPER(*s)) + return 0; + s++; + } + return 1; +} + +/** Return true iff every character in <b>s</b> is whitespace space; else + * return false. */ +int +tor_strisspace(const char *s) +{ + while (*s) { + if (!TOR_ISSPACE(*s)) + return 0; + s++; + } + return 1; +} + +/** As strcmp, except that either string may be NULL. The NULL string is + * considered to be before any non-NULL string. */ +int +strcmp_opt(const char *s1, const char *s2) +{ + if (!s1) { + if (!s2) + return 0; + else + return -1; + } else if (!s2) { + return 1; + } else { + return strcmp(s1, s2); + } +} + +/** Compares the first strlen(s2) characters of s1 with s2. Returns as for + * strcmp. + */ +int +strcmpstart(const char *s1, const char *s2) +{ + size_t n = strlen(s2); + return strncmp(s1, s2, n); +} + +/** Compare the s1_len-byte string <b>s1</b> with <b>s2</b>, + * without depending on a terminating nul in s1. Sorting order is first by + * length, then lexically; return values are as for strcmp. + */ +int +strcmp_len(const char *s1, const char *s2, size_t s1_len) +{ + size_t s2_len = strlen(s2); + if (s1_len < s2_len) + return -1; + if (s1_len > s2_len) + return 1; + return fast_memcmp(s1, s2, s2_len); +} + +/** Compares the first strlen(s2) characters of s1 with s2. Returns as for + * strcasecmp. + */ +int +strcasecmpstart(const char *s1, const char *s2) +{ + size_t n = strlen(s2); + return strncasecmp(s1, s2, n); +} + +/** Compare the value of the string <b>prefix</b> with the start of the + * <b>memlen</b>-byte memory chunk at <b>mem</b>. Return as for strcmp. + * + * [As fast_memcmp(mem, prefix, strlen(prefix)) but returns -1 if memlen is + * less than strlen(prefix).] + */ +int +fast_memcmpstart(const void *mem, size_t memlen, + const char *prefix) +{ + size_t plen = strlen(prefix); + if (memlen < plen) + return -1; + return fast_memcmp(mem, prefix, plen); +} + +/** Compares the last strlen(s2) characters of s1 with s2. Returns as for + * strcmp. + */ +int +strcmpend(const char *s1, const char *s2) +{ + size_t n1 = strlen(s1), n2 = strlen(s2); + if (n2>n1) + return strcmp(s1,s2); + else + return strncmp(s1+(n1-n2), s2, n2); +} + +/** Compares the last strlen(s2) characters of s1 with s2. Returns as for + * strcasecmp. + */ +int +strcasecmpend(const char *s1, const char *s2) +{ + size_t n1 = strlen(s1), n2 = strlen(s2); + if (n2>n1) /* then they can't be the same; figure out which is bigger */ + return strcasecmp(s1,s2); + else + return strncasecmp(s1+(n1-n2), s2, n2); +} + +/** Return a pointer to the first char of s that is not whitespace and + * not a comment, or to the terminating NUL if no such character exists. + */ +const char * +eat_whitespace(const char *s) +{ + raw_assert(s); + + while (1) { + switch (*s) { + case '\0': + default: + return s; + case ' ': + case '\t': + case '\n': + case '\r': + ++s; + break; + case '#': + ++s; + while (*s && *s != '\n') + ++s; + } + } +} + +/** Return a pointer to the first char of s that is not whitespace and + * not a comment, or to the terminating NUL if no such character exists. + */ +const char * +eat_whitespace_eos(const char *s, const char *eos) +{ + raw_assert(s); + raw_assert(eos && s <= eos); + + while (s < eos) { + switch (*s) { + case '\0': + default: + return s; + case ' ': + case '\t': + case '\n': + case '\r': + ++s; + break; + case '#': + ++s; + while (s < eos && *s && *s != '\n') + ++s; + } + } + return s; +} + +/** Return a pointer to the first char of s that is not a space or a tab + * or a \\r, or to the terminating NUL if no such character exists. */ +const char * +eat_whitespace_no_nl(const char *s) +{ + while (*s == ' ' || *s == '\t' || *s == '\r') + ++s; + return s; +} + +/** As eat_whitespace_no_nl, but stop at <b>eos</b> whether we have + * found a non-whitespace character or not. */ +const char * +eat_whitespace_eos_no_nl(const char *s, const char *eos) +{ + while (s < eos && (*s == ' ' || *s == '\t' || *s == '\r')) + ++s; + return s; +} + +/** Return a pointer to the first char of s that is whitespace or <b>#</b>, + * or to the terminating NUL if no such character exists. + */ +const char * +find_whitespace(const char *s) +{ + /* tor_assert(s); */ + while (1) { + switch (*s) + { + case '\0': + case '#': + case ' ': + case '\r': + case '\n': + case '\t': + return s; + default: + ++s; + } + } +} + +/** As find_whitespace, but stop at <b>eos</b> whether we have found a + * whitespace or not. */ +const char * +find_whitespace_eos(const char *s, const char *eos) +{ + /* tor_assert(s); */ + while (s < eos) { + switch (*s) + { + case '\0': + case '#': + case ' ': + case '\r': + case '\n': + case '\t': + return s; + default: + ++s; + } + } + return s; +} + +/** Return the first occurrence of <b>needle</b> in <b>haystack</b> that + * occurs at the start of a line (that is, at the beginning of <b>haystack</b> + * or immediately after a newline). Return NULL if no such string is found. + */ +const char * +find_str_at_start_of_line(const char *haystack, const char *needle) +{ + size_t needle_len = strlen(needle); + + do { + if (!strncmp(haystack, needle, needle_len)) + return haystack; + + haystack = strchr(haystack, '\n'); + if (!haystack) + return NULL; + else + ++haystack; + } while (*haystack); + + return NULL; +} + +/** Returns true if <b>string</b> could be a C identifier. + A C identifier must begin with a letter or an underscore and the + rest of its characters can be letters, numbers or underscores. No + length limit is imposed. */ +int +string_is_C_identifier(const char *string) +{ + size_t iter; + size_t length = strlen(string); + if (!length) + return 0; + + for (iter = 0; iter < length ; iter++) { + if (iter == 0) { + if (!(TOR_ISALPHA(string[iter]) || + string[iter] == '_')) + return 0; + } else { + if (!(TOR_ISALPHA(string[iter]) || + TOR_ISDIGIT(string[iter]) || + string[iter] == '_')) + return 0; + } + } + + return 1; +} diff --git a/src/lib/string/util_string.h b/src/lib/string/util_string.h new file mode 100644 index 0000000000..75407d5ffa --- /dev/null +++ b/src/lib/string/util_string.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_UTIL_STRING_H +#define TOR_UTIL_STRING_H + +#include "orconfig.h" +#include "lib/cc/compat_compiler.h" + +#include <stddef.h> + +const void *tor_memmem(const void *haystack, size_t hlen, const void *needle, + size_t nlen); +const void *tor_memstr(const void *haystack, size_t hlen, + const char *needle); +int tor_mem_is_zero(const char *mem, size_t len); +int tor_digest_is_zero(const char *digest); +int tor_digest256_is_zero(const char *digest); + +/** Allowable characters in a hexadecimal string. */ +#define HEX_CHARACTERS "0123456789ABCDEFabcdef" +void tor_strlower(char *s); +void tor_strupper(char *s); +int tor_strisprint(const char *s); +int tor_strisnonupper(const char *s); +int tor_strisspace(const char *s); +int strcmp_opt(const char *s1, const char *s2); +int strcmpstart(const char *s1, const char *s2); +int strcmp_len(const char *s1, const char *s2, size_t len); +int strcasecmpstart(const char *s1, const char *s2); +int strcmpend(const char *s1, const char *s2); +int strcasecmpend(const char *s1, const char *s2); +int fast_memcmpstart(const void *mem, size_t memlen, const char *prefix); + +void tor_strstrip(char *s, const char *strip); + +const char *eat_whitespace(const char *s); +const char *eat_whitespace_eos(const char *s, const char *eos); +const char *eat_whitespace_no_nl(const char *s); +const char *eat_whitespace_eos_no_nl(const char *s, const char *eos); +const char *find_whitespace(const char *s); +const char *find_whitespace_eos(const char *s, const char *eos); +const char *find_str_at_start_of_line(const char *haystack, + const char *needle); + +int string_is_C_identifier(const char *string); + +#endif /* !defined(TOR_UTIL_STRING_H) */ diff --git a/src/lib/term/.may_include b/src/lib/term/.may_include new file mode 100644 index 0000000000..c93a06e59e --- /dev/null +++ b/src/lib/term/.may_include @@ -0,0 +1,9 @@ +orconfig.h + +lib/cc/*.h +lib/log/*.h +lib/term/*.h +lib/malloc/*.h + +# From src/ext +tor_readpassphrase.h diff --git a/src/lib/term/getpass.c b/src/lib/term/getpass.c new file mode 100644 index 0000000000..10c99914f8 --- /dev/null +++ b/src/lib/term/getpass.c @@ -0,0 +1,115 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/term/getpass.h" + +#include "lib/log/util_bug.h" +#include "lib/malloc/util_malloc.h" + +#ifdef _WIN32 +#include <windows.h> +#include <conio.h> +#include <wchar.h> +/* Some mingw headers lack these. :p */ +#if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH +wint_t _getwch(void); +#endif +#ifndef WEOF +#define WEOF (wchar_t)(0xFFFF) +#endif +#if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY +static inline void +SecureZeroMemory(PVOID ptr, SIZE_T cnt) +{ + volatile char *vcptr = (volatile char*)ptr; + while (cnt--) + *vcptr++ = 0; +} +#endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */ +#elif defined(HAVE_READPASSPHRASE_H) +#include <readpassphrase.h> +#else +#include "tor_readpassphrase.h" +#endif /* defined(_WIN32) || ... */ + +#include <stdlib.h> +#include <string.h> + +/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b> + * bytes of passphrase into <b>output</b>. Return the number of bytes in + * the passphrase, excluding terminating NUL. + */ +ssize_t +tor_getpass(const char *prompt, char *output, size_t buflen) +{ + tor_assert(buflen <= SSIZE_MAX); + tor_assert(buflen >= 1); +#if defined(HAVE_READPASSPHRASE) + char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF); + if (pwd == NULL) + return -1; + return strlen(pwd); +#elif defined(_WIN32) + int r = -1; + while (*prompt) { + _putch(*prompt++); + } + + tor_assert(buflen <= INT_MAX); + wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t)); + + wchar_t *ptr = buf, *lastch = buf + buflen - 1; + while (ptr < lastch) { + wint_t ch = _getwch(); + switch (ch) { + case '\r': + case '\n': + case WEOF: + goto done_reading; + case 3: + goto done; /* Can't actually read ctrl-c this way. */ + case '\b': + if (ptr > buf) + --ptr; + continue; + case 0: + case 0xe0: + ch = _getwch(); /* Ignore; this is a function or arrow key */ + break; + default: + *ptr++ = ch; + break; + } + } + done_reading: + ; + +#ifndef WC_ERR_INVALID_CHARS +#define WC_ERR_INVALID_CHARS 0x80 +#endif + + /* Now convert it to UTF-8 */ + r = WideCharToMultiByte(CP_UTF8, + WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS, + buf, (int)(ptr-buf), + output, (int)(buflen-1), + NULL, NULL); + if (r <= 0) { + r = -1; + goto done; + } + + tor_assert(r < (int)buflen); + + output[r] = 0; + + done: + SecureZeroMemory(buf, sizeof(wchar_t)*buflen); + tor_free(buf); + return r; +#else +#error "No implementation for tor_getpass found!" +#endif /* defined(HAVE_READPASSPHRASE) || ... */ +} diff --git a/src/lib/term/getpass.h b/src/lib/term/getpass.h new file mode 100644 index 0000000000..9d03f7036c --- /dev/null +++ b/src/lib/term/getpass.h @@ -0,0 +1,13 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GETPASS_H +#define TOR_GETPASS_H + +#include "lib/cc/torint.h" + +ssize_t tor_getpass(const char *prompt, char *output, size_t buflen); + +#endif diff --git a/src/lib/term/include.am b/src/lib/term/include.am new file mode 100644 index 0000000000..55fe548ebc --- /dev/null +++ b/src/lib/term/include.am @@ -0,0 +1,24 @@ + +noinst_LIBRARIES += src/lib/libtor-term.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-term-testing.a +endif + +if BUILD_READPASSPHRASE_C +readpassphrase_source=src/ext/readpassphrase.c +else +readpassphrase_source= +endif + +src_lib_libtor_term_a_SOURCES = \ + src/lib/term/getpass.c \ + $(readpassphrase_source) + +src_lib_libtor_term_testing_a_SOURCES = \ + $(src_lib_libtor_term_a_SOURCES) +src_lib_libtor_term_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_term_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/term/getpass.h diff --git a/src/lib/testsupport/.may_include b/src/lib/testsupport/.may_include new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/src/lib/testsupport/.may_include diff --git a/src/lib/testsupport/include.am b/src/lib/testsupport/include.am new file mode 100644 index 0000000000..b2aa620985 --- /dev/null +++ b/src/lib/testsupport/include.am @@ -0,0 +1,3 @@ + +noinst_HEADERS += \ + src/lib/testsupport/testsupport.h diff --git a/src/common/testsupport.h b/src/lib/testsupport/testsupport.h index a3f2ff91ed..9a55d306fc 100644 --- a/src/common/testsupport.h +++ b/src/lib/testsupport/testsupport.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TESTSUPPORT_H diff --git a/src/lib/thread/.may_include b/src/lib/thread/.may_include new file mode 100644 index 0000000000..93ad0cd734 --- /dev/null +++ b/src/lib/thread/.may_include @@ -0,0 +1,6 @@ +orconfig.h +lib/cc/*.h +lib/lock/*.h +lib/log/*.h +lib/testsupport/*.h +lib/thread/*.h diff --git a/src/common/compat_pthreads.c b/src/lib/thread/compat_pthreads.c index 002274c469..246c6254bb 100644 --- a/src/common/compat_pthreads.c +++ b/src/lib/thread/compat_pthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,13 +11,16 @@ */ #include "orconfig.h" +#include "lib/thread/threads.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <sys/time.h> #include <pthread.h> #include <signal.h> #include <time.h> - -#include "compat.h" -#include "torlog.h" -#include "util.h" +#include <errno.h> +#include <string.h> /** Wraps a void (*)(void*) function and its argument so we can * invoke them in a way pthreads would expect. @@ -91,88 +94,6 @@ spawn_exit(void) pthread_exit(NULL); } -/** A mutex attribute that we're going to use to tell pthreads that we want - * "recursive" mutexes (i.e., once we can re-lock if we're already holding - * them.) */ -static pthread_mutexattr_t attr_recursive; - -/** Initialize <b>mutex</b> so it can be locked. Every mutex must be set - * up with tor_mutex_init() or tor_mutex_new(); not both. */ -void -tor_mutex_init(tor_mutex_t *mutex) -{ - if (PREDICT_UNLIKELY(!threads_initialized)) - tor_threads_init(); // LCOV_EXCL_LINE - const int err = pthread_mutex_init(&mutex->mutex, &attr_recursive); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} - -/** As tor_mutex_init, but initialize a mutex suitable that may be - * non-recursive, if the OS supports that. */ -void -tor_mutex_init_nonrecursive(tor_mutex_t *mutex) -{ - int err; - if (!threads_initialized) - tor_threads_init(); // LCOV_EXCL_LINE - err = pthread_mutex_init(&mutex->mutex, NULL); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d creating a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} - -/** Wait until <b>m</b> is free, then acquire it. */ -void -tor_mutex_acquire(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_lock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d locking a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} -/** Release the lock <b>m</b> so another thread can have it. */ -void -tor_mutex_release(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_unlock(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d unlocking a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} -/** Clean up the mutex <b>m</b> so that it no longer uses any system - * resources. Does not free <b>m</b>. This function must only be called on - * mutexes from tor_mutex_init(). */ -void -tor_mutex_uninit(tor_mutex_t *m) -{ - int err; - tor_assert(m); - err = pthread_mutex_destroy(&m->mutex); - if (PREDICT_UNLIKELY(err)) { - // LCOV_EXCL_START - log_err(LD_GENERAL, "Error %d destroying a mutex.", err); - tor_assert_unreached(); - // LCOV_EXCL_STOP - } -} /** Return an integer representing this thread. */ unsigned long tor_get_thread_id(void) @@ -333,8 +254,7 @@ void tor_threads_init(void) { if (!threads_initialized) { - pthread_mutexattr_init(&attr_recursive); - pthread_mutexattr_settype(&attr_recursive, PTHREAD_MUTEX_RECURSIVE); + tor_locking_init(); const int ret1 = pthread_attr_init(&attr_detached); tor_assert(ret1 == 0); #ifndef PTHREAD_CREATE_DETACHED @@ -347,4 +267,3 @@ tor_threads_init(void) set_main_thread(); } } - diff --git a/src/lib/thread/compat_threads.c b/src/lib/thread/compat_threads.c new file mode 100644 index 0000000000..972960e242 --- /dev/null +++ b/src/lib/thread/compat_threads.c @@ -0,0 +1,111 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_threads.c + * + * \brief Cross-platform threading and inter-thread communication logic. + * (Platform-specific parts are written in the other compat_*threads + * modules.) + */ + +#include "orconfig.h" +#include <stdlib.h> +#include "lib/thread/threads.h" + +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#include <string.h> + +/** Allocate and return a new condition variable. */ +tor_cond_t * +tor_cond_new(void) +{ + tor_cond_t *cond = tor_malloc(sizeof(tor_cond_t)); + if (BUG(tor_cond_init(cond)<0)) + tor_free(cond); // LCOV_EXCL_LINE + return cond; +} + +/** Free all storage held in <b>c</b>. */ +void +tor_cond_free_(tor_cond_t *c) +{ + if (!c) + return; + tor_cond_uninit(c); + tor_free(c); +} + +/** Identity of the "main" thread */ +static unsigned long main_thread_id = -1; + +/** Start considering the current thread to be the 'main thread'. This has + * no effect on anything besides in_main_thread(). */ +void +set_main_thread(void) +{ + main_thread_id = tor_get_thread_id(); +} +/** Return true iff called from the main thread. */ +int +in_main_thread(void) +{ + return main_thread_id == tor_get_thread_id(); +} + +#ifndef HAVE_STDATOMIC_H +/** Initialize a new atomic counter with the value 0 */ +void +atomic_counter_init(atomic_counter_t *counter) +{ + memset(counter, 0, sizeof(*counter)); + tor_mutex_init_nonrecursive(&counter->mutex); +} +/** Clean up all resources held by an atomic counter. */ +void +atomic_counter_destroy(atomic_counter_t *counter) +{ + tor_mutex_uninit(&counter->mutex); + memset(counter, 0, sizeof(*counter)); +} +/** Add a value to an atomic counter. */ +void +atomic_counter_add(atomic_counter_t *counter, size_t add) +{ + tor_mutex_acquire(&counter->mutex); + counter->val += add; + tor_mutex_release(&counter->mutex); +} +/** Subtract a value from an atomic counter. */ +void +atomic_counter_sub(atomic_counter_t *counter, size_t sub) +{ + // this relies on unsigned overflow, but that's fine. + atomic_counter_add(counter, -sub); +} +/** Return the current value of an atomic counter */ +size_t +atomic_counter_get(atomic_counter_t *counter) +{ + size_t val; + tor_mutex_acquire(&counter->mutex); + val = counter->val; + tor_mutex_release(&counter->mutex); + return val; +} +/** Replace the value of an atomic counter; return the old one. */ +size_t +atomic_counter_exchange(atomic_counter_t *counter, size_t newval) +{ + size_t oldval; + tor_mutex_acquire(&counter->mutex); + oldval = counter->val; + counter->val = newval; + tor_mutex_release(&counter->mutex); + return oldval; +} +#endif /* !defined(HAVE_STDATOMIC_H) */ diff --git a/src/common/compat_winthreads.c b/src/lib/thread/compat_winthreads.c index 7021344f6e..7f9877d21e 100644 --- a/src/common/compat_winthreads.c +++ b/src/lib/thread/compat_winthreads.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,12 +12,12 @@ #ifdef _WIN32 -#include "compat.h" #include <windows.h> #include <process.h> -#include "util.h" -#include "container.h" -#include "torlog.h" +#include "lib/thread/threads.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/log/win32err.h" /* This value is more or less total cargo-cult */ #define SPIN_COUNT 2000 @@ -55,33 +55,6 @@ spawn_exit(void) // LCOV_EXCL_STOP } -void -tor_mutex_init(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} -void -tor_mutex_init_nonrecursive(tor_mutex_t *m) -{ - InitializeCriticalSection(&m->mutex); -} - -void -tor_mutex_uninit(tor_mutex_t *m) -{ - DeleteCriticalSection(&m->mutex); -} -void -tor_mutex_acquire(tor_mutex_t *m) -{ - tor_assert(m); - EnterCriticalSection(&m->mutex); -} -void -tor_mutex_release(tor_mutex_t *m) -{ - LeaveCriticalSection(&m->mutex); -} unsigned long tor_get_thread_id(void) { @@ -248,4 +221,3 @@ tor_threads_init(void) } #endif /* defined(_WIN32) */ - diff --git a/src/lib/thread/include.am b/src/lib/thread/include.am new file mode 100644 index 0000000000..9ec23d166e --- /dev/null +++ b/src/lib/thread/include.am @@ -0,0 +1,27 @@ + +noinst_LIBRARIES += src/lib/libtor-thread.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-thread-testing.a +endif + +if THREADS_PTHREADS +threads_impl_source=src/lib/thread/compat_pthreads.c +endif +if THREADS_WIN32 +threads_impl_source=src/lib/thread/compat_winthreads.c +endif + +src_lib_libtor_thread_a_SOURCES = \ + src/lib/thread/compat_threads.c \ + src/lib/thread/numcpus.c \ + $(threads_impl_source) + +src_lib_libtor_thread_testing_a_SOURCES = \ + $(src_lib_libtor_thread_a_SOURCES) +src_lib_libtor_thread_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_thread_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/thread/threads.h \ + src/lib/thread/numcpus.h diff --git a/src/lib/thread/numcpus.c b/src/lib/thread/numcpus.c new file mode 100644 index 0000000000..534b0570f8 --- /dev/null +++ b/src/lib/thread/numcpus.c @@ -0,0 +1,93 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/thread/numcpus.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif + +#include <stdlib.h> + +/** Implementation logic for compute_num_cpus(). */ +static int +compute_num_cpus_impl(void) +{ +#ifdef _WIN32 + SYSTEM_INFO info; + memset(&info, 0, sizeof(info)); + GetSystemInfo(&info); + if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX) + return (int)info.dwNumberOfProcessors; + else + return -1; +#elif defined(HAVE_SYSCONF) +#ifdef _SC_NPROCESSORS_CONF + long cpus_conf = sysconf(_SC_NPROCESSORS_CONF); +#else + long cpus_conf = -1; +#endif +#ifdef _SC_NPROCESSORS_ONLN + long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN); +#else + long cpus_onln = -1; +#endif + long cpus = -1; + + if (cpus_conf > 0 && cpus_onln < 0) { + cpus = cpus_conf; + } else if (cpus_onln > 0 && cpus_conf < 0) { + cpus = cpus_onln; + } else if (cpus_onln > 0 && cpus_conf > 0) { + if (cpus_onln < cpus_conf) { + log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them " + "are available. Telling Tor to only use %ld. You can over" + "ride this with the NumCPUs option", + cpus_conf, cpus_onln, cpus_onln); + } + cpus = cpus_onln; + } + + if (cpus >= 1 && cpus < INT_MAX) + return (int)cpus; + else + return -1; +#else + return -1; +#endif /* defined(_WIN32) || ... */ +} + +#define MAX_DETECTABLE_CPUS 16 + +/** Return how many CPUs we are running with. We assume that nobody is + * using hot-swappable CPUs, so we don't recompute this after the first + * time. Return -1 if we don't know how to tell the number of CPUs on this + * system. + */ +int +compute_num_cpus(void) +{ + static int num_cpus = -2; + if (num_cpus == -2) { + num_cpus = compute_num_cpus_impl(); + tor_assert(num_cpus != -2); + if (num_cpus > MAX_DETECTABLE_CPUS) { + /* LCOV_EXCL_START */ + log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I " + "will not autodetect any more than %d, though. If you " + "want to configure more, set NumCPUs in your torrc", + num_cpus, MAX_DETECTABLE_CPUS); + num_cpus = MAX_DETECTABLE_CPUS; + /* LCOV_EXCL_STOP */ + } + } + return num_cpus; +} diff --git a/src/lib/thread/numcpus.h b/src/lib/thread/numcpus.h new file mode 100644 index 0000000000..2899a9ec8a --- /dev/null +++ b/src/lib/thread/numcpus.h @@ -0,0 +1,11 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_NUMCPUS_H +#define TOR_NUMCPUS_H + +int compute_num_cpus(void); + +#endif diff --git a/src/common/compat_threads.h b/src/lib/thread/threads.h index c93e601ec5..fcccc643d5 100644 --- a/src/common/compat_threads.h +++ b/src/lib/thread/threads.h @@ -1,62 +1,25 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_COMPAT_THREADS_H #define TOR_COMPAT_THREADS_H #include "orconfig.h" -#include "torint.h" -#include "testsupport.h" - -#if defined(HAVE_PTHREAD_H) && !defined(_WIN32) -#include <pthread.h> -#endif +#include "lib/cc/torint.h" +#include "lib/testsupport/testsupport.h" +#include "lib/lock/compat_mutex.h" #ifdef HAVE_STDATOMIC_H #include <stdatomic.h> #endif -#if defined(_WIN32) -#define USE_WIN32_THREADS -#elif defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_CREATE) -#define USE_PTHREADS -#else -#error "No threading system was found" -#endif /* defined(_WIN32) || ... */ +struct timeval; int spawn_func(void (*func)(void *), void *data); void spawn_exit(void) ATTR_NORETURN; -/* Because we use threads instead of processes on most platforms (Windows, - * Linux, etc), we need locking for them. On platforms with poor thread - * support or broken gethostbyname_r, these functions are no-ops. */ - -/** A generic lock structure for multithreaded builds. */ -typedef struct tor_mutex_t { -#if defined(USE_WIN32_THREADS) - /** Windows-only: on windows, we implement locks with CRITICAL_SECTIONS. */ - CRITICAL_SECTION mutex; -#elif defined(USE_PTHREADS) - /** Pthreads-only: with pthreads, we implement locks with - * pthread_mutex_t. */ - pthread_mutex_t mutex; -#else - /** No-threads only: Dummy variable so that tor_mutex_t takes up space. */ - int _unused; -#endif /* defined(USE_WIN32_THREADS) || ... */ -} tor_mutex_t; - -tor_mutex_t *tor_mutex_new(void); -tor_mutex_t *tor_mutex_new_nonrecursive(void); -void tor_mutex_init(tor_mutex_t *m); -void tor_mutex_init_nonrecursive(tor_mutex_t *m); -void tor_mutex_acquire(tor_mutex_t *m); -void tor_mutex_release(tor_mutex_t *m); -void tor_mutex_free_(tor_mutex_t *m); -#define tor_mutex_free(m) FREE_AND_NULL(tor_mutex_t, tor_mutex_free_, (m)) -void tor_mutex_uninit(tor_mutex_t *m); unsigned long tor_get_thread_id(void); void tor_threads_init(void); @@ -91,32 +54,6 @@ int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, void tor_cond_signal_one(tor_cond_t *cond); void tor_cond_signal_all(tor_cond_t *cond); -/** Helper type used to manage waking up the main thread while it's in - * the libevent main loop. Used by the work queue code. */ -typedef struct alert_sockets_s { - /* XXXX This structure needs a better name. */ - /** Socket that the main thread should listen for EV_READ events on. - * Note that this socket may be a regular fd on a non-Windows platform. - */ - tor_socket_t read_fd; - /** Socket to use when alerting the main thread. */ - tor_socket_t write_fd; - /** Function to alert the main thread */ - int (*alert_fn)(tor_socket_t write_fd); - /** Function to make the main thread no longer alerted. */ - int (*drain_fn)(tor_socket_t read_fd); -} alert_sockets_t; - -/* Flags to disable one or more alert_sockets backends. */ -#define ASOCKS_NOEVENTFD2 (1u<<0) -#define ASOCKS_NOEVENTFD (1u<<1) -#define ASOCKS_NOPIPE2 (1u<<2) -#define ASOCKS_NOPIPE (1u<<3) -#define ASOCKS_NOSOCKETPAIR (1u<<4) - -int alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags); -void alert_sockets_close(alert_sockets_t *socks); - typedef struct tor_threadlocal_s { #ifdef _WIN32 DWORD index; @@ -220,4 +157,3 @@ atomic_counter_exchange(atomic_counter_t *counter, size_t newval) #endif /* defined(HAVE_STDATOMIC_H) */ #endif /* !defined(TOR_COMPAT_THREADS_H) */ - diff --git a/src/lib/time/.may_include b/src/lib/time/.may_include new file mode 100644 index 0000000000..2c7e37a836 --- /dev/null +++ b/src/lib/time/.may_include @@ -0,0 +1,11 @@ +orconfig.h + +lib/cc/*.h +lib/err/*.h +lib/intmath/*.h +lib/log/*.h +lib/time/*.h +lib/wallclock/*.h + +# For load_windows_system_lib. +lib/fs/winlib.h
\ No newline at end of file diff --git a/src/common/compat_time.c b/src/lib/time/compat_time.c index 40847a8442..2ea6eca988 100644 --- a/src/common/compat_time.c +++ b/src/lib/time/compat_time.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,7 +10,15 @@ **/ #define COMPAT_TIME_PRIVATE -#include "compat.h" +#include "lib/time/compat_time.h" + +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/intmath/muldiv.h" +#include "lib/intmath/bits.h" +#include "lib/fs/winlib.h" +#include "lib/wallclock/timeval.h" #ifdef _WIN32 #include <winsock2.h> @@ -20,6 +28,9 @@ #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -34,15 +45,9 @@ #include <mach/mach_time.h> #endif -#include "torlog.h" -#include "util.h" -#include "container.h" - -#ifndef HAVE_GETTIMEOFDAY -#ifdef HAVE_FTIME -#include <sys/timeb.h> -#endif -#endif +#include <errno.h> +#include <stdlib.h> +#include <string.h> #ifdef _WIN32 #undef HAVE_CLOCK_GETTIME @@ -68,54 +73,6 @@ tor_sleep_msec(int msec) } #endif /* defined(TOR_UNIT_TESTS) */ -/** Set *timeval to the current time of day. On error, log and terminate. - * (Same as gettimeofday(timeval,NULL), but never returns -1.) - */ -MOCK_IMPL(void, -tor_gettimeofday, (struct timeval *timeval)) -{ -#ifdef _WIN32 - /* Epoch bias copied from perl: number of units between windows epoch and - * Unix epoch. */ -#define EPOCH_BIAS U64_LITERAL(116444736000000000) -#define UNITS_PER_SEC U64_LITERAL(10000000) -#define USEC_PER_SEC U64_LITERAL(1000000) -#define UNITS_PER_USEC U64_LITERAL(10) - union { - uint64_t ft_64; - FILETIME ft_ft; - } ft; - /* number of 100-nsec units since Jan 1, 1601 */ - GetSystemTimeAsFileTime(&ft.ft_ft); - if (ft.ft_64 < EPOCH_BIAS) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"System time is before 1970; failing."); - exit(1); // exit ok: system clock is broken. - /* LCOV_EXCL_STOP */ - } - ft.ft_64 -= EPOCH_BIAS; - timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); - timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); -#elif defined(HAVE_GETTIMEOFDAY) - if (gettimeofday(timeval, NULL)) { - /* LCOV_EXCL_START */ - log_err(LD_GENERAL,"gettimeofday failed."); - /* If gettimeofday dies, we have either given a bad timezone (we didn't), - or segfaulted.*/ - exit(1); // exit ok: gettimeofday failed. - /* LCOV_EXCL_STOP */ - } -#elif defined(HAVE_FTIME) - struct timeb tb; - ftime(&tb); - timeval->tv_sec = tb.time; - timeval->tv_usec = tb.millitm * 1000; -#else -#error "No way to get time." -#endif /* defined(_WIN32) || ... */ - return; -} - #define ONE_MILLION ((int64_t) (1000 * 1000)) #define ONE_BILLION ((int64_t) (1000 * 1000 * 1000)) @@ -900,4 +857,3 @@ monotime_msec_to_approx_coarse_stamp_units(uint64_t msec) return (msec * STAMP_TICKS_PER_SECOND) / 1000; } #endif - diff --git a/src/common/compat_time.h b/src/lib/time/compat_time.h index 57ab20ab11..4427ce8f92 100644 --- a/src/common/compat_time.h +++ b/src/lib/time/compat_time.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,6 +19,10 @@ #define TOR_COMPAT_TIME_H #include "orconfig.h" +#include "lib/cc/torint.h" + +#include "lib/wallclock/tor_gettimeofday.h" + #ifdef _WIN32 #undef HAVE_CLOCK_GETTIME #endif @@ -200,8 +204,6 @@ monotime_coarse_diff_msec32(const monotime_coarse_t *start, #endif } -MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); - #ifdef TOR_UNIT_TESTS void tor_sleep_msec(int msec); @@ -230,4 +232,3 @@ void monotime_reset_ratchets_for_testing(void); #endif /* defined(COMPAT_TIME_PRIVATE) */ #endif /* !defined(TOR_COMPAT_TIME_H) */ - diff --git a/src/lib/time/include.am b/src/lib/time/include.am new file mode 100644 index 0000000000..a3f93a3744 --- /dev/null +++ b/src/lib/time/include.am @@ -0,0 +1,19 @@ + +noinst_LIBRARIES += src/lib/libtor-time.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-time-testing.a +endif + +src_lib_libtor_time_a_SOURCES = \ + src/lib/time/compat_time.c \ + src/lib/time/tvdiff.c + +src_lib_libtor_time_testing_a_SOURCES = \ + $(src_lib_libtor_time_a_SOURCES) +src_lib_libtor_time_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_time_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/time/compat_time.h \ + src/lib/time/tvdiff.h diff --git a/src/lib/time/tvdiff.c b/src/lib/time/tvdiff.c new file mode 100644 index 0000000000..cfd1ace771 --- /dev/null +++ b/src/lib/time/tvdiff.c @@ -0,0 +1,162 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "lib/time/tvdiff.h" + +#include "lib/cc/compat_compiler.h" +#include "lib/log/torlog.h" + +#ifdef _WIN32 +#include <winsock2.h> +#endif +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#define TOR_USEC_PER_SEC 1000000 + +/** Return the difference between start->tv_sec and end->tv_sec. + * Returns INT64_MAX on overflow and underflow. + */ +static int64_t +tv_secdiff_impl(const struct timeval *start, const struct timeval *end) +{ + const int64_t s = (int64_t)start->tv_sec; + const int64_t e = (int64_t)end->tv_sec; + + /* This may not be the most efficient way of implemeting this check, + * but it's easy to see that it's correct and doesn't overflow */ + + if (s > 0 && e < INT64_MIN + s) { + /* s is positive: equivalent to e - s < INT64_MIN, but without any + * overflow */ + return INT64_MAX; + } else if (s < 0 && e > INT64_MAX + s) { + /* s is negative: equivalent to e - s > INT64_MAX, but without any + * overflow */ + return INT64_MAX; + } + + return e - s; +} + +/** Return the number of microseconds elapsed between *start and *end. + * Returns LONG_MAX on overflow and underflow. + */ +long +tv_udiff(const struct timeval *start, const struct timeval *end) +{ + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "start tv_usec: %"PRId64 " microseconds", + (int64_t)start->tv_usec); + return LONG_MAX; + } + + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on microsecond detail with bad " + "end tv_usec: %"PRId64 " microseconds", + (int64_t)end->tv_usec); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t udiff; + const int64_t secdiff = tv_secdiff_impl(start, end); + + /* end->tv_usec - start->tv_usec can be up to 1 second either way */ + if (secdiff > (int64_t)(LONG_MAX/1000000 - 1) || + secdiff < (int64_t)(LONG_MIN/1000000 + 1)) { + log_warn(LD_GENERAL, "comparing times on microsecond detail too far " + "apart: %"PRId64 " seconds", (secdiff)); + return LONG_MAX; + } + + /* we'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + udiff = secdiff*1000000 + ((int64_t)end->tv_usec - (int64_t)start->tv_usec); + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (udiff > (int64_t)LONG_MAX || udiff < (int64_t)LONG_MIN) { + return LONG_MAX; + } +#endif + + return (long)udiff; +} + +/** Return the number of milliseconds elapsed between *start and *end. + * If the tv_usec difference is 500, rounds away from zero. + * Returns LONG_MAX on overflow and underflow. + */ +long +tv_mdiff(const struct timeval *start, const struct timeval *end) +{ + /* Sanity check tv_usec */ + if (start->tv_usec > TOR_USEC_PER_SEC || start->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "start tv_usec: %"PRId64 " microseconds", + (int64_t)start->tv_usec); + return LONG_MAX; + } + + if (end->tv_usec > TOR_USEC_PER_SEC || end->tv_usec < 0) { + log_warn(LD_GENERAL, "comparing times on millisecond detail with bad " + "end tv_usec: %"PRId64 " microseconds", + (int64_t)end->tv_usec); + return LONG_MAX; + } + + /* Some BSDs have struct timeval.tv_sec 64-bit, but time_t (and long) 32-bit + */ + int64_t mdiff; + const int64_t secdiff = tv_secdiff_impl(start, end); + + /* end->tv_usec - start->tv_usec can be up to 1 second either way, but the + * mdiff calculation may add another temporary second for rounding. + * Whether this actually causes overflow depends on the compiler's constant + * folding and order of operations. */ + if (secdiff > (int64_t)(LONG_MAX/1000 - 2) || + secdiff < (int64_t)(LONG_MIN/1000 + 1)) { + log_warn(LD_GENERAL, "comparing times on millisecond detail too far " + "apart: %"PRId64 " seconds", (int64_t)secdiff); + return LONG_MAX; + } + + /* Subtract and round */ + mdiff = secdiff*1000 + + /* We add a million usec here to ensure that the result is positive, + * so that the round-towards-zero behavior of the division will give + * the right result for rounding to the nearest msec. Later we subtract + * 1000 in order to get the correct result. + * We'll never get an overflow here, because we check that both usecs are + * between 0 and TV_USEC_PER_SEC. */ + ((int64_t)end->tv_usec - (int64_t)start->tv_usec + 500 + 1000000) / 1000 + - 1000; + + /* Some compilers are smart enough to work out this is a no-op on L64 */ +#if SIZEOF_LONG < 8 + if (mdiff > (int64_t)LONG_MAX || mdiff < (int64_t)LONG_MIN) { + return LONG_MAX; + } +#endif + + return (long)mdiff; +} + +/** + * Converts timeval to milliseconds. + */ +int64_t +tv_to_msec(const struct timeval *tv) +{ + int64_t conv = ((int64_t)tv->tv_sec)*1000L; + /* Round ghetto-style */ + conv += ((int64_t)tv->tv_usec+500)/1000L; + return conv; +} diff --git a/src/lib/time/tvdiff.h b/src/lib/time/tvdiff.h new file mode 100644 index 0000000000..215de9cf37 --- /dev/null +++ b/src/lib/time/tvdiff.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TVDIFF_H +#define TOR_TVDIFF_H + +#include "lib/cc/torint.h" +struct timeval; + +long tv_udiff(const struct timeval *start, const struct timeval *end); +long tv_mdiff(const struct timeval *start, const struct timeval *end); +int64_t tv_to_msec(const struct timeval *tv); + +#endif diff --git a/src/lib/tls/.may_include b/src/lib/tls/.may_include new file mode 100644 index 0000000000..ca7cb455e4 --- /dev/null +++ b/src/lib/tls/.may_include @@ -0,0 +1,16 @@ +orconfig.h + +lib/arch/*.h +lib/cc/*.h +lib/container/*.h +lib/crypt_ops/*.h +lib/ctime/*.h +lib/encoding/*.h +lib/intmath/*.h +lib/log/*.h +lib/net/*.h +lib/string/*.h +lib/testsupport/testsupport.h +lib/tls/*.h + +ciphers.inc diff --git a/src/common/buffers_tls.c b/src/lib/tls/buffers_tls.c index 041f78b818..243e0eb0bc 100644 --- a/src/common/buffers_tls.c +++ b/src/lib/tls/buffers_tls.c @@ -1,20 +1,19 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define BUFFERS_PRIVATE #include "orconfig.h" #include <stddef.h> -#include "buffers.h" -#include "buffers_tls.h" -#include "compat.h" -#include "compress.h" -#include "util.h" -#include "torint.h" -#include "torlog.h" -#include "tortls.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" +#include "lib/cc/torint.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/tls/tortls.h" + #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -176,4 +175,3 @@ buf_flush_to_tls(buf_t *buf, tor_tls_t *tls, size_t flushlen, tor_assert(flushed < INT_MAX); return (int)flushed; } - diff --git a/src/common/buffers_tls.h b/src/lib/tls/buffers_tls.h index 2f9fda45a0..d9d26c82bd 100644 --- a/src/common/buffers_tls.h +++ b/src/lib/tls/buffers_tls.h @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_BUFFERS_TLS_H diff --git a/src/common/ciphers.inc b/src/lib/tls/ciphers.inc index 0084b3e325..0084b3e325 100644 --- a/src/common/ciphers.inc +++ b/src/lib/tls/ciphers.inc diff --git a/src/lib/tls/include.am b/src/lib/tls/include.am new file mode 100644 index 0000000000..b3b013f4dd --- /dev/null +++ b/src/lib/tls/include.am @@ -0,0 +1,20 @@ + +noinst_LIBRARIES += src/lib/libtor-tls.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-tls-testing.a +endif + +src_lib_libtor_tls_a_SOURCES = \ + src/lib/tls/buffers_tls.c \ + src/lib/tls/tortls.c + +src_lib_libtor_tls_testing_a_SOURCES = \ + $(src_lib_libtor_tls_a_SOURCES) +src_lib_libtor_tls_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_tls_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/tls/ciphers.inc \ + src/lib/tls/buffers_tls.h \ + src/lib/tls/tortls.h diff --git a/src/common/tortls.c b/src/lib/tls/tortls.c index 669742c9dd..1cd22a7eba 100644 --- a/src/common/tortls.c +++ b/src/lib/tls/tortls.c @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -19,16 +19,15 @@ #define TORTLS_PRIVATE #define TORTLS_OPENSSL_PRIVATE -#include <assert.h> #ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ #include <winsock2.h> #include <ws2tcpip.h> #endif -#include "crypto.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "compat.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_util.h" /* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ @@ -52,12 +51,22 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) #define TORTLS_PRIVATE -#include "tortls.h" -#include "util.h" -#include "torlog.h" -#include "container.h" +#include "lib/tls/tortls.h" +#include "lib/log/torlog.h" +#include "lib/log/util_bug.h" +#include "lib/container/smartlist.h" +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" +#include "lib/net/socket.h" +#include "lib/intmath/cmp.h" +#include "lib/ctime/di_ops.h" +#include "lib/encoding/time_fmt.h" + +#include <stdlib.h> #include <string.h> +#include "lib/arch/bytes.h" + #ifdef OPENSSL_1_1_API #define X509_get_notBefore_const(cert) \ X509_get0_notBefore(cert) @@ -1392,7 +1401,7 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) { unsigned char cipherid[3]; tor_assert(ssl); - set_uint16(cipherid, htons(cipher)); + set_uint16(cipherid, tor_htons(cipher)); cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting * with a two-byte 'cipherid', it may look for a v2 * cipher with the appropriate 3 bytes. */ @@ -1406,7 +1415,7 @@ find_cipher_by_id(const SSL *ssl, const SSL_METHOD *m, uint16_t cipher) # if defined(HAVE_STRUCT_SSL_METHOD_ST_GET_CIPHER_BY_CHAR) if (m && m->get_cipher_by_char) { unsigned char cipherid[3]; - set_uint16(cipherid, htons(cipher)); + set_uint16(cipherid, tor_htons(cipher)); cipherid[2] = 0; /* If ssl23_get_cipher_by_char finds no cipher starting * with a two-byte 'cipherid', it may look for a v2 * cipher with the appropriate 3 bytes. */ @@ -2433,8 +2442,8 @@ tls_get_write_overhead_ratio,(void)) if (total_bytes_written_over_tls == 0) return 1.0; - return U64_TO_DBL(total_bytes_written_by_tls) / - U64_TO_DBL(total_bytes_written_over_tls); + return ((double)total_bytes_written_by_tls) / + ((double)total_bytes_written_over_tls); } /** Implement check_no_tls_errors: If there are any pending OpenSSL @@ -2660,4 +2669,3 @@ evaluate_ecgroup_for_tls(const char *ecgroup) return ret; } - diff --git a/src/common/tortls.h b/src/lib/tls/tortls.h index 7c867bfff2..fe192b2abc 100644 --- a/src/common/tortls.h +++ b/src/lib/tls/tortls.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TORTLS_H @@ -11,10 +11,9 @@ * \brief Headers for tortls.c **/ -#include "crypto_rsa.h" -#include "compat_openssl.h" -#include "compat.h" -#include "testsupport.h" +#include "lib/crypt_ops/crypto_rsa.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/testsupport/testsupport.h" /* Opaque structure to hold a TLS connection. */ typedef struct tor_tls_t tor_tls_t; @@ -292,4 +291,3 @@ const char *tor_tls_get_ciphersuite_name(tor_tls_t *tls); int evaluate_ecgroup_for_tls(const char *ecgroup); #endif /* !defined(TOR_TORTLS_H) */ - diff --git a/src/lib/trace/.may_include b/src/lib/trace/.may_include new file mode 100644 index 0000000000..45cd13676b --- /dev/null +++ b/src/lib/trace/.may_include @@ -0,0 +1,3 @@ +orconfig.h +lib/log/*.h +lib/trace/*.h diff --git a/src/trace/debug.h b/src/lib/trace/debug.h index 3a1652543a..9b5d9d05c8 100644 --- a/src/trace/debug.h +++ b/src/lib/trace/debug.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TRACE_LOG_DEBUG_H #define TOR_TRACE_LOG_DEBUG_H -#include "torlog.h" +#include "lib/log/torlog.h" /* Stringify pre-processor trick. */ #define XSTR(d) STR(d) diff --git a/src/trace/events.h b/src/lib/trace/events.h index 1be1fd596e..6d4269aaed 100644 --- a/src/trace/events.h +++ b/src/lib/trace/events.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -31,7 +31,7 @@ /* Enable event tracing for the debug framework where all trace events are * mapped to a log_debug(). */ #ifdef USE_EVENT_TRACING_DEBUG -#include "trace/debug.h" +#include "lib/trace/debug.h" #endif #else /* TOR_EVENT_TRACING_ENABLED */ diff --git a/src/lib/trace/include.am b/src/lib/trace/include.am new file mode 100644 index 0000000000..6f10c98744 --- /dev/null +++ b/src/lib/trace/include.am @@ -0,0 +1,18 @@ + +noinst_LIBRARIES += \ + src/lib/libtor-trace.a + +TRACEHEADERS = \ + src/lib/trace/trace.h \ + src/lib/trace/events.h + +if USE_EVENT_TRACING_DEBUG +TRACEHEADERS += \ + src/lib/trace/debug.h +endif + +# Library source files. +src_lib_libtor_trace_a_SOURCES = \ + src/lib/trace/trace.c + +noinst_HEADERS+= $(TRACEHEADERS) diff --git a/src/trace/trace.c b/src/lib/trace/trace.c index fcdb80091f..c0bbbb0cc6 100644 --- a/src/trace/trace.c +++ b/src/lib/trace/trace.c @@ -1,7 +1,7 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "trace.h" +#include "lib/trace/trace.h" /** Initialize the tracing library. */ void diff --git a/src/trace/trace.h b/src/lib/trace/trace.h index 28fcd8eea8..2dd51aace1 100644 --- a/src/trace/trace.h +++ b/src/lib/trace/trace.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TRACE_TRACE_H diff --git a/src/lib/wallclock/.may_include b/src/lib/wallclock/.may_include new file mode 100644 index 0000000000..dc010da063 --- /dev/null +++ b/src/lib/wallclock/.may_include @@ -0,0 +1,6 @@ +orconfig.h +lib/cc/*.h +lib/err/*.h +lib/wallclock/*.h +lib/string/*.h +lib/testsupport/*.h diff --git a/src/lib/wallclock/approx_time.c b/src/lib/wallclock/approx_time.c new file mode 100644 index 0000000000..2528954f13 --- /dev/null +++ b/src/lib/wallclock/approx_time.c @@ -0,0 +1,38 @@ +/* Copyright (c) 2003, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/wallclock/approx_time.h" + +/* ===== + * Cached time + * ===== */ + +#ifndef TIME_IS_FAST +/** Cached estimate of the current time. Updated around once per second; + * may be a few seconds off if we are really busy. This is a hack to avoid + * calling time(NULL) (which not everybody has optimized) on critical paths. + */ +static time_t cached_approx_time = 0; + +/** Return a cached estimate of the current time from when + * update_approx_time() was last called. This is a hack to avoid calling + * time(NULL) on critical paths: please do not even think of calling it + * anywhere else. */ +time_t +approx_time(void) +{ + return cached_approx_time; +} + +/** Update the cached estimate of the current time. This function SHOULD be + * called once per second, and MUST be called before the first call to + * get_approx_time. */ +void +update_approx_time(time_t now) +{ + cached_approx_time = now; +} +#endif /* !defined(TIME_IS_FAST) */ diff --git a/src/lib/wallclock/approx_time.h b/src/lib/wallclock/approx_time.h new file mode 100644 index 0000000000..c57ff5bcd3 --- /dev/null +++ b/src/lib/wallclock/approx_time.h @@ -0,0 +1,20 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_APPROX_TIME_H +#define TOR_APPROX_TIME_H + +#include <time.h> + +/* Cached time */ +#ifdef TIME_IS_FAST +#define approx_time() time(NULL) +#define update_approx_time(t) STMT_NIL +#else +time_t approx_time(void); +void update_approx_time(time_t now); +#endif /* defined(TIME_IS_FAST) */ + +#endif diff --git a/src/lib/wallclock/include.am b/src/lib/wallclock/include.am new file mode 100644 index 0000000000..7864c21e16 --- /dev/null +++ b/src/lib/wallclock/include.am @@ -0,0 +1,22 @@ + +noinst_LIBRARIES += src/lib/libtor-wallclock.a + +if UNITTESTS_ENABLED +noinst_LIBRARIES += src/lib/libtor-wallclock-testing.a +endif + +src_lib_libtor_wallclock_a_SOURCES = \ + src/lib/wallclock/approx_time.c \ + src/lib/wallclock/tm_cvt.c \ + src/lib/wallclock/tor_gettimeofday.c + +src_lib_libtor_wallclock_testing_a_SOURCES = \ + $(src_lib_libtor_wallclock_a_SOURCES) +src_lib_libtor_wallclock_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) +src_lib_libtor_wallclock_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) + +noinst_HEADERS += \ + src/lib/wallclock/approx_time.h \ + src/lib/wallclock/timeval.h \ + src/lib/wallclock/tm_cvt.h \ + src/lib/wallclock/tor_gettimeofday.h diff --git a/src/lib/wallclock/timeval.c b/src/lib/wallclock/timeval.c new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/src/lib/wallclock/timeval.c diff --git a/src/lib/wallclock/timeval.h b/src/lib/wallclock/timeval.h new file mode 100644 index 0000000000..6a9b36a022 --- /dev/null +++ b/src/lib/wallclock/timeval.h @@ -0,0 +1,58 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_TIMEVAL_H +#define TOR_TIMEVAL_H + +#include "orconfig.h" +#include "lib/cc/torint.h" + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifndef timeradd +/** Replacement for timeradd on platforms that do not have it: sets tvout to + * the sum of tv1 and tv2. */ +#define timeradd(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec + (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv1)->tv_usec + (tv2)->tv_usec; \ + if ((tvout)->tv_usec >= 1000000) { \ + (tvout)->tv_usec -= 1000000; \ + (tvout)->tv_sec++; \ + } \ + } while (0) +#endif /* !defined(timeradd) */ + +#ifndef timersub +/** Replacement for timersub on platforms that do not have it: sets tvout to + * tv1 minus tv2. */ +#define timersub(tv1,tv2,tvout) \ + do { \ + (tvout)->tv_sec = (tv1)->tv_sec - (tv2)->tv_sec; \ + (tvout)->tv_usec = (tv1)->tv_usec - (tv2)->tv_usec; \ + if ((tvout)->tv_usec < 0) { \ + (tvout)->tv_usec += 1000000; \ + (tvout)->tv_sec--; \ + } \ + } while (0) +#endif /* !defined(timersub) */ + +#ifndef timercmp +/** Replacement for timercmp on platforms that do not have it: returns true + * iff the relational operator "op" makes the expression tv1 op tv2 true. + * + * Note that while this definition should work for all boolean operators, some + * platforms' native timercmp definitions do not support >=, <=, or ==. So + * don't use those. + */ +#define timercmp(tv1,tv2,op) \ + (((tv1)->tv_sec == (tv2)->tv_sec) ? \ + ((tv1)->tv_usec op (tv2)->tv_usec) : \ + ((tv1)->tv_sec op (tv2)->tv_sec)) +#endif /* !defined(timercmp) */ + +#endif diff --git a/src/lib/wallclock/tm_cvt.c b/src/lib/wallclock/tm_cvt.c new file mode 100644 index 0000000000..31d929e635 --- /dev/null +++ b/src/lib/wallclock/tm_cvt.c @@ -0,0 +1,195 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#include "orconfig.h" +#include "lib/cc/torint.h" +#include "lib/cc/compat_compiler.h" +#include "lib/wallclock/tm_cvt.h" +#include "lib/string/printf.h" +#include "lib/err/torerr.h" + +#include <errno.h> +#include <time.h> +#include <string.h> +#include <stdlib.h> + +#if !defined(_WIN32) +/** Defined iff we need to add locks when defining fake versions of reentrant + * versions of time-related functions. */ +#define TIME_FNS_NEED_LOCKS +#endif + +/** Helper: Deal with confused or out-of-bounds values from localtime_r and + * friends. (On some platforms, they can give out-of-bounds values or can + * return NULL.) If <b>islocal</b>, this is a localtime result; otherwise + * it's from gmtime. The function returns <b>r</b>, when given <b>timep</b> + * as its input. If we need to store new results, store them in + * <b>resultbuf</b>. */ +static struct tm * +correct_tm(int islocal, const time_t *timep, struct tm *resultbuf, + struct tm *r, char **err_out) +{ + const char *outcome; + + if (PREDICT_LIKELY(r)) { + /* We can't strftime dates after 9999 CE, and we want to avoid dates + * before 1 CE (avoiding the year 0 issue and negative years). */ + if (r->tm_year > 8099) { + r->tm_year = 8099; + r->tm_mon = 11; + r->tm_mday = 31; + r->tm_yday = 364; + r->tm_wday = 6; + r->tm_hour = 23; + r->tm_min = 59; + r->tm_sec = 59; + } else if (r->tm_year < (1-1900)) { + r->tm_year = (1-1900); + r->tm_mon = 0; + r->tm_mday = 1; + r->tm_yday = 0; + r->tm_wday = 0; + r->tm_hour = 0; + r->tm_min = 0; + r->tm_sec = 0; + } + return r; + } + + /* If we get here, gmtime or localtime returned NULL. It might have done + * this because of overrun or underrun, or it might have done it because of + * some other weird issue. */ + if (timep) { + if (*timep < 0) { + r = resultbuf; + r->tm_year = 70; /* 1970 CE */ + r->tm_mon = 0; + r->tm_mday = 1; + r->tm_yday = 0; + r->tm_wday = 0; + r->tm_hour = 0; + r->tm_min = 0 ; + r->tm_sec = 0; + outcome = "Rounding up to 1970"; + goto done; + } else if (*timep >= INT32_MAX) { + /* Rounding down to INT32_MAX isn't so great, but keep in mind that we + * only do it if gmtime/localtime tells us NULL. */ + r = resultbuf; + r->tm_year = 137; /* 2037 CE */ + r->tm_mon = 11; + r->tm_mday = 31; + r->tm_yday = 364; + r->tm_wday = 6; + r->tm_hour = 23; + r->tm_min = 59; + r->tm_sec = 59; + outcome = "Rounding down to 2037"; + goto done; + } + } + + /* If we get here, then gmtime/localtime failed without getting an extreme + * value for *timep */ + /* LCOV_EXCL_START */ + r = resultbuf; + memset(resultbuf, 0, sizeof(struct tm)); + outcome="can't recover"; + /* LCOV_EXCL_STOP */ + done: + if (err_out) { + tor_asprintf(err_out, "%s(%"PRId64") failed with error %s: %s", + islocal?"localtime":"gmtime", + timep?((int64_t)*timep):0, + strerror(errno), + outcome); + } + return r; +} + +/** @{ */ +/** As localtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in local time, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +#ifdef HAVE_LOCALTIME_R +struct tm * +tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + r = localtime_r(timep, result); + return correct_tm(1, timep, result, r, err_out); +} +#elif defined(TIME_FNS_NEED_LOCKS) +struct tm * +tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + static tor_mutex_t *m=NULL; + if (!m) { m=tor_mutex_new(); } + raw_assert(result); + tor_mutex_acquire(m); + r = localtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + tor_mutex_release(m); + return correct_tm(1, timep, result, r, err_out); +} +#else +struct tm * +tor_localtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + raw_assert(result); + r = localtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + return correct_tm(1, timep, result, r, err_out); +} +#endif /* defined(HAVE_LOCALTIME_R) || ... */ +/** @} */ + +/** @{ */ +/** As gmtime_r, but defined for platforms that don't have it: + * + * Convert *<b>timep</b> to a struct tm in UTC, and store the value in + * *<b>result</b>. Return the result on success, or NULL on failure. + */ +#ifdef HAVE_GMTIME_R +struct tm * +tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + r = gmtime_r(timep, result); + return correct_tm(0, timep, result, r, err_out); +} +#elif defined(TIME_FNS_NEED_LOCKS) +struct tm * +tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + static tor_mutex_t *m=NULL; + if (!m) { m=tor_mutex_new(); } + raw_assert(result); + tor_mutex_acquire(m); + r = gmtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + tor_mutex_release(m); + return correct_tm(0, timep, result, r, err_out); +} +#else +struct tm * +tor_gmtime_r_msg(const time_t *timep, struct tm *result, char **err_out) +{ + struct tm *r; + raw_assert(result); + r = gmtime(timep); + if (r) + memcpy(result, r, sizeof(struct tm)); + return correct_tm(0, timep, result, r, err_out); +} +#endif /* defined(HAVE_GMTIME_R) || ... */ diff --git a/src/lib/wallclock/tm_cvt.h b/src/lib/wallclock/tm_cvt.h new file mode 100644 index 0000000000..4d87acd4fa --- /dev/null +++ b/src/lib/wallclock/tm_cvt.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_WALLCLOCK_TM_CVT_H +#define TOR_WALLCLOCK_TM_CVT_H + +#include <sys/types.h> + +struct tm; +struct tm *tor_localtime_r_msg(const time_t *timep, struct tm *result, + char **err_out); +struct tm *tor_gmtime_r_msg(const time_t *timep, struct tm *result, + char **err_out); + +#endif diff --git a/src/lib/wallclock/tor_gettimeofday.c b/src/lib/wallclock/tor_gettimeofday.c new file mode 100644 index 0000000000..eb902e681d --- /dev/null +++ b/src/lib/wallclock/tor_gettimeofday.c @@ -0,0 +1,82 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/** + * \file compat_time.c + * \brief Portable wrappers for finding out the current time, running + * timers, etc. + **/ + +#include "orconfig.h" +#include "lib/err/torerr.h" +#include "lib/wallclock/tor_gettimeofday.h" +#include "lib/cc/torint.h" + +#include <stddef.h> +#include <stdlib.h> + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifndef HAVE_GETTIMEOFDAY +#ifdef HAVE_FTIME +#include <sys/timeb.h> +#endif +#endif + +/** Set *timeval to the current time of day. On error, log and terminate. + * (Same as gettimeofday(timeval,NULL), but never returns -1.) + */ +MOCK_IMPL(void, +tor_gettimeofday, (struct timeval *timeval)) +{ +#ifdef _WIN32 + /* Epoch bias copied from perl: number of units between windows epoch and + * Unix epoch. */ +#define EPOCH_BIAS UINT64_C(116444736000000000) +#define UNITS_PER_SEC UINT64_C(10000000) +#define USEC_PER_SEC UINT64_C(1000000) +#define UNITS_PER_USEC UINT64_C(10) + union { + uint64_t ft_64; + FILETIME ft_ft; + } ft; + /* number of 100-nsec units since Jan 1, 1601 */ + GetSystemTimeAsFileTime(&ft.ft_ft); + if (ft.ft_64 < EPOCH_BIAS) { + /* LCOV_EXCL_START */ + raw_assert_unreached_msg("System time is before 1970; failing."); + /* LCOV_EXCL_STOP */ + } + ft.ft_64 -= EPOCH_BIAS; + timeval->tv_sec = (unsigned) (ft.ft_64 / UNITS_PER_SEC); + timeval->tv_usec = (unsigned) ((ft.ft_64 / UNITS_PER_USEC) % USEC_PER_SEC); +#elif defined(HAVE_GETTIMEOFDAY) + if (gettimeofday(timeval, NULL)) { + /* LCOV_EXCL_START */ + /* If gettimeofday dies, we have either given a bad timezone (we didn't), + or segfaulted.*/ + raw_assert_unreached_msg("gettimeofday failed"); + /* LCOV_EXCL_STOP */ + } +#elif defined(HAVE_FTIME) + struct timeb tb; + ftime(&tb); + timeval->tv_sec = tb.time; + timeval->tv_usec = tb.millitm * 1000; +#else +#error "No way to get time." +#endif /* defined(_WIN32) || ... */ + return; +} diff --git a/src/lib/wallclock/tor_gettimeofday.h b/src/lib/wallclock/tor_gettimeofday.h new file mode 100644 index 0000000000..728ad9565d --- /dev/null +++ b/src/lib/wallclock/tor_gettimeofday.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2003-2004, Roger Dingledine + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +#ifndef TOR_GETTIMEOFDAY_H +#define TOR_GETTIMEOFDAY_H + +#include "lib/testsupport/testsupport.h" + +struct timeval; + +MOCK_DECL(void, tor_gettimeofday, (struct timeval *timeval)); + +#endif diff --git a/src/or/Makefile.nmake b/src/or/Makefile.nmake deleted file mode 100644 index 429ae67858..0000000000 --- a/src/or/Makefile.nmake +++ /dev/null @@ -1,79 +0,0 @@ -all: tor.exe - -CFLAGS = /O2 /MT /I ..\win32 /I ..\..\..\build-alpha\include /I ..\common \ - /I ..\ext - -LIBS = ..\..\..\build-alpha\lib\libevent.lib \ - ..\..\..\build-alpha\lib\libcrypto.lib \ - ..\..\..\build-alpha\lib\libssl.lib \ - ..\..\..\build-alpha\lib\libz.lib \ - ws2_32.lib advapi32.lib shell32.lib \ - crypt32.lib gdi32.lib user32.lib - -LIBTOR_OBJECTS = \ - addressmap.obj \ - buffers.obj \ - channel.obj \ - channelpadding.obj \ - channeltls.obj \ - circpathbias.obj \ - circuitbuild.obj \ - circuitlist.obj \ - circuitmux.obj \ - circuitmux_ewma.obj \ - circuitstats.obj \ - circuituse.obj \ - command.obj \ - config.obj \ - config_codedigest.obj \ - confparse.obj \ - connection.obj \ - connection_edge.obj \ - connection_or.obj \ - control.obj \ - cpuworker.obj \ - directory.obj \ - dirserv.obj \ - dirvote.obj \ - dns.obj \ - dnsserv.obj \ - ext_orport.obj \ - fp_pair.obj \ - entrynodes.obj \ - geoip.obj \ - hibernate.obj \ - main.obj \ - microdesc.obj \ - networkstatus.obj \ - nodelist.obj \ - ntmain.obj \ - onion.obj \ - onion_fast.obj \ - onion_ntor.obj \ - onion_tap.obj \ - policies.obj \ - reasons.obj \ - relay.obj \ - rendclient.obj \ - rendcommon.obj \ - rendmid.obj \ - rendservice.obj \ - rephist.obj \ - replaycache.obj \ - router.obj \ - routerlist.obj \ - routerparse.obj \ - routerset.obj \ - scheduler.obj \ - statefile.obj \ - status.obj \ - transports.obj - -libtor.lib: $(LIBTOR_OBJECTS) - lib $(LIBTOR_OBJECTS) /out:$@ - -tor.exe: libtor.lib tor_main.obj - $(CC) $(CFLAGS) $(LIBS) libtor.lib ..\common\*.lib ..\ext\*.lib tor_main.obj /Fe$@ - -clean: - del $(LIBTOR_OBJECTS) tor_main.obj *.lib tor.exe diff --git a/src/or/circuitlist.h b/src/or/circuitlist.h deleted file mode 100644 index 246f0c8815..0000000000 --- a/src/or/circuitlist.h +++ /dev/null @@ -1,98 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file circuitlist.h - * \brief Header file for circuitlist.c. - **/ - -#ifndef TOR_CIRCUITLIST_H -#define TOR_CIRCUITLIST_H - -#include "testsupport.h" -#include "hs_ident.h" - -MOCK_DECL(smartlist_t *, circuit_get_global_list, (void)); -smartlist_t *circuit_get_global_origin_circuit_list(void); -int circuit_any_opened_circuits(void); -int circuit_any_opened_circuits_cached(void); -void circuit_cache_opened_circuit_state(int circuits_are_opened); - -const char *circuit_state_to_string(int state); -const char *circuit_purpose_to_controller_string(uint8_t purpose); -const char *circuit_purpose_to_controller_hs_state_string(uint8_t purpose); -const char *circuit_purpose_to_string(uint8_t purpose); -void circuit_dump_by_conn(connection_t *conn, int severity); -void circuit_set_p_circid_chan(or_circuit_t *circ, circid_t id, - channel_t *chan); -void circuit_set_n_circid_chan(circuit_t *circ, circid_t id, - channel_t *chan); -void channel_mark_circid_unusable(channel_t *chan, circid_t id); -void channel_mark_circid_usable(channel_t *chan, circid_t id); -time_t circuit_id_when_marked_unusable_on_channel(circid_t circ_id, - channel_t *chan); -void circuit_set_state(circuit_t *circ, uint8_t state); -void circuit_close_all_marked(void); -int32_t circuit_initial_package_window(void); -origin_circuit_t *origin_circuit_new(void); -or_circuit_t *or_circuit_new(circid_t p_circ_id, channel_t *p_chan); -circuit_t *circuit_get_by_circid_channel(circid_t circ_id, - channel_t *chan); -circuit_t * -circuit_get_by_circid_channel_even_if_marked(circid_t circ_id, - channel_t *chan); -int circuit_id_in_use_on_channel(circid_t circ_id, channel_t *chan); -circuit_t *circuit_get_by_edge_conn(edge_connection_t *conn); -void circuit_unlink_all_from_channel(channel_t *chan, int reason); -origin_circuit_t *circuit_get_by_global_id(uint32_t id); -origin_circuit_t *circuit_get_ready_rend_circ_by_rend_data( - const rend_data_t *rend_data); -origin_circuit_t *circuit_get_next_by_pk_and_purpose(origin_circuit_t *start, - const uint8_t *digest, uint8_t purpose); -origin_circuit_t *circuit_get_next_service_intro_circ(origin_circuit_t *start); -origin_circuit_t *circuit_get_next_service_rp_circ(origin_circuit_t *start); -origin_circuit_t *circuit_get_next_service_hsdir_circ(origin_circuit_t *start); -origin_circuit_t *circuit_find_to_cannibalize(uint8_t purpose, - extend_info_t *info, int flags); -void circuit_mark_all_unused_circs(void); -void circuit_mark_all_dirty_circs_as_unusable(void); -MOCK_DECL(void, circuit_mark_for_close_, (circuit_t *circ, int reason, - int line, const char *file)); -int circuit_get_cpath_len(origin_circuit_t *circ); -int circuit_get_cpath_opened_len(const origin_circuit_t *); -void circuit_clear_cpath(origin_circuit_t *circ); -crypt_path_t *circuit_get_cpath_hop(origin_circuit_t *circ, int hopnum); -void circuit_get_all_pending_on_channel(smartlist_t *out, - channel_t *chan); -int circuit_count_pending_on_channel(channel_t *chan); - -#define circuit_mark_for_close(c, reason) \ - circuit_mark_for_close_((c), (reason), __LINE__, SHORT_FILE__) - -void assert_cpath_layer_ok(const crypt_path_t *cp); -MOCK_DECL(void, assert_circuit_ok,(const circuit_t *c)); -void circuit_free_all(void); -void circuits_handle_oom(size_t current_allocation); - -void circuit_clear_testing_cell_stats(circuit_t *circ); - -void channel_note_destroy_pending(channel_t *chan, circid_t id); -MOCK_DECL(void, channel_note_destroy_not_pending, - (channel_t *chan, circid_t id)); - -smartlist_t *circuit_find_circuits_to_upgrade_from_guard_wait(void); - -#ifdef CIRCUITLIST_PRIVATE -STATIC void circuit_free_(circuit_t *circ); -#define circuit_free(circ) FREE_AND_NULL(circuit_t, circuit_free_, (circ)) -STATIC size_t n_cells_in_circ_queues(const circuit_t *c); -STATIC uint32_t circuit_max_queued_data_age(const circuit_t *c, uint32_t now); -STATIC uint32_t circuit_max_queued_cell_age(const circuit_t *c, uint32_t now); -STATIC uint32_t circuit_max_queued_item_age(const circuit_t *c, uint32_t now); -#endif /* defined(CIRCUITLIST_PRIVATE) */ - -#endif /* !defined(TOR_CIRCUITLIST_H) */ - diff --git a/src/or/hs_ntor.h b/src/or/hs_ntor.h deleted file mode 100644 index 77e544a130..0000000000 --- a/src/or/hs_ntor.h +++ /dev/null @@ -1,67 +0,0 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -#ifndef TOR_HS_NTOR_H -#define TOR_HS_NTOR_H - -#include "or.h" - -/* Output length of KDF for key expansion */ -#define HS_NTOR_KEY_EXPANSION_KDF_OUT_LEN \ - (DIGEST256_LEN*2 + CIPHER256_KEY_LEN*2) - -/* Key material needed to encode/decode INTRODUCE1 cells */ -typedef struct { - /* Key used for encryption of encrypted INTRODUCE1 blob */ - uint8_t enc_key[CIPHER256_KEY_LEN]; - /* MAC key used to protect encrypted INTRODUCE1 blob */ - uint8_t mac_key[DIGEST256_LEN]; -} hs_ntor_intro_cell_keys_t; - -/* Key material needed to encode/decode RENDEZVOUS1 cells */ -typedef struct { - /* This is the MAC of the HANDSHAKE_INFO field */ - uint8_t rend_cell_auth_mac[DIGEST256_LEN]; - /* This is the key seed used to derive further rendezvous crypto keys as - * detailed in section 4.2.1 of rend-spec-ng.txt. */ - uint8_t ntor_key_seed[DIGEST256_LEN]; -} hs_ntor_rend_cell_keys_t; - -int hs_ntor_client_get_introduce1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_public_key_t *intro_enc_pubkey, - const curve25519_keypair_t *client_ephemeral_enc_keypair, - const uint8_t *subcredential, - hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out); - -int hs_ntor_client_get_rendezvous1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_keypair_t *client_ephemeral_enc_keypair, - const curve25519_public_key_t *intro_enc_pubkey, - const curve25519_public_key_t *service_ephemeral_rend_pubkey, - hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out); - -int hs_ntor_service_get_introduce1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_keypair_t *intro_enc_keypair, - const curve25519_public_key_t *client_ephemeral_enc_pubkey, - const uint8_t *subcredential, - hs_ntor_intro_cell_keys_t *hs_ntor_intro_cell_keys_out); - -int hs_ntor_service_get_rendezvous1_keys( - const ed25519_public_key_t *intro_auth_pubkey, - const curve25519_keypair_t *intro_enc_keypair, - const curve25519_keypair_t *service_ephemeral_rend_keypair, - const curve25519_public_key_t *client_ephemeral_enc_pubkey, - hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys_out); - -int hs_ntor_circuit_key_expansion(const uint8_t *ntor_key_seed, - size_t seed_len, - uint8_t *keys_out, size_t keys_out_len); - -int hs_ntor_client_rendezvous2_mac_is_good( - const hs_ntor_rend_cell_keys_t *hs_ntor_rend_cell_keys, - const uint8_t *rcvd_mac); - -#endif /* !defined(TOR_HS_NTOR_H) */ - diff --git a/src/or/include.am b/src/or/include.am deleted file mode 100644 index 59d593a5e9..0000000000 --- a/src/or/include.am +++ /dev/null @@ -1,320 +0,0 @@ -bin_PROGRAMS+= src/or/tor -noinst_LIBRARIES += \ - src/or/libtor.a -if UNITTESTS_ENABLED -noinst_LIBRARIES += \ - src/or/libtor-testing.a -endif -if COVERAGE_ENABLED -noinst_PROGRAMS+= src/or/tor-cov -endif - -if BUILD_NT_SERVICES -tor_platform_source=src/or/ntmain.c -else -tor_platform_source= -endif - -EXTRA_DIST+= src/or/ntmain.c src/or/Makefile.nmake - -LIBTOR_A_SOURCES = \ - src/or/addressmap.c \ - src/or/bridges.c \ - src/or/channel.c \ - src/or/channelpadding.c \ - src/or/channeltls.c \ - src/or/circpathbias.c \ - src/or/circuitbuild.c \ - src/or/circuitlist.c \ - src/or/circuitmux.c \ - src/or/circuitmux_ewma.c \ - src/or/circuitstats.c \ - src/or/circuituse.c \ - src/or/command.c \ - src/or/config.c \ - src/or/confparse.c \ - src/or/connection.c \ - src/or/connection_edge.c \ - src/or/connection_or.c \ - src/or/conscache.c \ - src/or/consdiff.c \ - src/or/consdiffmgr.c \ - src/or/control.c \ - src/or/cpuworker.c \ - src/or/directory.c \ - src/or/dirserv.c \ - src/or/dns.c \ - src/or/dnsserv.c \ - src/or/dos.c \ - src/or/fp_pair.c \ - src/or/geoip.c \ - src/or/entrynodes.c \ - src/or/ext_orport.c \ - src/or/git_revision.c \ - src/or/hibernate.c \ - src/or/hs_cache.c \ - src/or/hs_cell.c \ - src/or/hs_circuit.c \ - src/or/hs_circuitmap.c \ - src/or/hs_client.c \ - src/or/hs_common.c \ - src/or/hs_config.c \ - src/or/hs_control.c \ - src/or/hs_descriptor.c \ - src/or/hs_ident.c \ - src/or/hs_intropoint.c \ - src/or/hs_ntor.c \ - src/or/hs_service.c \ - src/or/hs_stats.c \ - src/or/keypin.c \ - src/or/main.c \ - src/or/microdesc.c \ - src/or/networkstatus.c \ - src/or/nodelist.c \ - src/or/onion.c \ - src/or/onion_fast.c \ - src/or/onion_tap.c \ - src/or/transports.c \ - src/or/parsecommon.c \ - src/or/periodic.c \ - src/or/protover.c \ - src/or/protover_rust.c \ - src/or/proto_cell.c \ - src/or/proto_control0.c \ - src/or/proto_ext_or.c \ - src/or/proto_http.c \ - src/or/proto_socks.c \ - src/or/policies.c \ - src/or/reasons.c \ - src/or/relay.c \ - src/or/relay_crypto.c \ - src/or/rendcache.c \ - src/or/rendclient.c \ - src/or/rendcommon.c \ - src/or/rendmid.c \ - src/or/rendservice.c \ - src/or/rephist.c \ - src/or/replaycache.c \ - src/or/router.c \ - src/or/routerkeys.c \ - src/or/routerlist.c \ - src/or/routerparse.c \ - src/or/routerset.c \ - src/or/scheduler.c \ - src/or/scheduler_kist.c \ - src/or/scheduler_vanilla.c \ - src/or/shared_random_client.c \ - src/or/statefile.c \ - src/or/status.c \ - src/or/torcert.c \ - src/or/tor_api.c \ - src/or/voting_schedule.c \ - src/or/onion_ntor.c \ - $(tor_platform_source) - -# -# Modules are conditionnally compiled in tor starting here. We add the C files -# only if the modules has been enabled at configure time. We always add the -# source files of every module to libtor-testing.a so we can build the unit -# tests for everything. See the UNITTESTS_ENABLED branch below. -# -LIBTOR_TESTING_A_SOURCES = $(LIBTOR_A_SOURCES) - -# The Directory Authority module. -MODULE_DIRAUTH_SOURCES = \ - src/or/dirauth/dircollate.c \ - src/or/dirauth/dirvote.c \ - src/or/dirauth/shared_random.c \ - src/or/dirauth/shared_random_state.c -if BUILD_MODULE_DIRAUTH -LIBTOR_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) -endif - -src_or_libtor_a_SOURCES = $(LIBTOR_A_SOURCES) -if UNITTESTS_ENABLED - -# Add the sources of the modules that are needed for tests to work here. -LIBTOR_TESTING_A_SOURCES += $(MODULE_DIRAUTH_SOURCES) - -src_or_libtor_testing_a_SOURCES = $(LIBTOR_TESTING_A_SOURCES) -else -src_or_libtor_testing_a_SOURCES = -endif - -src_or_tor_SOURCES = src/or/tor_main.c -AM_CPPFLAGS += -I$(srcdir)/src/or -Isrc/or - -src/or/tor_main.$(OBJEXT) \ - src/or/src_or_tor_cov-tor_main.$(OBJEXT): micro-revision.i - -AM_CPPFLAGS += -DSHARE_DATADIR="\"$(datadir)\"" \ - -DLOCALSTATEDIR="\"$(localstatedir)\"" \ - -DBINDIR="\"$(bindir)\"" - -src_or_libtor_testing_a_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_or_libtor_testing_a_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) - -# -L flags need to go in LDFLAGS. -l flags need to go in LDADD. -# This seems to matter nowhere but on windows, but I assure you that it -# matters a lot there, and is quite hard to debug if you forget to do it. - - -src_or_tor_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ -src_or_tor_LDADD = src/or/libtor.a src/common/libor.a src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event.a src/trunnel/libor-trunnel.a \ - src/trace/libor-trace.a \ - $(rust_ldadd) \ - @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ - @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ - @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ - -if COVERAGE_ENABLED -src_or_tor_cov_SOURCES = src/or/tor_main.c -src_or_tor_cov_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) -src_or_tor_cov_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_or_tor_cov_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ -src_or_tor_cov_LDADD = src/or/libtor-testing.a src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event-testing.a src/trunnel/libor-trunnel-testing.a \ - @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ @TOR_SYSTEMD_LIBS@ \ - @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ -endif - -ORHEADERS = \ - src/or/addressmap.h \ - src/or/auth_dirs.inc \ - src/or/bridges.h \ - src/or/channel.h \ - src/or/channelpadding.h \ - src/or/channeltls.h \ - src/or/circpathbias.h \ - src/or/circuitbuild.h \ - src/or/circuitlist.h \ - src/or/circuitmux.h \ - src/or/circuitmux_ewma.h \ - src/or/circuitstats.h \ - src/or/circuituse.h \ - src/or/command.h \ - src/or/config.h \ - src/or/confparse.h \ - src/or/connection.h \ - src/or/connection_edge.h \ - src/or/connection_or.h \ - src/or/conscache.h \ - src/or/consdiff.h \ - src/or/consdiffmgr.h \ - src/or/control.h \ - src/or/cpuworker.h \ - src/or/directory.h \ - src/or/dirserv.h \ - src/or/dns.h \ - src/or/dns_structs.h \ - src/or/dnsserv.h \ - src/or/dos.h \ - src/or/ext_orport.h \ - src/or/fallback_dirs.inc \ - src/or/fp_pair.h \ - src/or/geoip.h \ - src/or/entrynodes.h \ - src/or/git_revision.h \ - src/or/hibernate.h \ - src/or/hs_cache.h \ - src/or/hs_cell.h \ - src/or/hs_circuit.h \ - src/or/hs_circuitmap.h \ - src/or/hs_client.h \ - src/or/hs_common.h \ - src/or/hs_config.h \ - src/or/hs_control.h \ - src/or/hs_descriptor.h \ - src/or/hs_ident.h \ - src/or/hs_intropoint.h \ - src/or/hs_ntor.h \ - src/or/hs_stats.h \ - src/or/hs_service.h \ - src/or/keypin.h \ - src/or/main.h \ - src/or/microdesc.h \ - src/or/networkstatus.h \ - src/or/nodelist.h \ - src/or/ntmain.h \ - src/or/onion.h \ - src/or/onion_fast.h \ - src/or/onion_ntor.h \ - src/or/onion_tap.h \ - src/or/or.h \ - src/or/transports.h \ - src/or/parsecommon.h \ - src/or/periodic.h \ - src/or/policies.h \ - src/or/protover.h \ - src/or/proto_cell.h \ - src/or/proto_control0.h \ - src/or/proto_ext_or.h \ - src/or/proto_http.h \ - src/or/proto_socks.h \ - src/or/reasons.h \ - src/or/relay.h \ - src/or/relay_crypto.h \ - src/or/rendcache.h \ - src/or/rendclient.h \ - src/or/rendcommon.h \ - src/or/rendmid.h \ - src/or/rendservice.h \ - src/or/rephist.h \ - src/or/replaycache.h \ - src/or/router.h \ - src/or/routerkeys.h \ - src/or/routerlist.h \ - src/or/routerkeys.h \ - src/or/routerset.h \ - src/or/routerparse.h \ - src/or/scheduler.h \ - src/or/shared_random_client.h \ - src/or/statefile.h \ - src/or/status.h \ - src/or/torcert.h \ - src/or/tor_api_internal.h \ - src/or/voting_schedule.h - -# We add the headers of the modules even though they are disabled so we can -# properly compiled the entry points stub. - -# The Directory Authority module headers. -ORHEADERS += \ - src/or/dirauth/dircollate.h \ - src/or/dirauth/dirvote.h \ - src/or/dirauth/mode.h \ - src/or/dirauth/shared_random.h \ - src/or/dirauth/shared_random_state.h - -# This may someday want to be an installed file? -noinst_HEADERS += src/or/tor_api.h - -noinst_HEADERS += $(ORHEADERS) micro-revision.i - -micro-revision.i: FORCE - $(AM_V_at)rm -f micro-revision.tmp; \ - if test -r "$(top_srcdir)/.git" && \ - test -x "`which git 2>&1;true`"; then \ - HASH="`cd "$(top_srcdir)" && git rev-parse --short=16 HEAD`"; \ - echo \"$$HASH\" > micro-revision.tmp; \ - fi; \ - if test ! -f micro-revision.tmp; then \ - if test ! -f micro-revision.i; then \ - echo '""' > micro-revision.i; \ - fi; \ - elif test ! -f micro-revision.i || \ - test x"`cat micro-revision.tmp`" != x"`cat micro-revision.i`"; then \ - mv micro-revision.tmp micro-revision.i; \ - fi; \ - rm -f micro-revision.tmp; \ - true - -CLEANFILES+= micro-revision.i src/or/micro-revision.i micro-revision.tmp - -FORCE: diff --git a/src/or/or.h b/src/or/or.h deleted file mode 100644 index db8f9544fe..0000000000 --- a/src/or/or.h +++ /dev/null @@ -1,5534 +0,0 @@ -/* Copyright (c) 2001 Matej Pfajfar. - * Copyright (c) 2001-2004, Roger Dingledine. - * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file or.h - * \brief Master header file for Tor-specific functionality. - **/ - -#ifndef TOR_OR_H -#define TOR_OR_H - -#include "orconfig.h" - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif -#ifdef HAVE_SYS_PARAM_H -#include <sys/param.h> /* FreeBSD needs this to know what version it is */ -#endif -#include "torint.h" -#ifdef HAVE_SYS_FCNTL_H -#include <sys/fcntl.h> -#endif -#ifdef HAVE_FCNTL_H -#include <fcntl.h> -#endif -#ifdef HAVE_SYS_IOCTL_H -#include <sys/ioctl.h> -#endif -#ifdef HAVE_SYS_UN_H -#include <sys/un.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_NETINET_IN_H -#include <netinet/in.h> -#endif -#ifdef HAVE_ARPA_INET_H -#include <arpa/inet.h> -#endif -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif -#ifdef HAVE_ASSERT_H -#include <assert.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -#ifdef _WIN32 -#include <winsock2.h> -#include <io.h> -#include <process.h> -#include <direct.h> -#include <windows.h> -#endif /* defined(_WIN32) */ - -#include "crypto.h" -#include "crypto_format.h" -#include "tortls.h" -#include "torlog.h" -#include "container.h" -#include "compress.h" -#include "address.h" -#include "compat_libevent.h" -#include "ht.h" -#include "confline.h" -#include "replaycache.h" -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" -#include "tor_queue.h" -#include "token_bucket.h" -#include "util_format.h" -#include "hs_circuitmap.h" - -/* These signals are defined to help handle_control_signal work. - */ -#ifndef SIGHUP -#define SIGHUP 1 -#endif -#ifndef SIGINT -#define SIGINT 2 -#endif -#ifndef SIGUSR1 -#define SIGUSR1 10 -#endif -#ifndef SIGUSR2 -#define SIGUSR2 12 -#endif -#ifndef SIGTERM -#define SIGTERM 15 -#endif -/* Controller signals start at a high number so we don't - * conflict with system-defined signals. */ -#define SIGNEWNYM 129 -#define SIGCLEARDNSCACHE 130 -#define SIGHEARTBEAT 131 - -#if (SIZEOF_CELL_T != 0) -/* On Irix, stdlib.h defines a cell_t type, so we need to make sure - * that our stuff always calls cell_t something different. */ -#define cell_t tor_cell_t -#endif - -#ifdef ENABLE_TOR2WEB_MODE -#define NON_ANONYMOUS_MODE_ENABLED 1 -#endif - -/** Helper macro: Given a pointer to to.base_, of type from*, return &to. */ -#define DOWNCAST(to, ptr) ((to*)SUBTYPE_P(ptr, to, base_)) - -/** Length of longest allowable configured nickname. */ -#define MAX_NICKNAME_LEN 19 -/** Length of a router identity encoded as a hexadecimal digest, plus - * possible dollar sign. */ -#define MAX_HEX_NICKNAME_LEN (HEX_DIGEST_LEN+1) -/** Maximum length of verbose router identifier: dollar sign, hex ID digest, - * equal sign or tilde, nickname. */ -#define MAX_VERBOSE_NICKNAME_LEN (1+HEX_DIGEST_LEN+1+MAX_NICKNAME_LEN) - -/** Maximum size, in bytes, for resized buffers. */ -#define MAX_BUF_SIZE ((1<<24)-1) /* 16MB-1 */ -/** Maximum size, in bytes, for any directory object that we've downloaded. */ -#define MAX_DIR_DL_SIZE MAX_BUF_SIZE - -/** For HTTP parsing: Maximum number of bytes we'll accept in the headers - * of an HTTP request or response. */ -#define MAX_HEADERS_SIZE 50000 -/** Maximum size, in bytes, for any directory object that we're accepting - * as an upload. */ -#define MAX_DIR_UL_SIZE MAX_BUF_SIZE - -/** Maximum size, in bytes, of a single router descriptor uploaded to us - * as a directory authority. Caches and clients fetch whatever descriptors - * the authorities tell them to fetch, and don't care about size. */ -#define MAX_DESCRIPTOR_UPLOAD_SIZE 20000 - -/** Maximum size of a single extrainfo document, as above. */ -#define MAX_EXTRAINFO_UPLOAD_SIZE 50000 - -/** Minimum lifetime for an onion key in days. */ -#define MIN_ONION_KEY_LIFETIME_DAYS (1) - -/** Maximum lifetime for an onion key in days. */ -#define MAX_ONION_KEY_LIFETIME_DAYS (90) - -/** Default lifetime for an onion key in days. */ -#define DEFAULT_ONION_KEY_LIFETIME_DAYS (28) - -/** Minimum grace period for acceptance of an onion key in days. - * The maximum value is defined in proposal #274 as being the current network - * consensus parameter for "onion-key-rotation-days". */ -#define MIN_ONION_KEY_GRACE_PERIOD_DAYS (1) - -/** Default grace period for acceptance of an onion key in days. */ -#define DEFAULT_ONION_KEY_GRACE_PERIOD_DAYS (7) - -/** How often we should check the network consensus if it is time to rotate or - * expire onion keys. */ -#define ONION_KEY_CONSENSUS_CHECK_INTERVAL (60*60) - -/** How often do we rotate TLS contexts? */ -#define MAX_SSL_KEY_LIFETIME_INTERNAL (2*60*60) - -/** How old do we allow a router to get before removing it - * from the router list? In seconds. */ -#define ROUTER_MAX_AGE (60*60*48) -/** How old can a router get before we (as a server) will no longer - * consider it live? In seconds. */ -#define ROUTER_MAX_AGE_TO_PUBLISH (60*60*24) -/** How old do we let a saved descriptor get before force-removing it? */ -#define OLD_ROUTER_DESC_MAX_AGE (60*60*24*5) - -/** Possible rules for generating circuit IDs on an OR connection. */ -typedef enum { - CIRC_ID_TYPE_LOWER=0, /**< Pick from 0..1<<15-1. */ - CIRC_ID_TYPE_HIGHER=1, /**< Pick from 1<<15..1<<16-1. */ - /** The other side of a connection is an OP: never create circuits to it, - * and let it use any circuit ID it wants. */ - CIRC_ID_TYPE_NEITHER=2 -} circ_id_type_t; -#define circ_id_type_bitfield_t ENUM_BF(circ_id_type_t) - -#define CONN_TYPE_MIN_ 3 -/** Type for sockets listening for OR connections. */ -#define CONN_TYPE_OR_LISTENER 3 -/** A bidirectional TLS connection transmitting a sequence of cells. - * May be from an OR to an OR, or from an OP to an OR. */ -#define CONN_TYPE_OR 4 -/** A TCP connection from an onion router to a stream's destination. */ -#define CONN_TYPE_EXIT 5 -/** Type for sockets listening for SOCKS connections. */ -#define CONN_TYPE_AP_LISTENER 6 -/** A SOCKS proxy connection from the user application to the onion - * proxy. */ -#define CONN_TYPE_AP 7 -/** Type for sockets listening for HTTP connections to the directory server. */ -#define CONN_TYPE_DIR_LISTENER 8 -/** Type for HTTP connections to the directory server. */ -#define CONN_TYPE_DIR 9 -/* Type 10 is unused. */ -/** Type for listening for connections from user interface process. */ -#define CONN_TYPE_CONTROL_LISTENER 11 -/** Type for connections from user interface process. */ -#define CONN_TYPE_CONTROL 12 -/** Type for sockets listening for transparent connections redirected by pf or - * netfilter. */ -#define CONN_TYPE_AP_TRANS_LISTENER 13 -/** Type for sockets listening for transparent connections redirected by - * natd. */ -#define CONN_TYPE_AP_NATD_LISTENER 14 -/** Type for sockets listening for DNS requests. */ -#define CONN_TYPE_AP_DNS_LISTENER 15 - -/** Type for connections from the Extended ORPort. */ -#define CONN_TYPE_EXT_OR 16 -/** Type for sockets listening for Extended ORPort connections. */ -#define CONN_TYPE_EXT_OR_LISTENER 17 -/** Type for sockets listening for HTTP CONNECT tunnel connections. */ -#define CONN_TYPE_AP_HTTP_CONNECT_LISTENER 18 - -#define CONN_TYPE_MAX_ 19 -/* !!!! If _CONN_TYPE_MAX is ever over 31, we must grow the type field in - * connection_t. */ - -/* Proxy client types */ -#define PROXY_NONE 0 -#define PROXY_CONNECT 1 -#define PROXY_SOCKS4 2 -#define PROXY_SOCKS5 3 -/* !!!! If there is ever a PROXY_* type over 3, we must grow the proxy_type - * field in or_connection_t */ - -/* Pluggable transport proxy type. Don't use this in or_connection_t, - * instead use the actual underlying proxy type (see above). */ -#define PROXY_PLUGGABLE 4 - -/* Proxy client handshake states */ -/* We use a proxy but we haven't even connected to it yet. */ -#define PROXY_INFANT 1 -/* We use an HTTP proxy and we've sent the CONNECT command. */ -#define PROXY_HTTPS_WANT_CONNECT_OK 2 -/* We use a SOCKS4 proxy and we've sent the CONNECT command. */ -#define PROXY_SOCKS4_WANT_CONNECT_OK 3 -/* We use a SOCKS5 proxy and we try to negotiate without - any authentication . */ -#define PROXY_SOCKS5_WANT_AUTH_METHOD_NONE 4 -/* We use a SOCKS5 proxy and we try to negotiate with - Username/Password authentication . */ -#define PROXY_SOCKS5_WANT_AUTH_METHOD_RFC1929 5 -/* We use a SOCKS5 proxy and we just sent our credentials. */ -#define PROXY_SOCKS5_WANT_AUTH_RFC1929_OK 6 -/* We use a SOCKS5 proxy and we just sent our CONNECT command. */ -#define PROXY_SOCKS5_WANT_CONNECT_OK 7 -/* We use a proxy and we CONNECTed successfully!. */ -#define PROXY_CONNECTED 8 - -/** True iff <b>x</b> is an edge connection. */ -#define CONN_IS_EDGE(x) \ - ((x)->type == CONN_TYPE_EXIT || (x)->type == CONN_TYPE_AP) - -/** State for any listener connection. */ -#define LISTENER_STATE_READY 0 - -#define OR_CONN_STATE_MIN_ 1 -/** State for a connection to an OR: waiting for connect() to finish. */ -#define OR_CONN_STATE_CONNECTING 1 -/** State for a connection to an OR: waiting for proxy handshake to complete */ -#define OR_CONN_STATE_PROXY_HANDSHAKING 2 -/** State for an OR connection client: SSL is handshaking, not done - * yet. */ -#define OR_CONN_STATE_TLS_HANDSHAKING 3 -/** State for a connection to an OR: We're doing a second SSL handshake for - * renegotiation purposes. (V2 handshake only.) */ -#define OR_CONN_STATE_TLS_CLIENT_RENEGOTIATING 4 -/** State for a connection at an OR: We're waiting for the client to - * renegotiate (to indicate a v2 handshake) or send a versions cell (to - * indicate a v3 handshake) */ -#define OR_CONN_STATE_TLS_SERVER_RENEGOTIATING 5 -/** State for an OR connection: We're done with our SSL handshake, we've done - * renegotiation, but we haven't yet negotiated link protocol versions and - * sent a netinfo cell. */ -#define OR_CONN_STATE_OR_HANDSHAKING_V2 6 -/** State for an OR connection: We're done with our SSL handshake, but we - * haven't yet negotiated link protocol versions, done a V3 handshake, and - * sent a netinfo cell. */ -#define OR_CONN_STATE_OR_HANDSHAKING_V3 7 -/** State for an OR connection: Ready to send/receive cells. */ -#define OR_CONN_STATE_OPEN 8 -#define OR_CONN_STATE_MAX_ 8 - -/** States of the Extended ORPort protocol. Be careful before changing - * the numbers: they matter. */ -#define EXT_OR_CONN_STATE_MIN_ 1 -/** Extended ORPort authentication is waiting for the authentication - * type selected by the client. */ -#define EXT_OR_CONN_STATE_AUTH_WAIT_AUTH_TYPE 1 -/** Extended ORPort authentication is waiting for the client nonce. */ -#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_NONCE 2 -/** Extended ORPort authentication is waiting for the client hash. */ -#define EXT_OR_CONN_STATE_AUTH_WAIT_CLIENT_HASH 3 -#define EXT_OR_CONN_STATE_AUTH_MAX 3 -/** Authentication finished and the Extended ORPort is now accepting - * traffic. */ -#define EXT_OR_CONN_STATE_OPEN 4 -/** Extended ORPort is flushing its last messages and preparing to - * start accepting OR connections. */ -#define EXT_OR_CONN_STATE_FLUSHING 5 -#define EXT_OR_CONN_STATE_MAX_ 5 - -#define EXIT_CONN_STATE_MIN_ 1 -/** State for an exit connection: waiting for response from DNS farm. */ -#define EXIT_CONN_STATE_RESOLVING 1 -/** State for an exit connection: waiting for connect() to finish. */ -#define EXIT_CONN_STATE_CONNECTING 2 -/** State for an exit connection: open and ready to transmit data. */ -#define EXIT_CONN_STATE_OPEN 3 -/** State for an exit connection: waiting to be removed. */ -#define EXIT_CONN_STATE_RESOLVEFAILED 4 -#define EXIT_CONN_STATE_MAX_ 4 - -/* The AP state values must be disjoint from the EXIT state values. */ -#define AP_CONN_STATE_MIN_ 5 -/** State for a SOCKS connection: waiting for SOCKS request. */ -#define AP_CONN_STATE_SOCKS_WAIT 5 -/** State for a SOCKS connection: got a y.onion URL; waiting to receive - * rendezvous descriptor. */ -#define AP_CONN_STATE_RENDDESC_WAIT 6 -/** The controller will attach this connection to a circuit; it isn't our - * job to do so. */ -#define AP_CONN_STATE_CONTROLLER_WAIT 7 -/** State for a SOCKS connection: waiting for a completed circuit. */ -#define AP_CONN_STATE_CIRCUIT_WAIT 8 -/** State for a SOCKS connection: sent BEGIN, waiting for CONNECTED. */ -#define AP_CONN_STATE_CONNECT_WAIT 9 -/** State for a SOCKS connection: sent RESOLVE, waiting for RESOLVED. */ -#define AP_CONN_STATE_RESOLVE_WAIT 10 -/** State for a SOCKS connection: ready to send and receive. */ -#define AP_CONN_STATE_OPEN 11 -/** State for a transparent natd connection: waiting for original - * destination. */ -#define AP_CONN_STATE_NATD_WAIT 12 -/** State for an HTTP tunnel: waiting for an HTTP CONNECT command. */ -#define AP_CONN_STATE_HTTP_CONNECT_WAIT 13 -#define AP_CONN_STATE_MAX_ 13 - -/** True iff the AP_CONN_STATE_* value <b>s</b> means that the corresponding - * edge connection is not attached to any circuit. */ -#define AP_CONN_STATE_IS_UNATTACHED(s) \ - ((s) <= AP_CONN_STATE_CIRCUIT_WAIT || (s) == AP_CONN_STATE_NATD_WAIT) - -#define DIR_CONN_STATE_MIN_ 1 -/** State for connection to directory server: waiting for connect(). */ -#define DIR_CONN_STATE_CONNECTING 1 -/** State for connection to directory server: sending HTTP request. */ -#define DIR_CONN_STATE_CLIENT_SENDING 2 -/** State for connection to directory server: reading HTTP response. */ -#define DIR_CONN_STATE_CLIENT_READING 3 -/** State for connection to directory server: happy and finished. */ -#define DIR_CONN_STATE_CLIENT_FINISHED 4 -/** State for connection at directory server: waiting for HTTP request. */ -#define DIR_CONN_STATE_SERVER_COMMAND_WAIT 5 -/** State for connection at directory server: sending HTTP response. */ -#define DIR_CONN_STATE_SERVER_WRITING 6 -#define DIR_CONN_STATE_MAX_ 6 - -/** True iff the purpose of <b>conn</b> means that it's a server-side - * directory connection. */ -#define DIR_CONN_IS_SERVER(conn) ((conn)->purpose == DIR_PURPOSE_SERVER) - -#define CONTROL_CONN_STATE_MIN_ 1 -/** State for a control connection: Authenticated and accepting v1 commands. */ -#define CONTROL_CONN_STATE_OPEN 1 -/** State for a control connection: Waiting for authentication; speaking - * protocol v1. */ -#define CONTROL_CONN_STATE_NEEDAUTH 2 -#define CONTROL_CONN_STATE_MAX_ 2 - -#define DIR_PURPOSE_MIN_ 4 -/** A connection to a directory server: set after a v2 rendezvous - * descriptor is downloaded. */ -#define DIR_PURPOSE_HAS_FETCHED_RENDDESC_V2 4 -/** A connection to a directory server: download one or more server - * descriptors. */ -#define DIR_PURPOSE_FETCH_SERVERDESC 6 -/** A connection to a directory server: download one or more extra-info - * documents. */ -#define DIR_PURPOSE_FETCH_EXTRAINFO 7 -/** A connection to a directory server: upload a server descriptor. */ -#define DIR_PURPOSE_UPLOAD_DIR 8 -/** A connection to a directory server: upload a v3 networkstatus vote. */ -#define DIR_PURPOSE_UPLOAD_VOTE 10 -/** A connection to a directory server: upload a v3 consensus signature */ -#define DIR_PURPOSE_UPLOAD_SIGNATURES 11 -/** A connection to a directory server: download one or more v3 networkstatus - * votes. */ -#define DIR_PURPOSE_FETCH_STATUS_VOTE 12 -/** A connection to a directory server: download a v3 detached signatures - * object for a consensus. */ -#define DIR_PURPOSE_FETCH_DETACHED_SIGNATURES 13 -/** A connection to a directory server: download a v3 networkstatus - * consensus. */ -#define DIR_PURPOSE_FETCH_CONSENSUS 14 -/** A connection to a directory server: download one or more directory - * authority certificates. */ -#define DIR_PURPOSE_FETCH_CERTIFICATE 15 - -/** Purpose for connection at a directory server. */ -#define DIR_PURPOSE_SERVER 16 -/** A connection to a hidden service directory server: upload a v2 rendezvous - * descriptor. */ -#define DIR_PURPOSE_UPLOAD_RENDDESC_V2 17 -/** A connection to a hidden service directory server: download a v2 rendezvous - * descriptor. */ -#define DIR_PURPOSE_FETCH_RENDDESC_V2 18 -/** A connection to a directory server: download a microdescriptor. */ -#define DIR_PURPOSE_FETCH_MICRODESC 19 -/** A connection to a hidden service directory: upload a v3 descriptor. */ -#define DIR_PURPOSE_UPLOAD_HSDESC 20 -/** A connection to a hidden service directory: fetch a v3 descriptor. */ -#define DIR_PURPOSE_FETCH_HSDESC 21 -/** A connection to a directory server: set after a hidden service descriptor - * is downloaded. */ -#define DIR_PURPOSE_HAS_FETCHED_HSDESC 22 -#define DIR_PURPOSE_MAX_ 22 - -/** True iff <b>p</b> is a purpose corresponding to uploading - * data to a directory server. */ -#define DIR_PURPOSE_IS_UPLOAD(p) \ - ((p)==DIR_PURPOSE_UPLOAD_DIR || \ - (p)==DIR_PURPOSE_UPLOAD_VOTE || \ - (p)==DIR_PURPOSE_UPLOAD_SIGNATURES || \ - (p)==DIR_PURPOSE_UPLOAD_RENDDESC_V2 || \ - (p)==DIR_PURPOSE_UPLOAD_HSDESC) - -#define EXIT_PURPOSE_MIN_ 1 -/** This exit stream wants to do an ordinary connect. */ -#define EXIT_PURPOSE_CONNECT 1 -/** This exit stream wants to do a resolve (either normal or reverse). */ -#define EXIT_PURPOSE_RESOLVE 2 -#define EXIT_PURPOSE_MAX_ 2 - -/* !!!! If any connection purpose is ever over 31, we must grow the type - * field in connection_t. */ - -/** Circuit state: I'm the origin, still haven't done all my handshakes. */ -#define CIRCUIT_STATE_BUILDING 0 -/** Circuit state: Waiting to process the onionskin. */ -#define CIRCUIT_STATE_ONIONSKIN_PENDING 1 -/** Circuit state: I'd like to deliver a create, but my n_chan is still - * connecting. */ -#define CIRCUIT_STATE_CHAN_WAIT 2 -/** Circuit state: the circuit is open but we don't want to actually use it - * until we find out if a better guard will be available. - */ -#define CIRCUIT_STATE_GUARD_WAIT 3 -/** Circuit state: onionskin(s) processed, ready to send/receive cells. */ -#define CIRCUIT_STATE_OPEN 4 - -#define CIRCUIT_PURPOSE_MIN_ 1 - -/* these circuits were initiated elsewhere */ -#define CIRCUIT_PURPOSE_OR_MIN_ 1 -/** OR-side circuit purpose: normal circuit, at OR. */ -#define CIRCUIT_PURPOSE_OR 1 -/** OR-side circuit purpose: At OR, from the service, waiting for intro from - * clients. */ -#define CIRCUIT_PURPOSE_INTRO_POINT 2 -/** OR-side circuit purpose: At OR, from the client, waiting for the service. - */ -#define CIRCUIT_PURPOSE_REND_POINT_WAITING 3 -/** OR-side circuit purpose: At OR, both circuits have this purpose. */ -#define CIRCUIT_PURPOSE_REND_ESTABLISHED 4 -#define CIRCUIT_PURPOSE_OR_MAX_ 4 - -/* these circuits originate at this node */ - -/* here's how circ client-side purposes work: - * normal circuits are C_GENERAL. - * circuits that are c_introducing are either on their way to - * becoming open, or they are open and waiting for a - * suitable rendcirc before they send the intro. - * circuits that are c_introduce_ack_wait have sent the intro, - * but haven't gotten a response yet. - * circuits that are c_establish_rend are either on their way - * to becoming open, or they are open and have sent the - * establish_rendezvous cell but haven't received an ack. - * circuits that are c_rend_ready are open and have received a - * rend ack, but haven't heard from the service yet. if they have a - * buildstate->pending_final_cpath then they're expecting a - * cell from the service, else they're not. - * circuits that are c_rend_ready_intro_acked are open, and - * some intro circ has sent its intro and received an ack. - * circuits that are c_rend_joined are open, have heard from - * the service, and are talking to it. - */ -/** Client-side circuit purpose: Normal circuit, with cpath. */ -#define CIRCUIT_PURPOSE_C_GENERAL 5 -#define CIRCUIT_PURPOSE_C_HS_MIN_ 6 -/** Client-side circuit purpose: at the client, connecting to intro point. */ -#define CIRCUIT_PURPOSE_C_INTRODUCING 6 -/** Client-side circuit purpose: at the client, sent INTRODUCE1 to intro point, - * waiting for ACK/NAK. */ -#define CIRCUIT_PURPOSE_C_INTRODUCE_ACK_WAIT 7 -/** Client-side circuit purpose: at the client, introduced and acked, closing. - */ -#define CIRCUIT_PURPOSE_C_INTRODUCE_ACKED 8 -/** Client-side circuit purpose: at the client, waiting for ack. */ -#define CIRCUIT_PURPOSE_C_ESTABLISH_REND 9 -/** Client-side circuit purpose: at the client, waiting for the service. */ -#define CIRCUIT_PURPOSE_C_REND_READY 10 -/** Client-side circuit purpose: at the client, waiting for the service, - * INTRODUCE has been acknowledged. */ -#define CIRCUIT_PURPOSE_C_REND_READY_INTRO_ACKED 11 -/** Client-side circuit purpose: at the client, rendezvous established. */ -#define CIRCUIT_PURPOSE_C_REND_JOINED 12 -/** This circuit is used for getting hsdirs */ -#define CIRCUIT_PURPOSE_C_HSDIR_GET 13 -#define CIRCUIT_PURPOSE_C_HS_MAX_ 13 -/** This circuit is used for build time measurement only */ -#define CIRCUIT_PURPOSE_C_MEASURE_TIMEOUT 14 -#define CIRCUIT_PURPOSE_C_MAX_ 14 - -#define CIRCUIT_PURPOSE_S_HS_MIN_ 15 -/** Hidden-service-side circuit purpose: at the service, waiting for - * introductions. */ -#define CIRCUIT_PURPOSE_S_ESTABLISH_INTRO 15 -/** Hidden-service-side circuit purpose: at the service, successfully - * established intro. */ -#define CIRCUIT_PURPOSE_S_INTRO 16 -/** Hidden-service-side circuit purpose: at the service, connecting to rend - * point. */ -#define CIRCUIT_PURPOSE_S_CONNECT_REND 17 -/** Hidden-service-side circuit purpose: at the service, rendezvous - * established. */ -#define CIRCUIT_PURPOSE_S_REND_JOINED 18 -/** This circuit is used for uploading hsdirs */ -#define CIRCUIT_PURPOSE_S_HSDIR_POST 19 -#define CIRCUIT_PURPOSE_S_HS_MAX_ 19 - -/** A testing circuit; not meant to be used for actual traffic. */ -#define CIRCUIT_PURPOSE_TESTING 20 -/** A controller made this circuit and Tor should not use it. */ -#define CIRCUIT_PURPOSE_CONTROLLER 21 -/** This circuit is used for path bias probing only */ -#define CIRCUIT_PURPOSE_PATH_BIAS_TESTING 22 - -/** This circuit is used for vanguards/restricted paths. - * - * This type of circuit is *only* created preemptively and never - * on-demand. When an HS operation needs to take place (e.g. connect to an - * intro point), these circuits are then cannibalized and repurposed to the - * actual needed HS purpose. */ -#define CIRCUIT_PURPOSE_HS_VANGUARDS 23 - -#define CIRCUIT_PURPOSE_MAX_ 23 -/** A catch-all for unrecognized purposes. Currently we don't expect - * to make or see any circuits with this purpose. */ -#define CIRCUIT_PURPOSE_UNKNOWN 255 - -/** True iff the circuit purpose <b>p</b> is for a circuit that - * originated at this node. */ -#define CIRCUIT_PURPOSE_IS_ORIGIN(p) ((p)>CIRCUIT_PURPOSE_OR_MAX_) -/** True iff the circuit purpose <b>p</b> is for a circuit that originated - * here to serve as a client. (Hidden services don't count here.) */ -#define CIRCUIT_PURPOSE_IS_CLIENT(p) \ - ((p)> CIRCUIT_PURPOSE_OR_MAX_ && \ - (p)<=CIRCUIT_PURPOSE_C_MAX_) -/** True iff the circuit_t <b>c</b> is actually an origin_circuit_t. */ -#define CIRCUIT_IS_ORIGIN(c) (CIRCUIT_PURPOSE_IS_ORIGIN((c)->purpose)) -/** True iff the circuit purpose <b>p</b> is for an established rendezvous - * circuit. */ -#define CIRCUIT_PURPOSE_IS_ESTABLISHED_REND(p) \ - ((p) == CIRCUIT_PURPOSE_C_REND_JOINED || \ - (p) == CIRCUIT_PURPOSE_S_REND_JOINED) -/** True iff the circuit_t c is actually an or_circuit_t */ -#define CIRCUIT_IS_ORCIRC(c) (((circuit_t *)(c))->magic == OR_CIRCUIT_MAGIC) - -/** True iff this circuit purpose should count towards the global - * pending rate limit (set by MaxClientCircuitsPending). We count all - * general purpose circuits, as well as the first step of client onion - * service connections (HSDir gets). */ -#define CIRCUIT_PURPOSE_COUNTS_TOWARDS_MAXPENDING(p) \ - ((p) == CIRCUIT_PURPOSE_C_GENERAL || \ - (p) == CIRCUIT_PURPOSE_C_HSDIR_GET) - -/** How many circuits do we want simultaneously in-progress to handle - * a given stream? */ -#define MIN_CIRCUITS_HANDLING_STREAM 2 - -/* These RELAY_COMMAND constants define values for relay cell commands, and -* must match those defined in tor-spec.txt. */ -#define RELAY_COMMAND_BEGIN 1 -#define RELAY_COMMAND_DATA 2 -#define RELAY_COMMAND_END 3 -#define RELAY_COMMAND_CONNECTED 4 -#define RELAY_COMMAND_SENDME 5 -#define RELAY_COMMAND_EXTEND 6 -#define RELAY_COMMAND_EXTENDED 7 -#define RELAY_COMMAND_TRUNCATE 8 -#define RELAY_COMMAND_TRUNCATED 9 -#define RELAY_COMMAND_DROP 10 -#define RELAY_COMMAND_RESOLVE 11 -#define RELAY_COMMAND_RESOLVED 12 -#define RELAY_COMMAND_BEGIN_DIR 13 -#define RELAY_COMMAND_EXTEND2 14 -#define RELAY_COMMAND_EXTENDED2 15 - -#define RELAY_COMMAND_ESTABLISH_INTRO 32 -#define RELAY_COMMAND_ESTABLISH_RENDEZVOUS 33 -#define RELAY_COMMAND_INTRODUCE1 34 -#define RELAY_COMMAND_INTRODUCE2 35 -#define RELAY_COMMAND_RENDEZVOUS1 36 -#define RELAY_COMMAND_RENDEZVOUS2 37 -#define RELAY_COMMAND_INTRO_ESTABLISHED 38 -#define RELAY_COMMAND_RENDEZVOUS_ESTABLISHED 39 -#define RELAY_COMMAND_INTRODUCE_ACK 40 - -/* Reasons why an OR connection is closed. */ -#define END_OR_CONN_REASON_DONE 1 -#define END_OR_CONN_REASON_REFUSED 2 /* connection refused */ -#define END_OR_CONN_REASON_OR_IDENTITY 3 -#define END_OR_CONN_REASON_CONNRESET 4 /* connection reset by peer */ -#define END_OR_CONN_REASON_TIMEOUT 5 -#define END_OR_CONN_REASON_NO_ROUTE 6 /* no route to host/net */ -#define END_OR_CONN_REASON_IO_ERROR 7 /* read/write error */ -#define END_OR_CONN_REASON_RESOURCE_LIMIT 8 /* sockets, buffers, etc */ -#define END_OR_CONN_REASON_PT_MISSING 9 /* PT failed or not available */ -#define END_OR_CONN_REASON_MISC 10 - -/* Reasons why we (or a remote OR) might close a stream. See tor-spec.txt for - * documentation of these. The values must match. */ -#define END_STREAM_REASON_MISC 1 -#define END_STREAM_REASON_RESOLVEFAILED 2 -#define END_STREAM_REASON_CONNECTREFUSED 3 -#define END_STREAM_REASON_EXITPOLICY 4 -#define END_STREAM_REASON_DESTROY 5 -#define END_STREAM_REASON_DONE 6 -#define END_STREAM_REASON_TIMEOUT 7 -#define END_STREAM_REASON_NOROUTE 8 -#define END_STREAM_REASON_HIBERNATING 9 -#define END_STREAM_REASON_INTERNAL 10 -#define END_STREAM_REASON_RESOURCELIMIT 11 -#define END_STREAM_REASON_CONNRESET 12 -#define END_STREAM_REASON_TORPROTOCOL 13 -#define END_STREAM_REASON_NOTDIRECTORY 14 -#define END_STREAM_REASON_ENTRYPOLICY 15 - -/* These high-numbered end reasons are not part of the official spec, - * and are not intended to be put in relay end cells. They are here - * to be more informative when sending back socks replies to the - * application. */ -/* XXXX 256 is no longer used; feel free to reuse it. */ -/** We were unable to attach the connection to any circuit at all. */ -/* XXXX the ways we use this one don't make a lot of sense. */ -#define END_STREAM_REASON_CANT_ATTACH 257 -/** We can't connect to any directories at all, so we killed our streams - * before they can time out. */ -#define END_STREAM_REASON_NET_UNREACHABLE 258 -/** This is a SOCKS connection, and the client used (or misused) the SOCKS - * protocol in a way we couldn't handle. */ -#define END_STREAM_REASON_SOCKSPROTOCOL 259 -/** This is a transparent proxy connection, but we can't extract the original - * target address:port. */ -#define END_STREAM_REASON_CANT_FETCH_ORIG_DEST 260 -/** This is a connection on the NATD port, and the destination IP:Port was - * either ill-formed or out-of-range. */ -#define END_STREAM_REASON_INVALID_NATD_DEST 261 -/** The target address is in a private network (like 127.0.0.1 or 10.0.0.1); - * you don't want to do that over a randomly chosen exit */ -#define END_STREAM_REASON_PRIVATE_ADDR 262 -/** This is an HTTP tunnel connection and the client used or misused HTTP in a - * way we can't handle. - */ -#define END_STREAM_REASON_HTTPPROTOCOL 263 - -/** Bitwise-and this value with endreason to mask out all flags. */ -#define END_STREAM_REASON_MASK 511 - -/** Bitwise-or this with the argument to control_event_stream_status - * to indicate that the reason came from an END cell. */ -#define END_STREAM_REASON_FLAG_REMOTE 512 -/** Bitwise-or this with the argument to control_event_stream_status - * to indicate that we already sent a CLOSED stream event. */ -#define END_STREAM_REASON_FLAG_ALREADY_SENT_CLOSED 1024 -/** Bitwise-or this with endreason to indicate that we already sent - * a socks reply, and no further reply needs to be sent from - * connection_mark_unattached_ap(). */ -#define END_STREAM_REASON_FLAG_ALREADY_SOCKS_REPLIED 2048 - -/** Reason for remapping an AP connection's address: we have a cached - * answer. */ -#define REMAP_STREAM_SOURCE_CACHE 1 -/** Reason for remapping an AP connection's address: the exit node told us an - * answer. */ -#define REMAP_STREAM_SOURCE_EXIT 2 - -/* 'type' values to use in RESOLVED cells. Specified in tor-spec.txt. */ -#define RESOLVED_TYPE_HOSTNAME 0 -#define RESOLVED_TYPE_IPV4 4 -#define RESOLVED_TYPE_IPV6 6 -#define RESOLVED_TYPE_ERROR_TRANSIENT 0xF0 -#define RESOLVED_TYPE_ERROR 0xF1 - -/* Negative reasons are internal: we never send them in a DESTROY or TRUNCATE - * call; they only go to the controller for tracking */ - -/* Closing introduction point that were opened in parallel. */ -#define END_CIRC_REASON_IP_NOW_REDUNDANT -4 - -/** Our post-timeout circuit time measurement period expired. - * We must give up now */ -#define END_CIRC_REASON_MEASUREMENT_EXPIRED -3 - -/** We couldn't build a path for this circuit. */ -#define END_CIRC_REASON_NOPATH -2 -/** Catch-all "other" reason for closing origin circuits. */ -#define END_CIRC_AT_ORIGIN -1 - -/* Reasons why we (or a remote OR) might close a circuit. See tor-spec.txt - * section 5.4 for documentation of these. */ -#define END_CIRC_REASON_MIN_ 0 -#define END_CIRC_REASON_NONE 0 -#define END_CIRC_REASON_TORPROTOCOL 1 -#define END_CIRC_REASON_INTERNAL 2 -#define END_CIRC_REASON_REQUESTED 3 -#define END_CIRC_REASON_HIBERNATING 4 -#define END_CIRC_REASON_RESOURCELIMIT 5 -#define END_CIRC_REASON_CONNECTFAILED 6 -#define END_CIRC_REASON_OR_IDENTITY 7 -#define END_CIRC_REASON_CHANNEL_CLOSED 8 -#define END_CIRC_REASON_FINISHED 9 -#define END_CIRC_REASON_TIMEOUT 10 -#define END_CIRC_REASON_DESTROYED 11 -#define END_CIRC_REASON_NOSUCHSERVICE 12 -#define END_CIRC_REASON_MAX_ 12 - -/** Bitwise-OR this with the argument to circuit_mark_for_close() or - * control_event_circuit_status() to indicate that the reason was - * passed through from a destroy or truncate cell. */ -#define END_CIRC_REASON_FLAG_REMOTE 512 - -/** Length of 'y' portion of 'y.onion' URL. */ -#define REND_SERVICE_ID_LEN_BASE32 16 - -/** Length of 'y.onion' including '.onion' URL. */ -#define REND_SERVICE_ADDRESS_LEN (16+1+5) - -/** Length of a binary-encoded rendezvous service ID. */ -#define REND_SERVICE_ID_LEN 10 - -/** Time period for which a v2 descriptor will be valid. */ -#define REND_TIME_PERIOD_V2_DESC_VALIDITY (24*60*60) - -/** Time period within which two sets of v2 descriptors will be uploaded in - * parallel. */ -#define REND_TIME_PERIOD_OVERLAPPING_V2_DESCS (60*60) - -/** Number of non-consecutive replicas (i.e. distributed somewhere - * in the ring) for a descriptor. */ -#define REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS 2 - -/** Number of consecutive replicas for a descriptor. */ -#define REND_NUMBER_OF_CONSECUTIVE_REPLICAS 3 - -/** Length of v2 descriptor ID (32 base32 chars = 160 bits). */ -#define REND_DESC_ID_V2_LEN_BASE32 BASE32_DIGEST_LEN - -/** Length of the base32-encoded secret ID part of versioned hidden service - * descriptors. */ -#define REND_SECRET_ID_PART_LEN_BASE32 BASE32_DIGEST_LEN - -/** Length of the base32-encoded hash of an introduction point's - * identity key. */ -#define REND_INTRO_POINT_ID_LEN_BASE32 BASE32_DIGEST_LEN - -/** Length of the descriptor cookie that is used for client authorization - * to hidden services. */ -#define REND_DESC_COOKIE_LEN 16 - -/** Length of the base64-encoded descriptor cookie that is used for - * exchanging client authorization between hidden service and client. */ -#define REND_DESC_COOKIE_LEN_BASE64 22 - -/** Length of client identifier in encrypted introduction points for hidden - * service authorization type 'basic'. */ -#define REND_BASIC_AUTH_CLIENT_ID_LEN 4 - -/** Multiple of the number of clients to which the real number of clients - * is padded with fake clients for hidden service authorization type - * 'basic'. */ -#define REND_BASIC_AUTH_CLIENT_MULTIPLE 16 - -/** Length of client entry consisting of client identifier and encrypted - * session key for hidden service authorization type 'basic'. */ -#define REND_BASIC_AUTH_CLIENT_ENTRY_LEN (REND_BASIC_AUTH_CLIENT_ID_LEN \ - + CIPHER_KEY_LEN) - -/** Maximum size of v2 hidden service descriptors. */ -#define REND_DESC_MAX_SIZE (20 * 1024) - -/** Legal characters for use in authorized client names for a hidden - * service. */ -#define REND_LEGAL_CLIENTNAME_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-_" - -/** Maximum length of authorized client names for a hidden service. */ -#define REND_CLIENTNAME_MAX_LEN 16 - -/** Length of the rendezvous cookie that is used to connect circuits at the - * rendezvous point. */ -#define REND_COOKIE_LEN DIGEST_LEN - -/** Client authorization type that a hidden service performs. */ -typedef enum rend_auth_type_t { - REND_NO_AUTH = 0, - REND_BASIC_AUTH = 1, - REND_STEALTH_AUTH = 2, -} rend_auth_type_t; - -/** Client-side configuration of authorization for a hidden service. */ -typedef struct rend_service_authorization_t { - uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; - char onion_address[REND_SERVICE_ADDRESS_LEN+1]; - rend_auth_type_t auth_type; -} rend_service_authorization_t; - -/** Client- and server-side data that is used for hidden service connection - * establishment. Not all fields contain data depending on where this struct - * is used. */ -typedef struct rend_data_t { - /* Hidden service protocol version of this base object. */ - uint32_t version; - - /** List of HSDir fingerprints on which this request has been sent to. This - * contains binary identity digest of the directory of size DIGEST_LEN. */ - smartlist_t *hsdirs_fp; - - /** Rendezvous cookie used by both, client and service. */ - char rend_cookie[REND_COOKIE_LEN]; - - /** Number of streams associated with this rendezvous circuit. */ - int nr_streams; -} rend_data_t; - -typedef struct rend_data_v2_t { - /* Rendezvous base data. */ - rend_data_t base_; - - /** Onion address (without the .onion part) that a client requests. */ - char onion_address[REND_SERVICE_ID_LEN_BASE32+1]; - - /** Descriptor ID for each replicas computed from the onion address. If - * the onion address is empty, this array MUST be empty. We keep them so - * we know when to purge our entry in the last hsdir request table. */ - char descriptor_id[REND_NUMBER_OF_NON_CONSECUTIVE_REPLICAS][DIGEST_LEN]; - - /** (Optional) descriptor cookie that is used by a client. */ - char descriptor_cookie[REND_DESC_COOKIE_LEN]; - - /** Authorization type for accessing a service used by a client. */ - rend_auth_type_t auth_type; - - /** Descriptor ID for a client request. The control port command HSFETCH - * uses this. It's set if the descriptor query should only use this - * descriptor ID. */ - char desc_id_fetch[DIGEST_LEN]; - - /** Hash of the hidden service's PK used by a service. */ - char rend_pk_digest[DIGEST_LEN]; -} rend_data_v2_t; - -/* From a base rend_data_t object <b>d</d>, return the v2 object. */ -static inline -rend_data_v2_t *TO_REND_DATA_V2(const rend_data_t *d) -{ - tor_assert(d); - tor_assert(d->version == 2); - return DOWNCAST(rend_data_v2_t, d); -} - -/* Stub because we can't include hs_ident.h. */ -struct hs_ident_edge_conn_t; -struct hs_ident_dir_conn_t; -struct hs_ident_circuit_t; - -/* Hidden service directory index used in a node_t which is set once we set - * the consensus. */ -typedef struct hsdir_index_t { - /* HSDir index to use when fetching a descriptor. */ - uint8_t fetch[DIGEST256_LEN]; - - /* HSDir index used by services to store their first and second - * descriptor. The first descriptor is chronologically older than the second - * one and uses older TP and SRV values. */ - uint8_t store_first[DIGEST256_LEN]; - uint8_t store_second[DIGEST256_LEN]; -} hsdir_index_t; - -/** Time interval for tracking replays of DH public keys received in - * INTRODUCE2 cells. Used only to avoid launching multiple - * simultaneous attempts to connect to the same rendezvous point. */ -#define REND_REPLAY_TIME_INTERVAL (5 * 60) - -/** Used to indicate which way a cell is going on a circuit. */ -typedef enum { - CELL_DIRECTION_IN=1, /**< The cell is moving towards the origin. */ - CELL_DIRECTION_OUT=2, /**< The cell is moving away from the origin. */ -} cell_direction_t; - -/** Initial value for both sides of a circuit transmission window when the - * circuit is initialized. Measured in cells. */ -#define CIRCWINDOW_START 1000 -#define CIRCWINDOW_START_MIN 100 -#define CIRCWINDOW_START_MAX 1000 -/** Amount to increment a circuit window when we get a circuit SENDME. */ -#define CIRCWINDOW_INCREMENT 100 -/** Initial value on both sides of a stream transmission window when the - * stream is initialized. Measured in cells. */ -#define STREAMWINDOW_START 500 -#define STREAMWINDOW_START_MAX 500 -/** Amount to increment a stream window when we get a stream SENDME. */ -#define STREAMWINDOW_INCREMENT 50 - -/** Maximum number of queued cells on a circuit for which we are the - * midpoint before we give up and kill it. This must be >= circwindow - * to avoid killing innocent circuits, and >= circwindow*2 to give - * leaky-pipe a chance of working someday. The ORCIRC_MAX_MIDDLE_KILL_THRESH - * ratio controls the margin of error between emitting a warning and - * killing the circuit. - */ -#define ORCIRC_MAX_MIDDLE_CELLS (CIRCWINDOW_START_MAX*2) -/** Ratio of hard (circuit kill) to soft (warning) thresholds for the - * ORCIRC_MAX_MIDDLE_CELLS tests. - */ -#define ORCIRC_MAX_MIDDLE_KILL_THRESH (1.1f) - -/* Cell commands. These values are defined in tor-spec.txt. */ -#define CELL_PADDING 0 -#define CELL_CREATE 1 -#define CELL_CREATED 2 -#define CELL_RELAY 3 -#define CELL_DESTROY 4 -#define CELL_CREATE_FAST 5 -#define CELL_CREATED_FAST 6 -#define CELL_VERSIONS 7 -#define CELL_NETINFO 8 -#define CELL_RELAY_EARLY 9 -#define CELL_CREATE2 10 -#define CELL_CREATED2 11 -#define CELL_PADDING_NEGOTIATE 12 - -#define CELL_VPADDING 128 -#define CELL_CERTS 129 -#define CELL_AUTH_CHALLENGE 130 -#define CELL_AUTHENTICATE 131 -#define CELL_AUTHORIZE 132 -#define CELL_COMMAND_MAX_ 132 - -/** How long to test reachability before complaining to the user. */ -#define TIMEOUT_UNTIL_UNREACHABILITY_COMPLAINT (20*60) - -/** Legal characters in a nickname. */ -#define LEGAL_NICKNAME_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - -/** Name to use in client TLS certificates if no nickname is given. Once - * Tor 0.1.2.x is obsolete, we can remove this. */ -#define DEFAULT_CLIENT_NICKNAME "client" - -/** Name chosen by routers that don't configure nicknames */ -#define UNNAMED_ROUTER_NICKNAME "Unnamed" - -/** Number of bytes in a SOCKS4 header. */ -#define SOCKS4_NETWORK_LEN 8 - -/* - * Relay payload: - * Relay command [1 byte] - * Recognized [2 bytes] - * Stream ID [2 bytes] - * Partial SHA-1 [4 bytes] - * Length [2 bytes] - * Relay payload [498 bytes] - */ - -/** Number of bytes in a cell, minus cell header. */ -#define CELL_PAYLOAD_SIZE 509 -/** Number of bytes in a cell transmitted over the network, in the longest - * form */ -#define CELL_MAX_NETWORK_SIZE 514 - -/** Maximum length of a header on a variable-length cell. */ -#define VAR_CELL_MAX_HEADER_SIZE 7 - -static int get_cell_network_size(int wide_circ_ids); -static inline int get_cell_network_size(int wide_circ_ids) -{ - return wide_circ_ids ? CELL_MAX_NETWORK_SIZE : CELL_MAX_NETWORK_SIZE - 2; -} -static int get_var_cell_header_size(int wide_circ_ids); -static inline int get_var_cell_header_size(int wide_circ_ids) -{ - return wide_circ_ids ? VAR_CELL_MAX_HEADER_SIZE : - VAR_CELL_MAX_HEADER_SIZE - 2; -} -static int get_circ_id_size(int wide_circ_ids); -static inline int get_circ_id_size(int wide_circ_ids) -{ - return wide_circ_ids ? 4 : 2; -} - -/** Number of bytes in a relay cell's header (not including general cell - * header). */ -#define RELAY_HEADER_SIZE (1+2+2+4+2) -/** Largest number of bytes that can fit in a relay cell payload. */ -#define RELAY_PAYLOAD_SIZE (CELL_PAYLOAD_SIZE-RELAY_HEADER_SIZE) - -/** Identifies a circuit on an or_connection */ -typedef uint32_t circid_t; -/** Identifies a stream on a circuit */ -typedef uint16_t streamid_t; - -/* channel_t typedef; struct channel_s is in channel.h */ - -typedef struct channel_s channel_t; - -/* channel_listener_t typedef; struct channel_listener_s is in channel.h */ - -typedef struct channel_listener_s channel_listener_t; - -/* channel states for channel_t */ - -typedef enum { - /* - * Closed state - channel is inactive - * - * Permitted transitions from: - * - CHANNEL_STATE_CLOSING - * Permitted transitions to: - * - CHANNEL_STATE_OPENING - */ - CHANNEL_STATE_CLOSED = 0, - /* - * Opening state - channel is trying to connect - * - * Permitted transitions from: - * - CHANNEL_STATE_CLOSED - * Permitted transitions to: - * - CHANNEL_STATE_CLOSING - * - CHANNEL_STATE_ERROR - * - CHANNEL_STATE_OPEN - */ - CHANNEL_STATE_OPENING, - /* - * Open state - channel is active and ready for use - * - * Permitted transitions from: - * - CHANNEL_STATE_MAINT - * - CHANNEL_STATE_OPENING - * Permitted transitions to: - * - CHANNEL_STATE_CLOSING - * - CHANNEL_STATE_ERROR - * - CHANNEL_STATE_MAINT - */ - CHANNEL_STATE_OPEN, - /* - * Maintenance state - channel is temporarily offline for subclass specific - * maintenance activities such as TLS renegotiation. - * - * Permitted transitions from: - * - CHANNEL_STATE_OPEN - * Permitted transitions to: - * - CHANNEL_STATE_CLOSING - * - CHANNEL_STATE_ERROR - * - CHANNEL_STATE_OPEN - */ - CHANNEL_STATE_MAINT, - /* - * Closing state - channel is shutting down - * - * Permitted transitions from: - * - CHANNEL_STATE_MAINT - * - CHANNEL_STATE_OPEN - * Permitted transitions to: - * - CHANNEL_STATE_CLOSED, - * - CHANNEL_STATE_ERROR - */ - CHANNEL_STATE_CLOSING, - /* - * Error state - channel has experienced a permanent error - * - * Permitted transitions from: - * - CHANNEL_STATE_CLOSING - * - CHANNEL_STATE_MAINT - * - CHANNEL_STATE_OPENING - * - CHANNEL_STATE_OPEN - * Permitted transitions to: - * - None - */ - CHANNEL_STATE_ERROR, - /* - * Placeholder for maximum state value - */ - CHANNEL_STATE_LAST -} channel_state_t; - -/* channel listener states for channel_listener_t */ - -typedef enum { - /* - * Closed state - channel listener is inactive - * - * Permitted transitions from: - * - CHANNEL_LISTENER_STATE_CLOSING - * Permitted transitions to: - * - CHANNEL_LISTENER_STATE_LISTENING - */ - CHANNEL_LISTENER_STATE_CLOSED = 0, - /* - * Listening state - channel listener is listening for incoming - * connections - * - * Permitted transitions from: - * - CHANNEL_LISTENER_STATE_CLOSED - * Permitted transitions to: - * - CHANNEL_LISTENER_STATE_CLOSING - * - CHANNEL_LISTENER_STATE_ERROR - */ - CHANNEL_LISTENER_STATE_LISTENING, - /* - * Closing state - channel listener is shutting down - * - * Permitted transitions from: - * - CHANNEL_LISTENER_STATE_LISTENING - * Permitted transitions to: - * - CHANNEL_LISTENER_STATE_CLOSED, - * - CHANNEL_LISTENER_STATE_ERROR - */ - CHANNEL_LISTENER_STATE_CLOSING, - /* - * Error state - channel listener has experienced a permanent error - * - * Permitted transitions from: - * - CHANNEL_STATE_CLOSING - * - CHANNEL_STATE_LISTENING - * Permitted transitions to: - * - None - */ - CHANNEL_LISTENER_STATE_ERROR, - /* - * Placeholder for maximum state value - */ - CHANNEL_LISTENER_STATE_LAST -} channel_listener_state_t; - -/* TLS channel stuff */ - -typedef struct channel_tls_s channel_tls_t; - -/* circuitmux_t typedef; struct circuitmux_s is in circuitmux.h */ - -typedef struct circuitmux_s circuitmux_t; - -/** Parsed onion routing cell. All communication between nodes - * is via cells. */ -typedef struct cell_t { - circid_t circ_id; /**< Circuit which received the cell. */ - uint8_t command; /**< Type of the cell: one of CELL_PADDING, CELL_CREATE, - * CELL_DESTROY, etc */ - uint8_t payload[CELL_PAYLOAD_SIZE]; /**< Cell body. */ -} cell_t; - -/** Parsed variable-length onion routing cell. */ -typedef struct var_cell_t { - /** Type of the cell: CELL_VERSIONS, etc. */ - uint8_t command; - /** Circuit thich received the cell */ - circid_t circ_id; - /** Number of bytes actually stored in <b>payload</b> */ - uint16_t payload_len; - /** Payload of this cell */ - uint8_t payload[FLEXIBLE_ARRAY_MEMBER]; -} var_cell_t; - -/** A parsed Extended ORPort message. */ -typedef struct ext_or_cmd_t { - uint16_t cmd; /** Command type */ - uint16_t len; /** Body length */ - char body[FLEXIBLE_ARRAY_MEMBER]; /** Message body */ -} ext_or_cmd_t; - -/** A cell as packed for writing to the network. */ -typedef struct packed_cell_t { - /** Next cell queued on this circuit. */ - TOR_SIMPLEQ_ENTRY(packed_cell_t) next; - char body[CELL_MAX_NETWORK_SIZE]; /**< Cell as packed for network. */ - uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell - * was inserted */ -} packed_cell_t; - -/** A queue of cells on a circuit, waiting to be added to the - * or_connection_t's outbuf. */ -typedef struct cell_queue_t { - /** Linked list of packed_cell_t*/ - TOR_SIMPLEQ_HEAD(cell_simpleq, packed_cell_t) head; - int n; /**< The number of cells in the queue. */ -} cell_queue_t; - -/** A single queued destroy cell. */ -typedef struct destroy_cell_t { - TOR_SIMPLEQ_ENTRY(destroy_cell_t) next; - circid_t circid; - uint32_t inserted_timestamp; /**< Time (in timestamp units) when this cell - * was inserted */ - uint8_t reason; -} destroy_cell_t; - -/** A queue of destroy cells on a channel. */ -typedef struct destroy_cell_queue_t { - /** Linked list of packed_cell_t */ - TOR_SIMPLEQ_HEAD(dcell_simpleq, destroy_cell_t) head; - int n; /**< The number of cells in the queue. */ -} destroy_cell_queue_t; - -/** Beginning of a RELAY cell payload. */ -typedef struct { - uint8_t command; /**< The end-to-end relay command. */ - uint16_t recognized; /**< Used to tell whether cell is for us. */ - streamid_t stream_id; /**< Which stream is this cell associated with? */ - char integrity[4]; /**< Used to tell whether cell is corrupted. */ - uint16_t length; /**< How long is the payload body? */ -} relay_header_t; - -typedef struct socks_request_t socks_request_t; - -typedef struct entry_port_cfg_t { - /* Client port types (socks, dns, trans, natd) only: */ - uint8_t isolation_flags; /**< Zero or more isolation flags */ - int session_group; /**< A session group, or -1 if this port is not in a - * session group. */ - - /* Socks only: */ - /** When both no-auth and user/pass are advertised by a SOCKS client, select - * no-auth. */ - unsigned int socks_prefer_no_auth : 1; - /** When ISO_SOCKSAUTH is in use, Keep-Alive circuits indefinitely. */ - unsigned int socks_iso_keep_alive : 1; - - /* Client port types only: */ - unsigned int ipv4_traffic : 1; - unsigned int ipv6_traffic : 1; - unsigned int prefer_ipv6 : 1; - unsigned int dns_request : 1; - unsigned int onion_traffic : 1; - - /** For a socks listener: should we cache IPv4/IPv6 DNS information that - * exit nodes tell us? - * - * @{ */ - unsigned int cache_ipv4_answers : 1; - unsigned int cache_ipv6_answers : 1; - /** @} */ - /** For a socks listeners: if we find an answer in our client-side DNS cache, - * should we use it? - * - * @{ */ - unsigned int use_cached_ipv4_answers : 1; - unsigned int use_cached_ipv6_answers : 1; - /** @} */ - /** For socks listeners: When we can automap an address to IPv4 or IPv6, - * do we prefer IPv6? */ - unsigned int prefer_ipv6_virtaddr : 1; - -} entry_port_cfg_t; - -typedef struct server_port_cfg_t { - /* Server port types (or, dir) only: */ - unsigned int no_advertise : 1; - unsigned int no_listen : 1; - unsigned int all_addrs : 1; - unsigned int bind_ipv4_only : 1; - unsigned int bind_ipv6_only : 1; -} server_port_cfg_t; - -/* Values for connection_t.magic: used to make sure that downcasts (casts from -* connection_t to foo_connection_t) are safe. */ -#define BASE_CONNECTION_MAGIC 0x7C3C304Eu -#define OR_CONNECTION_MAGIC 0x7D31FF03u -#define EDGE_CONNECTION_MAGIC 0xF0374013u -#define ENTRY_CONNECTION_MAGIC 0xbb4a5703 -#define DIR_CONNECTION_MAGIC 0x9988ffeeu -#define CONTROL_CONNECTION_MAGIC 0x8abc765du -#define LISTENER_CONNECTION_MAGIC 0x1a1ac741u - -struct buf_t; - -/** Description of a connection to another host or process, and associated - * data. - * - * A connection is named based on what it's connected to -- an "OR - * connection" has a Tor node on the other end, an "exit - * connection" has a website or other server on the other end, and an - * "AP connection" has an application proxy (and thus a user) on the - * other end. - * - * Every connection has a type and a state. Connections never change - * their type, but can go through many state changes in their lifetime. - * - * Every connection has two associated input and output buffers. - * Listeners don't use them. For non-listener connections, incoming - * data is appended to conn->inbuf, and outgoing data is taken from - * conn->outbuf. Connections differ primarily in the functions called - * to fill and drain these buffers. - */ -typedef struct connection_t { - uint32_t magic; /**< For memory debugging: must equal one of - * *_CONNECTION_MAGIC. */ - - uint8_t state; /**< Current state of this connection. */ - unsigned int type:5; /**< What kind of connection is this? */ - unsigned int purpose:5; /**< Only used for DIR and EXIT types currently. */ - - /* The next fields are all one-bit booleans. Some are only applicable to - * connection subtypes, but we hold them here anyway, to save space. - */ - unsigned int read_blocked_on_bw:1; /**< Boolean: should we start reading - * again once the bandwidth throttler allows it? */ - unsigned int write_blocked_on_bw:1; /**< Boolean: should we start writing - * again once the bandwidth throttler allows - * writes? */ - unsigned int hold_open_until_flushed:1; /**< Despite this connection's being - * marked for close, do we flush it - * before closing it? */ - unsigned int inbuf_reached_eof:1; /**< Boolean: did read() return 0 on this - * conn? */ - /** Set to 1 when we're inside connection_flushed_some to keep us from - * calling connection_handle_write() recursively. */ - unsigned int in_flushed_some:1; - /** True if connection_handle_write is currently running on this connection. - */ - unsigned int in_connection_handle_write:1; - - /* For linked connections: - */ - unsigned int linked:1; /**< True if there is, or has been, a linked_conn. */ - /** True iff we'd like to be notified about read events from the - * linked conn. */ - unsigned int reading_from_linked_conn:1; - /** True iff we're willing to write to the linked conn. */ - unsigned int writing_to_linked_conn:1; - /** True iff we're currently able to read on the linked conn, and our - * read_event should be made active with libevent. */ - unsigned int active_on_link:1; - /** True iff we've called connection_close_immediate() on this linked - * connection. */ - unsigned int linked_conn_is_closed:1; - - /** CONNECT/SOCKS proxy client handshake state (for outgoing connections). */ - unsigned int proxy_state:4; - - /** Our socket; set to TOR_INVALID_SOCKET if this connection is closed, - * or has no socket. */ - tor_socket_t s; - int conn_array_index; /**< Index into the global connection array. */ - - struct event *read_event; /**< Libevent event structure. */ - struct event *write_event; /**< Libevent event structure. */ - struct buf_t *inbuf; /**< Buffer holding data read over this connection. */ - struct buf_t *outbuf; /**< Buffer holding data to write over this - * connection. */ - size_t outbuf_flushlen; /**< How much data should we try to flush from the - * outbuf? */ - time_t timestamp_last_read_allowed; /**< When was the last time libevent said - * we could read? */ - time_t timestamp_last_write_allowed; /**< When was the last time libevent - * said we could write? */ - - time_t timestamp_created; /**< When was this connection_t created? */ - - int socket_family; /**< Address family of this connection's socket. Usually - * AF_INET, but it can also be AF_UNIX, or AF_INET6 */ - tor_addr_t addr; /**< IP that socket "s" is directly connected to; - * may be the IP address for a proxy or pluggable transport, - * see "address" for the address of the final destination. - */ - uint16_t port; /**< If non-zero, port that socket "s" is directly connected - * to; may be the port for a proxy or pluggable transport, - * see "address" for the port at the final destination. */ - uint16_t marked_for_close; /**< Should we close this conn on the next - * iteration of the main loop? (If true, holds - * the line number where this connection was - * marked.) */ - const char *marked_for_close_file; /**< For debugging: in which file were - * we marked for close? */ - char *address; /**< FQDN (or IP) and port of the final destination for this - * connection; this is always the remote address, it is - * passed to a proxy or pluggable transport if one in use. - * See "addr" and "port" for the address that socket "s" is - * directly connected to. - * strdup into this, because free_connection() frees it. */ - /** Another connection that's connected to this one in lieu of a socket. */ - struct connection_t *linked_conn; - - /** Unique identifier for this connection on this Tor instance. */ - uint64_t global_identifier; - - /** Bytes read since last call to control_event_conn_bandwidth_used(). - * Only used if we're configured to emit CONN_BW events. */ - uint32_t n_read_conn_bw; - - /** Bytes written since last call to control_event_conn_bandwidth_used(). - * Only used if we're configured to emit CONN_BW events. */ - uint32_t n_written_conn_bw; -} connection_t; - -/** Subtype of connection_t; used for a listener socket. */ -typedef struct listener_connection_t { - connection_t base_; - - /** If the connection is a CONN_TYPE_AP_DNS_LISTENER, this field points - * to the evdns_server_port it uses to listen to and answer connections. */ - struct evdns_server_port *dns_server_port; - - entry_port_cfg_t entry_cfg; - -} listener_connection_t; - -/** Minimum length of the random part of an AUTH_CHALLENGE cell. */ -#define OR_AUTH_CHALLENGE_LEN 32 - -/** - * @name Certificate types for CERTS cells. - * - * These values are defined by the protocol, and affect how an X509 - * certificate in a CERTS cell is interpreted and used. - * - * @{ */ -/** A certificate that authenticates a TLS link key. The subject key - * must match the key used in the TLS handshake; it must be signed by - * the identity key. */ -#define OR_CERT_TYPE_TLS_LINK 1 -/** A self-signed identity certificate. The subject key must be a - * 1024-bit RSA key. */ -#define OR_CERT_TYPE_ID_1024 2 -/** A certificate that authenticates a key used in an AUTHENTICATE cell - * in the v3 handshake. The subject key must be a 1024-bit RSA key; it - * must be signed by the identity key */ -#define OR_CERT_TYPE_AUTH_1024 3 -/* DOCDOC */ -#define OR_CERT_TYPE_RSA_ED_CROSSCERT 7 -/**@}*/ - -/** The first supported type of AUTHENTICATE cell. It contains - * a bunch of structures signed with an RSA1024 key. The signed - * structures include a HMAC using negotiated TLS secrets, and a digest - * of all cells sent or received before the AUTHENTICATE cell (including - * the random server-generated AUTH_CHALLENGE cell). - */ -#define AUTHTYPE_RSA_SHA256_TLSSECRET 1 -/** As AUTHTYPE_RSA_SHA256_TLSSECRET, but instead of using the - * negotiated TLS secrets, uses exported keying material from the TLS - * session as described in RFC 5705. - * - * Not used by today's tors, since everything that supports this - * also supports ED25519_SHA256_5705, which is better. - **/ -#define AUTHTYPE_RSA_SHA256_RFC5705 2 -/** As AUTHTYPE_RSA_SHA256_RFC5705, but uses an Ed25519 identity key to - * authenticate. */ -#define AUTHTYPE_ED25519_SHA256_RFC5705 3 -/* - * NOTE: authchallenge_type_is_better() relies on these AUTHTYPE codes - * being sorted in order of preference. If we someday add one with - * a higher numerical value that we don't like as much, we should revise - * authchallenge_type_is_better(). - */ - -/** The length of the part of the AUTHENTICATE cell body that the client and - * server can generate independently (when using RSA_SHA256_TLSSECRET). It - * contains everything except the client's timestamp, the client's randomly - * generated nonce, and the signature. */ -#define V3_AUTH_FIXED_PART_LEN (8+(32*6)) -/** The length of the part of the AUTHENTICATE cell body that the client - * signs. */ -#define V3_AUTH_BODY_LEN (V3_AUTH_FIXED_PART_LEN + 8 + 16) - -/** Structure to hold all the certificates we've received on an OR connection - */ -typedef struct or_handshake_certs_t { - /** True iff we originated this connection. */ - int started_here; - /** The cert for the 'auth' RSA key that's supposed to sign the AUTHENTICATE - * cell. Signed with the RSA identity key. */ - tor_x509_cert_t *auth_cert; - /** The cert for the 'link' RSA key that was used to negotiate the TLS - * connection. Signed with the RSA identity key. */ - tor_x509_cert_t *link_cert; - /** A self-signed identity certificate: the RSA identity key signed - * with itself. */ - tor_x509_cert_t *id_cert; - /** The Ed25519 signing key, signed with the Ed25519 identity key. */ - struct tor_cert_st *ed_id_sign; - /** A digest of the X509 link certificate for the TLS connection, signed - * with the Ed25519 siging key. */ - struct tor_cert_st *ed_sign_link; - /** The Ed25519 authentication key (that's supposed to sign an AUTHENTICATE - * cell) , signed with the Ed25519 siging key. */ - struct tor_cert_st *ed_sign_auth; - /** The Ed25519 identity key, crosssigned with the RSA identity key. */ - uint8_t *ed_rsa_crosscert; - /** The length of <b>ed_rsa_crosscert</b> in bytes */ - size_t ed_rsa_crosscert_len; -} or_handshake_certs_t; - -/** Stores flags and information related to the portion of a v2/v3 Tor OR - * connection handshake that happens after the TLS handshake is finished. - */ -typedef struct or_handshake_state_t { - /** When was the VERSIONS cell sent on this connection? Used to get - * an estimate of the skew in the returning NETINFO reply. */ - time_t sent_versions_at; - /** True iff we originated this connection */ - unsigned int started_here : 1; - /** True iff we have received and processed a VERSIONS cell. */ - unsigned int received_versions : 1; - /** True iff we have received and processed an AUTH_CHALLENGE cell */ - unsigned int received_auth_challenge : 1; - /** True iff we have received and processed a CERTS cell. */ - unsigned int received_certs_cell : 1; - /** True iff we have received and processed an AUTHENTICATE cell */ - unsigned int received_authenticate : 1; - - /* True iff we've received valid authentication to some identity. */ - unsigned int authenticated : 1; - unsigned int authenticated_rsa : 1; - unsigned int authenticated_ed25519 : 1; - - /* True iff we have sent a netinfo cell */ - unsigned int sent_netinfo : 1; - - /** The signing->ed25519 link certificate corresponding to the x509 - * certificate we used on the TLS connection (if this is a server-side - * connection). We make a copy of this here to prevent a race condition - * caused by TLS context rotation. */ - struct tor_cert_st *own_link_cert; - - /** True iff we should feed outgoing cells into digest_sent and - * digest_received respectively. - * - * From the server's side of the v3 handshake, we want to capture everything - * from the VERSIONS cell through and including the AUTH_CHALLENGE cell. - * From the client's, we want to capture everything from the VERSIONS cell - * through but *not* including the AUTHENTICATE cell. - * - * @{ */ - unsigned int digest_sent_data : 1; - unsigned int digest_received_data : 1; - /**@}*/ - - /** Identity RSA digest that we have received and authenticated for our peer - * on this connection. */ - uint8_t authenticated_rsa_peer_id[DIGEST_LEN]; - /** Identity Ed25519 public key that we have received and authenticated for - * our peer on this connection. */ - ed25519_public_key_t authenticated_ed25519_peer_id; - - /** Digests of the cells that we have sent or received as part of a V3 - * handshake. Used for making and checking AUTHENTICATE cells. - * - * @{ - */ - crypto_digest_t *digest_sent; - crypto_digest_t *digest_received; - /** @} */ - - /** Certificates that a connection initiator sent us in a CERTS cell; we're - * holding on to them until we get an AUTHENTICATE cell. - */ - or_handshake_certs_t *certs; -} or_handshake_state_t; - -/** Length of Extended ORPort connection identifier. */ -#define EXT_OR_CONN_ID_LEN DIGEST_LEN /* 20 */ -/* - * OR_CONN_HIGHWATER and OR_CONN_LOWWATER moved from connection_or.c so - * channeltls.c can see them too. - */ - -/** When adding cells to an OR connection's outbuf, keep adding until the - * outbuf is at least this long, or we run out of cells. */ -#define OR_CONN_HIGHWATER (32*1024) - -/** Add cells to an OR connection's outbuf whenever the outbuf's data length - * drops below this size. */ -#define OR_CONN_LOWWATER (16*1024) - -/** Subtype of connection_t for an "OR connection" -- that is, one that speaks - * cells over TLS. */ -typedef struct or_connection_t { - connection_t base_; - - /** Hash of the public RSA key for the other side's identity key, or zeroes - * if the other side hasn't shown us a valid identity key. */ - char identity_digest[DIGEST_LEN]; - - /** Extended ORPort connection identifier. */ - char *ext_or_conn_id; - /** This is the ClientHash value we expect to receive from the - * client during the Extended ORPort authentication protocol. We - * compute it upon receiving the ClientNoce from the client, and we - * compare it with the acual ClientHash value sent by the - * client. */ - char *ext_or_auth_correct_client_hash; - /** String carrying the name of the pluggable transport - * (e.g. "obfs2") that is obfuscating this connection. If no - * pluggable transports are used, it's NULL. */ - char *ext_or_transport; - - char *nickname; /**< Nickname of OR on other side (if any). */ - - tor_tls_t *tls; /**< TLS connection state. */ - int tls_error; /**< Last tor_tls error code. */ - /** When we last used this conn for any client traffic. If not - * recent, we can rate limit it further. */ - - /* Channel using this connection */ - channel_tls_t *chan; - - tor_addr_t real_addr; /**< The actual address that this connection came from - * or went to. The <b>addr</b> field is prone to - * getting overridden by the address from the router - * descriptor matching <b>identity_digest</b>. */ - - /** Should this connection be used for extending circuits to the server - * matching the <b>identity_digest</b> field? Set to true if we're pretty - * sure we aren't getting MITMed, either because we're connected to an - * address listed in a server descriptor, or because an authenticated - * NETINFO cell listed the address we're connected to as recognized. */ - unsigned int is_canonical:1; - - /** True iff this is an outgoing connection. */ - unsigned int is_outgoing:1; - unsigned int proxy_type:2; /**< One of PROXY_NONE...PROXY_SOCKS5 */ - unsigned int wide_circ_ids:1; - /** True iff this connection has had its bootstrap failure logged with - * control_event_bootstrap_problem. */ - unsigned int have_noted_bootstrap_problem:1; - /** True iff this is a client connection and its address has been put in the - * geoip cache and handled by the DoS mitigation subsystem. We use this to - * insure we have a coherent count of concurrent connection. */ - unsigned int tracked_for_dos_mitigation : 1; - - uint16_t link_proto; /**< What protocol version are we using? 0 for - * "none negotiated yet." */ - uint16_t idle_timeout; /**< How long can this connection sit with no - * circuits on it before we close it? Based on - * IDLE_CIRCUIT_TIMEOUT_{NON,}CANONICAL and - * on is_canonical, randomized. */ - or_handshake_state_t *handshake_state; /**< If we are setting this connection - * up, state information to do so. */ - - time_t timestamp_lastempty; /**< When was the outbuf last completely empty?*/ - - token_bucket_rw_t bucket; /**< Used for rate limiting when the connection is - * in state CONN_OPEN. */ - - /* - * Count the number of bytes flushed out on this orconn, and the number of - * bytes TLS actually sent - used for overhead estimation for scheduling. - */ - uint64_t bytes_xmitted, bytes_xmitted_by_tls; -} or_connection_t; - -/** Subtype of connection_t for an "edge connection" -- that is, an entry (ap) - * connection, or an exit. */ -typedef struct edge_connection_t { - connection_t base_; - - struct edge_connection_t *next_stream; /**< Points to the next stream at this - * edge, if any */ - int package_window; /**< How many more relay cells can I send into the - * circuit? */ - int deliver_window; /**< How many more relay cells can end at me? */ - - struct circuit_t *on_circuit; /**< The circuit (if any) that this edge - * connection is using. */ - - /** A pointer to which node in the circ this conn exits at. Set for AP - * connections and for hidden service exit connections. */ - struct crypt_path_t *cpath_layer; - /** What rendezvous service are we querying for (if an AP) or providing (if - * an exit)? */ - rend_data_t *rend_data; - - /* Hidden service connection identifier for edge connections. Used by the HS - * client-side code to identify client SOCKS connections and by the - * service-side code to match HS circuits with their streams. */ - struct hs_ident_edge_conn_t *hs_ident; - - uint32_t address_ttl; /**< TTL for address-to-addr mapping on exit - * connection. Exit connections only. */ - uint32_t begincell_flags; /** Flags sent or received in the BEGIN cell - * for this connection */ - - streamid_t stream_id; /**< The stream ID used for this edge connection on its - * circuit */ - - /** The reason why this connection is closing; passed to the controller. */ - uint16_t end_reason; - - /** Bytes read since last call to control_event_stream_bandwidth_used() */ - uint32_t n_read; - - /** Bytes written since last call to control_event_stream_bandwidth_used() */ - uint32_t n_written; - - /** True iff this connection is for a DNS request only. */ - unsigned int is_dns_request:1; - /** True iff this connection is for a PTR DNS request. (exit only) */ - unsigned int is_reverse_dns_lookup:1; - - unsigned int edge_has_sent_end:1; /**< For debugging; only used on edge - * connections. Set once we've set the stream end, - * and check in connection_about_to_close_connection(). - */ - /** True iff we've blocked reading until the circuit has fewer queued - * cells. */ - unsigned int edge_blocked_on_circ:1; - - /** Unique ID for directory requests; this used to be in connection_t, but - * that's going away and being used on channels instead. We still tag - * edge connections with dirreq_id from circuits, so it's copied here. */ - uint64_t dirreq_id; -} edge_connection_t; - -/** Subtype of edge_connection_t for an "entry connection" -- that is, a SOCKS - * connection, a DNS request, a TransPort connection or a NATD connection */ -typedef struct entry_connection_t { - edge_connection_t edge_; - - /** Nickname of planned exit node -- used with .exit support. */ - /* XXX prop220: we need to make chosen_exit_name able to encode Ed IDs too. - * That's logically part of the UI parts for prop220 though. */ - char *chosen_exit_name; - - socks_request_t *socks_request; /**< SOCKS structure describing request (AP - * only.) */ - - /* === Isolation related, AP only. === */ - entry_port_cfg_t entry_cfg; - /** AP only: The newnym epoch in which we created this connection. */ - unsigned nym_epoch; - - /** AP only: The original requested address before we rewrote it. */ - char *original_dest_address; - /* Other fields to isolate on already exist. The ClientAddr is addr. The - ClientProtocol is a combination of type and socks_request-> - socks_version. SocksAuth is socks_request->username/password. - DestAddr is in socks_request->address. */ - - /** Number of times we've reassigned this application connection to - * a new circuit. We keep track because the timeout is longer if we've - * already retried several times. */ - uint8_t num_socks_retries; - - /** For AP connections only: buffer for data that we have sent - * optimistically, which we might need to re-send if we have to - * retry this connection. */ - struct buf_t *pending_optimistic_data; - /* For AP connections only: buffer for data that we previously sent - * optimistically which we are currently re-sending as we retry this - * connection. */ - struct buf_t *sending_optimistic_data; - - /** If this is a DNSPort connection, this field holds the pending DNS - * request that we're going to try to answer. */ - struct evdns_server_request *dns_server_request; - -#define DEBUGGING_17659 - -#ifdef DEBUGGING_17659 - uint16_t marked_pending_circ_line; - const char *marked_pending_circ_file; -#endif - -#define NUM_CIRCUITS_LAUNCHED_THRESHOLD 10 - /** Number of times we've launched a circuit to handle this stream. If - * it gets too high, that could indicate an inconsistency between our - * "launch a circuit to handle this stream" logic and our "attach our - * stream to one of the available circuits" logic. */ - unsigned int num_circuits_launched:4; - - /** True iff this stream must attach to a one-hop circuit (e.g. for - * begin_dir). */ - unsigned int want_onehop:1; - /** True iff this stream should use a BEGIN_DIR relay command to establish - * itself rather than BEGIN (either via onehop or via a whole circuit). */ - unsigned int use_begindir:1; - - /** For AP connections only. If 1, and we fail to reach the chosen exit, - * stop requiring it. */ - unsigned int chosen_exit_optional:1; - /** For AP connections only. If non-zero, this exit node was picked as - * a result of the TrackHostExit, and the value decrements every time - * we fail to complete a circuit to our chosen exit -- if it reaches - * zero, abandon the associated mapaddress. */ - unsigned int chosen_exit_retries:3; - - /** True iff this is an AP connection that came from a transparent or - * NATd connection */ - unsigned int is_transparent_ap:1; - - /** For AP connections only: Set if this connection's target exit node - * allows optimistic data (that is, data sent on this stream before - * the exit has sent a CONNECTED cell) and we have chosen to use it. - */ - unsigned int may_use_optimistic_data : 1; -} entry_connection_t; - -/** Subtype of connection_t for an "directory connection" -- that is, an HTTP - * connection to retrieve or serve directory material. */ -typedef struct dir_connection_t { - connection_t base_; - - /** Which 'resource' did we ask the directory for? This is typically the part - * of the URL string that defines, relative to the directory conn purpose, - * what thing we want. For example, in router descriptor downloads by - * descriptor digest, it contains "d/", then one or more +-separated - * fingerprints. - **/ - char *requested_resource; - unsigned int dirconn_direct:1; /**< Is this dirconn direct, or via Tor? */ - - /** If we're fetching descriptors, what router purpose shall we assign - * to them? */ - uint8_t router_purpose; - - /** List of spooled_resource_t for objects that we're spooling. We use - * it from back to front. */ - smartlist_t *spool; - /** The compression object doing on-the-fly compression for spooled data. */ - tor_compress_state_t *compress_state; - - /** What rendezvous service are we querying for? */ - rend_data_t *rend_data; - - /* Hidden service connection identifier for dir connections: Used by HS - client-side code to fetch HS descriptors, and by the service-side code to - upload descriptors. */ - struct hs_ident_dir_conn_t *hs_ident; - - /** If this is a one-hop connection, tracks the state of the directory guard - * for this connection (if any). */ - struct circuit_guard_state_t *guard_state; - - char identity_digest[DIGEST_LEN]; /**< Hash of the public RSA key for - * the directory server's signing key. */ - - /** Unique ID for directory requests; this used to be in connection_t, but - * that's going away and being used on channels instead. The dirserver still - * needs this for the incoming side, so it's moved here. */ - uint64_t dirreq_id; - -#ifdef MEASUREMENTS_21206 - /** Number of RELAY_DATA cells received. */ - uint32_t data_cells_received; - - /** Number of RELAY_DATA cells sent. */ - uint32_t data_cells_sent; -#endif /* defined(MEASUREMENTS_21206) */ -} dir_connection_t; - -/** Subtype of connection_t for an connection to a controller. */ -typedef struct control_connection_t { - connection_t base_; - - uint64_t event_mask; /**< Bitfield: which events does this controller - * care about? - * EVENT_MAX_ is >31, so we need a 64 bit mask */ - - /** True if we have sent a protocolinfo reply on this connection. */ - unsigned int have_sent_protocolinfo:1; - /** True if we have received a takeownership command on this - * connection. */ - unsigned int is_owning_control_connection:1; - - /** List of ephemeral onion services belonging to this connection. */ - smartlist_t *ephemeral_onion_services; - - /** If we have sent an AUTHCHALLENGE reply on this connection and - * have not received a successful AUTHENTICATE command, points to - * the value which the client must send to authenticate itself; - * otherwise, NULL. */ - char *safecookie_client_hash; - - /** Amount of space allocated in incoming_cmd. */ - uint32_t incoming_cmd_len; - /** Number of bytes currently stored in incoming_cmd. */ - uint32_t incoming_cmd_cur_len; - /** A control command that we're reading from the inbuf, but which has not - * yet arrived completely. */ - char *incoming_cmd; -} control_connection_t; - -/** Cast a connection_t subtype pointer to a connection_t **/ -#define TO_CONN(c) (&(((c)->base_))) - -/** Cast a entry_connection_t subtype pointer to a edge_connection_t **/ -#define ENTRY_TO_EDGE_CONN(c) (&(((c))->edge_)) -/** Cast a entry_connection_t subtype pointer to a connection_t **/ -#define ENTRY_TO_CONN(c) (TO_CONN(ENTRY_TO_EDGE_CONN(c))) - -/** Convert a connection_t* to an or_connection_t*; assert if the cast is - * invalid. */ -static or_connection_t *TO_OR_CONN(connection_t *); -/** Convert a connection_t* to a dir_connection_t*; assert if the cast is - * invalid. */ -static dir_connection_t *TO_DIR_CONN(connection_t *); -/** Convert a connection_t* to an edge_connection_t*; assert if the cast is - * invalid. */ -static edge_connection_t *TO_EDGE_CONN(connection_t *); -/** Convert a connection_t* to an entry_connection_t*; assert if the cast is - * invalid. */ -static entry_connection_t *TO_ENTRY_CONN(connection_t *); -/** Convert a edge_connection_t* to an entry_connection_t*; assert if the cast - * is invalid. */ -static entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *); -/** Convert a connection_t* to an control_connection_t*; assert if the cast is - * invalid. */ -static control_connection_t *TO_CONTROL_CONN(connection_t *); -/** Convert a connection_t* to an listener_connection_t*; assert if the cast is - * invalid. */ -static listener_connection_t *TO_LISTENER_CONN(connection_t *); - -static inline or_connection_t *TO_OR_CONN(connection_t *c) -{ - tor_assert(c->magic == OR_CONNECTION_MAGIC); - return DOWNCAST(or_connection_t, c); -} -static inline dir_connection_t *TO_DIR_CONN(connection_t *c) -{ - tor_assert(c->magic == DIR_CONNECTION_MAGIC); - return DOWNCAST(dir_connection_t, c); -} -static inline edge_connection_t *TO_EDGE_CONN(connection_t *c) -{ - tor_assert(c->magic == EDGE_CONNECTION_MAGIC || - c->magic == ENTRY_CONNECTION_MAGIC); - return DOWNCAST(edge_connection_t, c); -} -static inline entry_connection_t *TO_ENTRY_CONN(connection_t *c) -{ - tor_assert(c->magic == ENTRY_CONNECTION_MAGIC); - return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_.base_); -} -static inline entry_connection_t *EDGE_TO_ENTRY_CONN(edge_connection_t *c) -{ - tor_assert(c->base_.magic == ENTRY_CONNECTION_MAGIC); - return (entry_connection_t*) SUBTYPE_P(c, entry_connection_t, edge_); -} -static inline control_connection_t *TO_CONTROL_CONN(connection_t *c) -{ - tor_assert(c->magic == CONTROL_CONNECTION_MAGIC); - return DOWNCAST(control_connection_t, c); -} -static inline listener_connection_t *TO_LISTENER_CONN(connection_t *c) -{ - tor_assert(c->magic == LISTENER_CONNECTION_MAGIC); - return DOWNCAST(listener_connection_t, c); -} - -/** What action type does an address policy indicate: accept or reject? */ -typedef enum { - ADDR_POLICY_ACCEPT=1, - ADDR_POLICY_REJECT=2, -} addr_policy_action_t; -#define addr_policy_action_bitfield_t ENUM_BF(addr_policy_action_t) - -/** A reference-counted address policy rule. */ -typedef struct addr_policy_t { - int refcnt; /**< Reference count */ - /** What to do when the policy matches.*/ - addr_policy_action_bitfield_t policy_type:2; - unsigned int is_private:1; /**< True iff this is the pseudo-address, - * "private". */ - unsigned int is_canonical:1; /**< True iff this policy is the canonical - * copy (stored in a hash table to avoid - * duplication of common policies) */ - maskbits_t maskbits; /**< Accept/reject all addresses <b>a</b> such that the - * first <b>maskbits</b> bits of <b>a</b> match - * <b>addr</b>. */ - /** Base address to accept or reject. - * - * Note that wildcards are treated - * differntly depending on address family. An AF_UNSPEC address means - * "All addresses, IPv4 or IPv6." An AF_INET address with maskbits==0 means - * "All IPv4 addresses" and an AF_INET6 address with maskbits == 0 means - * "All IPv6 addresses". - **/ - tor_addr_t addr; - uint16_t prt_min; /**< Lowest port number to accept/reject. */ - uint16_t prt_max; /**< Highest port number to accept/reject. */ -} addr_policy_t; - -/** A cached_dir_t represents a cacheable directory object, along with its - * compressed form. */ -typedef struct cached_dir_t { - char *dir; /**< Contents of this object, NUL-terminated. */ - char *dir_compressed; /**< Compressed contents of this object. */ - size_t dir_len; /**< Length of <b>dir</b> (not counting its NUL). */ - size_t dir_compressed_len; /**< Length of <b>dir_compressed</b>. */ - time_t published; /**< When was this object published. */ - common_digests_t digests; /**< Digests of this object (networkstatus only) */ - /** Sha3 digest (also ns only) */ - uint8_t digest_sha3_as_signed[DIGEST256_LEN]; - int refcnt; /**< Reference count for this cached_dir_t. */ -} cached_dir_t; - -/** Enum used to remember where a signed_descriptor_t is stored and how to - * manage the memory for signed_descriptor_body. */ -typedef enum { - /** The descriptor isn't stored on disk at all: the copy in memory is - * canonical; the saved_offset field is meaningless. */ - SAVED_NOWHERE=0, - /** The descriptor is stored in the cached_routers file: the - * signed_descriptor_body is meaningless; the signed_descriptor_len and - * saved_offset are used to index into the mmaped cache file. */ - SAVED_IN_CACHE, - /** The descriptor is stored in the cached_routers.new file: the - * signed_descriptor_body and saved_offset fields are both set. */ - /* FFFF (We could also mmap the file and grow the mmap as needed, or - * lazy-load the descriptor text by using seek and read. We don't, for - * now.) - */ - SAVED_IN_JOURNAL -} saved_location_t; -#define saved_location_bitfield_t ENUM_BF(saved_location_t) - -/** Enumeration: what directory object is being downloaded? - * This determines which schedule is selected to perform the download. */ -typedef enum { - DL_SCHED_GENERIC = 0, - DL_SCHED_CONSENSUS = 1, - DL_SCHED_BRIDGE = 2, -} download_schedule_t; -#define download_schedule_bitfield_t ENUM_BF(download_schedule_t) - -/** Enumeration: is the download schedule for downloading from an authority, - * or from any available directory mirror? - * During bootstrap, "any" means a fallback (or an authority, if there - * are no fallbacks). - * When we have a valid consensus, "any" means any directory server. */ -typedef enum { - DL_WANT_ANY_DIRSERVER = 0, - DL_WANT_AUTHORITY = 1, -} download_want_authority_t; -#define download_want_authority_bitfield_t \ - ENUM_BF(download_want_authority_t) - -/** Enumeration: do we want to increment the schedule position each time a - * connection is attempted (these attempts can be concurrent), or do we want - * to increment the schedule position after a connection fails? */ -typedef enum { - DL_SCHED_INCREMENT_FAILURE = 0, - DL_SCHED_INCREMENT_ATTEMPT = 1, -} download_schedule_increment_t; -#define download_schedule_increment_bitfield_t \ - ENUM_BF(download_schedule_increment_t) - -/** Information about our plans for retrying downloads for a downloadable - * directory object. - * Each type of downloadable directory object has a corresponding retry - * <b>schedule</b>, which can be different depending on whether the object is - * being downloaded from an authority or a mirror (<b>want_authority</b>). - * <b>next_attempt_at</b> contains the next time we will attempt to download - * the object. - * For schedules that <b>increment_on</b> failure, <b>n_download_failures</b> - * is used to determine the position in the schedule. (Each schedule is a - * smartlist of integer delays, parsed from a CSV option.) Every time a - * connection attempt fails, <b>n_download_failures</b> is incremented, - * the new delay value is looked up from the schedule, and - * <b>next_attempt_at</b> is set delay seconds from the time the previous - * connection failed. Therefore, at most one failure-based connection can be - * in progress for each download_status_t. - * For schedules that <b>increment_on</b> attempt, <b>n_download_attempts</b> - * is used to determine the position in the schedule. Every time a - * connection attempt is made, <b>n_download_attempts</b> is incremented, - * the new delay value is looked up from the schedule, and - * <b>next_attempt_at</b> is set delay seconds from the time the previous - * connection was attempted. Therefore, multiple concurrent attempted-based - * connections can be in progress for each download_status_t. - * After an object is successfully downloaded, any other concurrent connections - * are terminated. A new schedule which starts at position 0 is used for - * subsequent downloads of the same object. - */ -typedef struct download_status_t { - time_t next_attempt_at; /**< When should we try downloading this object - * again? */ - uint8_t n_download_failures; /**< Number of failed downloads of the most - * recent object, since the last success. */ - uint8_t n_download_attempts; /**< Number of (potentially concurrent) attempts - * to download the most recent object, since - * the last success. */ - download_schedule_bitfield_t schedule : 8; /**< What kind of object is being - * downloaded? This determines the - * schedule used for the download. - */ - download_want_authority_bitfield_t want_authority : 1; /**< Is the download - * happening from an authority - * or a mirror? This determines - * the schedule used for the - * download. */ - download_schedule_increment_bitfield_t increment_on : 1; /**< does this - * schedule increment on each attempt, - * or after each failure? */ - uint8_t last_backoff_position; /**< number of attempts/failures, depending - * on increment_on, when we last recalculated - * the delay. Only updated if backoff - * == 1. */ - int last_delay_used; /**< last delay used for random exponential backoff; - * only updated if backoff == 1 */ -} download_status_t; - -/** If n_download_failures is this high, the download can never happen. */ -#define IMPOSSIBLE_TO_DOWNLOAD 255 - -/** The max size we expect router descriptor annotations we create to - * be. We'll accept larger ones if we see them on disk, but we won't - * create any that are larger than this. */ -#define ROUTER_ANNOTATION_BUF_LEN 256 - -/** Information need to cache an onion router's descriptor. */ -typedef struct signed_descriptor_t { - /** Pointer to the raw server descriptor, preceded by annotations. Not - * necessarily NUL-terminated. If saved_location is SAVED_IN_CACHE, this - * pointer is null. */ - char *signed_descriptor_body; - /** Length of the annotations preceding the server descriptor. */ - size_t annotations_len; - /** Length of the server descriptor. */ - size_t signed_descriptor_len; - /** Digest of the server descriptor, computed as specified in - * dir-spec.txt. */ - char signed_descriptor_digest[DIGEST_LEN]; - /** Identity digest of the router. */ - char identity_digest[DIGEST_LEN]; - /** Declared publication time of the descriptor. */ - time_t published_on; - /** For routerdescs only: digest of the corresponding extrainfo. */ - char extra_info_digest[DIGEST_LEN]; - /** For routerdescs only: A SHA256-digest of the extrainfo (if any) */ - char extra_info_digest256[DIGEST256_LEN]; - /** Certificate for ed25519 signing key. */ - struct tor_cert_st *signing_key_cert; - /** For routerdescs only: Status of downloading the corresponding - * extrainfo. */ - download_status_t ei_dl_status; - /** Where is the descriptor saved? */ - saved_location_t saved_location; - /** If saved_location is SAVED_IN_CACHE or SAVED_IN_JOURNAL, the offset of - * this descriptor in the corresponding file. */ - off_t saved_offset; - /** What position is this descriptor within routerlist->routers or - * routerlist->old_routers? -1 for none. */ - int routerlist_index; - /** The valid-until time of the most recent consensus that listed this - * descriptor. 0 for "never listed in a consensus, so far as we know." */ - time_t last_listed_as_valid_until; - /* If true, we do not ever try to save this object in the cache. */ - unsigned int do_not_cache : 1; - /* If true, this item is meant to represent an extrainfo. */ - unsigned int is_extrainfo : 1; - /* If true, we got an extrainfo for this item, and the digest was right, - * but it was incompatible. */ - unsigned int extrainfo_is_bogus : 1; - /* If true, we are willing to transmit this item unencrypted. */ - unsigned int send_unencrypted : 1; -} signed_descriptor_t; - -/** A signed integer representing a country code. */ -typedef int16_t country_t; - -/** Flags used to summarize the declared protocol versions of a relay, - * so we don't need to parse them again and again. */ -typedef struct protover_summary_flags_t { - /** True iff we have a proto line for this router, or a versions line - * from which we could infer the protocols. */ - unsigned int protocols_known:1; - - /** True iff this router has a version or protocol list that allows it to - * accept EXTEND2 cells. This requires Relay=2. */ - unsigned int supports_extend2_cells:1; - - /** True iff this router has a protocol list that allows it to negotiate - * ed25519 identity keys on a link handshake with us. This - * requires LinkAuth=3. */ - unsigned int supports_ed25519_link_handshake_compat:1; - - /** True iff this router has a protocol list that allows it to negotiate - * ed25519 identity keys on a link handshake, at all. This requires some - * LinkAuth=X for X >= 3. */ - unsigned int supports_ed25519_link_handshake_any:1; - - /** True iff this router has a protocol list that allows it to be an - * introduction point supporting ed25519 authentication key which is part of - * the v3 protocol detailed in proposal 224. This requires HSIntro=4. */ - unsigned int supports_ed25519_hs_intro : 1; - - /** True iff this router has a protocol list that allows it to be an hidden - * service directory supporting version 3 as seen in proposal 224. This - * requires HSDir=2. */ - unsigned int supports_v3_hsdir : 1; - - /** True iff this router has a protocol list that allows it to be an hidden - * service rendezvous point supporting version 3 as seen in proposal 224. - * This requires HSRend=2. */ - unsigned int supports_v3_rendezvous_point: 1; -} protover_summary_flags_t; - -/** Information about another onion router in the network. */ -typedef struct { - signed_descriptor_t cache_info; - char *nickname; /**< Human-readable OR name. */ - - uint32_t addr; /**< IPv4 address of OR, in host order. */ - uint16_t or_port; /**< Port for TLS connections. */ - uint16_t dir_port; /**< Port for HTTP directory connections. */ - - /** A router's IPv6 address, if it has one. */ - /* XXXXX187 Actually these should probably be part of a list of addresses, - * not just a special case. Use abstractions to access these; don't do it - * directly. */ - tor_addr_t ipv6_addr; - uint16_t ipv6_orport; - - crypto_pk_t *onion_pkey; /**< Public RSA key for onions. */ - crypto_pk_t *identity_pkey; /**< Public RSA key for signing. */ - /** Public curve25519 key for onions */ - curve25519_public_key_t *onion_curve25519_pkey; - /** What's the earliest expiration time on all the certs in this - * routerinfo? */ - time_t cert_expiration_time; - - char *platform; /**< What software/operating system is this OR using? */ - - char *protocol_list; /**< Encoded list of subprotocol versions supported - * by this OR */ - - /* link info */ - uint32_t bandwidthrate; /**< How many bytes does this OR add to its token - * bucket per second? */ - uint32_t bandwidthburst; /**< How large is this OR's token bucket? */ - /** How many bytes/s is this router known to handle? */ - uint32_t bandwidthcapacity; - smartlist_t *exit_policy; /**< What streams will this OR permit - * to exit on IPv4? NULL for 'reject *:*'. */ - /** What streams will this OR permit to exit on IPv6? - * NULL for 'reject *:*' */ - struct short_policy_t *ipv6_exit_policy; - long uptime; /**< How many seconds the router claims to have been up */ - smartlist_t *declared_family; /**< Nicknames of router which this router - * claims are its family. */ - char *contact_info; /**< Declared contact info for this router. */ - unsigned int is_hibernating:1; /**< Whether the router claims to be - * hibernating */ - unsigned int caches_extra_info:1; /**< Whether the router says it caches and - * serves extrainfo documents. */ - unsigned int allow_single_hop_exits:1; /**< Whether the router says - * it allows single hop exits. */ - - unsigned int wants_to_be_hs_dir:1; /**< True iff this router claims to be - * a hidden service directory. */ - unsigned int policy_is_reject_star:1; /**< True iff the exit policy for this - * router rejects everything. */ - /** True if, after we have added this router, we should re-launch - * tests for it. */ - unsigned int needs_retest_if_added:1; - - /** True iff this router included "tunnelled-dir-server" in its descriptor, - * implying it accepts tunnelled directory requests, or it advertised - * dir_port > 0. */ - unsigned int supports_tunnelled_dir_requests:1; - - /** Used during voting to indicate that we should not include an entry for - * this routerinfo. Used only during voting. */ - unsigned int omit_from_vote:1; - - /** Flags to summarize the protocol versions for this routerinfo_t. */ - protover_summary_flags_t pv; - -/** Tor can use this router for general positions in circuits; we got it - * from a directory server as usual, or we're an authority and a server - * uploaded it. */ -#define ROUTER_PURPOSE_GENERAL 0 -/** Tor should avoid using this router for circuit-building: we got it - * from a controller. If the controller wants to use it, it'll have to - * ask for it by identity. */ -#define ROUTER_PURPOSE_CONTROLLER 1 -/** Tor should use this router only for bridge positions in circuits: we got - * it via a directory request from the bridge itself, or a bridge - * authority. */ -#define ROUTER_PURPOSE_BRIDGE 2 -/** Tor should not use this router; it was marked in cached-descriptors with - * a purpose we didn't recognize. */ -#define ROUTER_PURPOSE_UNKNOWN 255 - - /** In what way did we find out about this router? One of ROUTER_PURPOSE_*. - * Routers of different purposes are kept segregated and used for different - * things; see notes on ROUTER_PURPOSE_* macros above. - */ - uint8_t purpose; -} routerinfo_t; - -/** Information needed to keep and cache a signed extra-info document. */ -typedef struct extrainfo_t { - signed_descriptor_t cache_info; - /** SHA256 digest of this document */ - uint8_t digest256[DIGEST256_LEN]; - /** The router's nickname. */ - char nickname[MAX_NICKNAME_LEN+1]; - /** True iff we found the right key for this extra-info, verified the - * signature, and found it to be bad. */ - unsigned int bad_sig : 1; - /** If present, we didn't have the right key to verify this extra-info, - * so this is a copy of the signature in the document. */ - char *pending_sig; - /** Length of pending_sig. */ - size_t pending_sig_len; -} extrainfo_t; - -/** Contents of a single router entry in a network status object. - */ -typedef struct routerstatus_t { - time_t published_on; /**< When was this router published? */ - char nickname[MAX_NICKNAME_LEN+1]; /**< The nickname this router says it - * has. */ - char identity_digest[DIGEST_LEN]; /**< Digest of the router's identity - * key. */ - /** Digest of the router's most recent descriptor or microdescriptor. - * If it's a descriptor, we only use the first DIGEST_LEN bytes. */ - char descriptor_digest[DIGEST256_LEN]; - uint32_t addr; /**< IPv4 address for this router, in host order. */ - uint16_t or_port; /**< IPv4 OR port for this router. */ - uint16_t dir_port; /**< Directory port for this router. */ - tor_addr_t ipv6_addr; /**< IPv6 address for this router. */ - uint16_t ipv6_orport; /**< IPv6 OR port for this router. */ - unsigned int is_authority:1; /**< True iff this router is an authority. */ - unsigned int is_exit:1; /**< True iff this router is a good exit. */ - unsigned int is_stable:1; /**< True iff this router stays up a long time. */ - unsigned int is_fast:1; /**< True iff this router has good bandwidth. */ - /** True iff this router is called 'running' in the consensus. We give it - * this funny name so that we don't accidentally use this bit as a view of - * whether we think the router is *currently* running. If that's what you - * want to know, look at is_running in node_t. */ - unsigned int is_flagged_running:1; - unsigned int is_named:1; /**< True iff "nickname" belongs to this router. */ - unsigned int is_unnamed:1; /**< True iff "nickname" belongs to another - * router. */ - unsigned int is_valid:1; /**< True iff this router isn't invalid. */ - unsigned int is_possible_guard:1; /**< True iff this router would be a good - * choice as an entry guard. */ - unsigned int is_bad_exit:1; /**< True iff this node is a bad choice for - * an exit node. */ - unsigned int is_hs_dir:1; /**< True iff this router is a v2-or-later hidden - * service directory. */ - unsigned int is_v2_dir:1; /** True iff this router publishes an open DirPort - * or it claims to accept tunnelled dir requests. - */ - - unsigned int has_bandwidth:1; /**< The vote/consensus had bw info */ - unsigned int has_exitsummary:1; /**< The vote/consensus had exit summaries */ - unsigned int bw_is_unmeasured:1; /**< This is a consensus entry, with - * the Unmeasured flag set. */ - - /** Flags to summarize the protocol versions for this routerstatus_t. */ - protover_summary_flags_t pv; - - uint32_t bandwidth_kb; /**< Bandwidth (capacity) of the router as reported in - * the vote/consensus, in kilobytes/sec. */ - - /** The consensus has guardfraction information for this router. */ - unsigned int has_guardfraction:1; - /** The guardfraction value of this router. */ - uint32_t guardfraction_percentage; - - char *exitsummary; /**< exit policy summary - - * XXX weasel: this probably should not stay a string. */ - - /* ---- The fields below aren't derived from the networkstatus; they - * hold local information only. */ - - time_t last_dir_503_at; /**< When did this router last tell us that it - * was too busy to serve directory info? */ - download_status_t dl_status; - -} routerstatus_t; - -/** A single entry in a parsed policy summary, describing a range of ports. */ -typedef struct short_policy_entry_t { - uint16_t min_port, max_port; -} short_policy_entry_t; - -/** A short_poliy_t is the parsed version of a policy summary. */ -typedef struct short_policy_t { - /** True if the members of 'entries' are port ranges to accept; false if - * they are port ranges to reject */ - unsigned int is_accept : 1; - /** The actual number of values in 'entries'. */ - unsigned int n_entries : 31; - /** An array of 0 or more short_policy_entry_t values, each describing a - * range of ports that this policy accepts or rejects (depending on the - * value of is_accept). - */ - short_policy_entry_t entries[FLEXIBLE_ARRAY_MEMBER]; -} short_policy_t; - -/** A microdescriptor is the smallest amount of information needed to build a - * circuit through a router. They are generated by the directory authorities, - * using information from the uploaded routerinfo documents. They are not - * self-signed, but are rather authenticated by having their hash in a signed - * networkstatus document. */ -typedef struct microdesc_t { - /** Hashtable node, used to look up the microdesc by its digest. */ - HT_ENTRY(microdesc_t) node; - - /* Cache information */ - - /** When was this microdescriptor last listed in a consensus document? - * Once a microdesc has been unlisted long enough, we can drop it. - */ - time_t last_listed; - /** Where is this microdescriptor currently stored? */ - saved_location_bitfield_t saved_location : 3; - /** If true, do not attempt to cache this microdescriptor on disk. */ - unsigned int no_save : 1; - /** If true, this microdesc has an entry in the microdesc_map */ - unsigned int held_in_map : 1; - /** Reference count: how many node_ts have a reference to this microdesc? */ - unsigned int held_by_nodes; - - /** If saved_location == SAVED_IN_CACHE, this field holds the offset of the - * microdescriptor in the cache. */ - off_t off; - - /* The string containing the microdesc. */ - - /** A pointer to the encoded body of the microdescriptor. If the - * saved_location is SAVED_IN_CACHE, then the body is a pointer into an - * mmap'd region. Otherwise, it is a malloc'd string. The string might not - * be NUL-terminated; take the length from <b>bodylen</b>. */ - char *body; - /** The length of the microdescriptor in <b>body</b>. */ - size_t bodylen; - /** A SHA256-digest of the microdescriptor. */ - char digest[DIGEST256_LEN]; - - /* Fields in the microdescriptor. */ - - /** As routerinfo_t.onion_pkey */ - crypto_pk_t *onion_pkey; - /** As routerinfo_t.onion_curve25519_pkey */ - curve25519_public_key_t *onion_curve25519_pkey; - /** Ed25519 identity key, if included. */ - ed25519_public_key_t *ed25519_identity_pkey; - /** As routerinfo_t.ipv6_addr */ - tor_addr_t ipv6_addr; - /** As routerinfo_t.ipv6_orport */ - uint16_t ipv6_orport; - /** As routerinfo_t.family */ - smartlist_t *family; - /** IPv4 exit policy summary */ - short_policy_t *exit_policy; - /** IPv6 exit policy summary */ - short_policy_t *ipv6_exit_policy; - -} microdesc_t; - -/** A node_t represents a Tor router. - * - * Specifically, a node_t is a Tor router as we are using it: a router that - * we are considering for circuits, connections, and so on. A node_t is a - * thin wrapper around the routerstatus, routerinfo, and microdesc for a - * single router, and provides a consistent interface for all of them. - * - * Also, a node_t has mutable state. While a routerinfo, a routerstatus, - * and a microdesc have[*] only the information read from a router - * descriptor, a consensus entry, and a microdescriptor (respectively)... - * a node_t has flags based on *our own current opinion* of the node. - * - * [*] Actually, there is some leftover information in each that is mutable. - * We should try to excise that. - */ -typedef struct node_t { - /* Indexing information */ - - /** Used to look up the node_t by its identity digest. */ - HT_ENTRY(node_t) ht_ent; - /** Used to look up the node_t by its ed25519 identity digest. */ - HT_ENTRY(node_t) ed_ht_ent; - /** Position of the node within the list of nodes */ - int nodelist_idx; - - /** The identity digest of this node_t. No more than one node_t per - * identity may exist at a time. */ - char identity[DIGEST_LEN]; - - /** The ed25519 identity of this node_t. This field is nonzero iff we - * currently have an ed25519 identity for this node in either md or ri, - * _and_ this node has been inserted to the ed25519-to-node map in the - * nodelist. - */ - ed25519_public_key_t ed25519_id; - - microdesc_t *md; - routerinfo_t *ri; - routerstatus_t *rs; - - /* local info: copied from routerstatus, then possibly frobbed based - * on experience. Authorities set this stuff directly. Note that - * these reflect knowledge of the primary (IPv4) OR port only. */ - - unsigned int is_running:1; /**< As far as we know, is this OR currently - * running? */ - unsigned int is_valid:1; /**< Has a trusted dirserver validated this OR? - * (For Authdir: Have we validated this OR?) */ - unsigned int is_fast:1; /** Do we think this is a fast OR? */ - unsigned int is_stable:1; /** Do we think this is a stable OR? */ - unsigned int is_possible_guard:1; /**< Do we think this is an OK guard? */ - unsigned int is_exit:1; /**< Do we think this is an OK exit? */ - unsigned int is_bad_exit:1; /**< Do we think this exit is censored, borked, - * or otherwise nasty? */ - unsigned int is_hs_dir:1; /**< True iff this router is a hidden service - * directory according to the authorities. */ - - /* Local info: warning state. */ - - unsigned int name_lookup_warned:1; /**< Have we warned the user for referring - * to this (unnamed) router by nickname? - */ - - /** Local info: we treat this node as if it rejects everything */ - unsigned int rejects_all:1; - - /* Local info: derived. */ - - /** True if the IPv6 OR port is preferred over the IPv4 OR port. - * XX/teor - can this become out of date if the torrc changes? */ - unsigned int ipv6_preferred:1; - - /** According to the geoip db what country is this router in? */ - /* XXXprop186 what is this suppose to mean with multiple OR ports? */ - country_t country; - - /* The below items are used only by authdirservers for - * reachability testing. */ - - /** When was the last time we could reach this OR? */ - time_t last_reachable; /* IPv4. */ - time_t last_reachable6; /* IPv6. */ - - /* Hidden service directory index data. This is used by a service or client - * in order to know what's the hs directory index for this node at the time - * the consensus is set. */ - struct hsdir_index_t hsdir_index; -} node_t; - -/** Linked list of microdesc hash lines for a single router in a directory - * vote. - */ -typedef struct vote_microdesc_hash_t { - /** Next element in the list, or NULL. */ - struct vote_microdesc_hash_t *next; - /** The raw contents of the microdesc hash line, from the "m" through the - * newline. */ - char *microdesc_hash_line; -} vote_microdesc_hash_t; - -/** The claim about a single router, made in a vote. */ -typedef struct vote_routerstatus_t { - routerstatus_t status; /**< Underlying 'status' object for this router. - * Flags are redundant. */ - /** How many known-flags are allowed in a vote? This is the width of - * the flags field of vote_routerstatus_t */ -#define MAX_KNOWN_FLAGS_IN_VOTE 64 - uint64_t flags; /**< Bit-field for all recognized flags; index into - * networkstatus_t.known_flags. */ - char *version; /**< The version that the authority says this router is - * running. */ - char *protocols; /**< The protocols that this authority says this router - * provides. */ - unsigned int has_measured_bw:1; /**< The vote had a measured bw */ - /** True iff the vote included an entry for ed25519 ID, or included - * "id ed25519 none" to indicate that there was no ed25519 ID. */ - unsigned int has_ed25519_listing:1; - /** True if the Ed25519 listing here is the consensus-opinion for the - * Ed25519 listing; false if there was no consensus on Ed25519 key status, - * or if this VRS doesn't reflect it. */ - unsigned int ed25519_reflects_consensus:1; - uint32_t measured_bw_kb; /**< Measured bandwidth (capacity) of the router */ - /** The hash or hashes that the authority claims this microdesc has. */ - vote_microdesc_hash_t *microdesc; - /** Ed25519 identity for this router, or zero if it has none. */ - uint8_t ed25519_id[ED25519_PUBKEY_LEN]; -} vote_routerstatus_t; - -/** A signature of some document by an authority. */ -typedef struct document_signature_t { - /** Declared SHA-1 digest of this voter's identity key */ - char identity_digest[DIGEST_LEN]; - /** Declared SHA-1 digest of signing key used by this voter. */ - char signing_key_digest[DIGEST_LEN]; - /** Algorithm used to compute the digest of the document. */ - digest_algorithm_t alg; - /** Signature of the signed thing. */ - char *signature; - /** Length of <b>signature</b> */ - int signature_len; - unsigned int bad_signature : 1; /**< Set to true if we've tried to verify - * the sig, and we know it's bad. */ - unsigned int good_signature : 1; /**< Set to true if we've verified the sig - * as good. */ -} document_signature_t; - -/** Information about a single voter in a vote or a consensus. */ -typedef struct networkstatus_voter_info_t { - /** Declared SHA-1 digest of this voter's identity key */ - char identity_digest[DIGEST_LEN]; - char *nickname; /**< Nickname of this voter */ - /** Digest of this voter's "legacy" identity key, if any. In vote only; for - * consensuses, we treat legacy keys as additional signers. */ - char legacy_id_digest[DIGEST_LEN]; - char *address; /**< Address of this voter, in string format. */ - uint32_t addr; /**< Address of this voter, in IPv4, in host order. */ - uint16_t dir_port; /**< Directory port of this voter */ - uint16_t or_port; /**< OR port of this voter */ - char *contact; /**< Contact information for this voter. */ - char vote_digest[DIGEST_LEN]; /**< Digest of this voter's vote, as signed. */ - - /* Nothing from here on is signed. */ - /** The signature of the document and the signature's status. */ - smartlist_t *sigs; -} networkstatus_voter_info_t; - -typedef struct networkstatus_sr_info_t { - /* Indicate if the dirauth partitipates in the SR protocol with its vote. - * This is tied to the SR flag in the vote. */ - unsigned int participate:1; - /* Both vote and consensus: Current and previous SRV. If list is empty, - * this means none were found in either the consensus or vote. */ - struct sr_srv_t *previous_srv; - struct sr_srv_t *current_srv; - /* Vote only: List of commitments. */ - smartlist_t *commits; -} networkstatus_sr_info_t; - -/** Enumerates the possible seriousness values of a networkstatus document. */ -typedef enum { - NS_TYPE_VOTE, - NS_TYPE_CONSENSUS, - NS_TYPE_OPINION, -} networkstatus_type_t; - -/** Enumerates recognized flavors of a consensus networkstatus document. All - * flavors of a consensus are generated from the same set of votes, but they - * present different types information to different versions of Tor. */ -typedef enum { - FLAV_NS = 0, - FLAV_MICRODESC = 1, -} consensus_flavor_t; - -/** How many different consensus flavors are there? */ -#define N_CONSENSUS_FLAVORS ((int)(FLAV_MICRODESC)+1) - -/** A common structure to hold a v3 network status vote, or a v3 network - * status consensus. */ -typedef struct networkstatus_t { - networkstatus_type_t type; /**< Vote, consensus, or opinion? */ - consensus_flavor_t flavor; /**< If a consensus, what kind? */ - unsigned int has_measured_bws : 1;/**< True iff this networkstatus contains - * measured= bandwidth values. */ - - time_t published; /**< Vote only: Time when vote was written. */ - time_t valid_after; /**< Time after which this vote or consensus applies. */ - time_t fresh_until; /**< Time before which this is the most recent vote or - * consensus. */ - time_t valid_until; /**< Time after which this vote or consensus should not - * be used. */ - - /** Consensus only: what method was used to produce this consensus? */ - int consensus_method; - /** Vote only: what methods is this voter willing to use? */ - smartlist_t *supported_methods; - - /** List of 'package' lines describing hashes of downloadable packages */ - smartlist_t *package_lines; - - /** How long does this vote/consensus claim that authorities take to - * distribute their votes to one another? */ - int vote_seconds; - /** How long does this vote/consensus claim that authorities take to - * distribute their consensus signatures to one another? */ - int dist_seconds; - - /** Comma-separated list of recommended client software, or NULL if this - * voter has no opinion. */ - char *client_versions; - char *server_versions; - - /** Lists of subprotocol versions which are _recommended_ for relays and - * clients, or which are _require_ for relays and clients. Tor shouldn't - * make any more network connections if a required protocol is missing. - */ - char *recommended_relay_protocols; - char *recommended_client_protocols; - char *required_relay_protocols; - char *required_client_protocols; - - /** List of flags that this vote/consensus applies to routers. If a flag is - * not listed here, the voter has no opinion on what its value should be. */ - smartlist_t *known_flags; - - /** List of key=value strings for the parameters in this vote or - * consensus, sorted by key. */ - smartlist_t *net_params; - - /** List of key=value strings for the bw weight parameters in the - * consensus. */ - smartlist_t *weight_params; - - /** List of networkstatus_voter_info_t. For a vote, only one element - * is included. For a consensus, one element is included for every voter - * whose vote contributed to the consensus. */ - smartlist_t *voters; - - struct authority_cert_t *cert; /**< Vote only: the voter's certificate. */ - - /** Digests of this document, as signed. */ - common_digests_t digests; - /** A SHA3-256 digest of the document, not including signatures: used for - * consensus diffs */ - uint8_t digest_sha3_as_signed[DIGEST256_LEN]; - - /** List of router statuses, sorted by identity digest. For a vote, - * the elements are vote_routerstatus_t; for a consensus, the elements - * are routerstatus_t. */ - smartlist_t *routerstatus_list; - - /** If present, a map from descriptor digest to elements of - * routerstatus_list. */ - digestmap_t *desc_digest_map; - - /** Contains the shared random protocol data from a vote or consensus. */ - networkstatus_sr_info_t sr_info; -} networkstatus_t; - -/** A set of signatures for a networkstatus consensus. Unless otherwise - * noted, all fields are as for networkstatus_t. */ -typedef struct ns_detached_signatures_t { - time_t valid_after; - time_t fresh_until; - time_t valid_until; - strmap_t *digests; /**< Map from flavor name to digestset_t */ - strmap_t *signatures; /**< Map from flavor name to list of - * document_signature_t */ -} ns_detached_signatures_t; - -/** Allowable types of desc_store_t. */ -typedef enum store_type_t { - ROUTER_STORE = 0, - EXTRAINFO_STORE = 1 -} store_type_t; - -/** A 'store' is a set of descriptors saved on disk, with accompanying - * journal, mmaped as needed, rebuilt as needed. */ -typedef struct desc_store_t { - /** Filename (within DataDir) for the store. We append .tmp to this - * filename for a temporary file when rebuilding the store, and .new to this - * filename for the journal. */ - const char *fname_base; - /** Human-readable description of what this store contains. */ - const char *description; - - tor_mmap_t *mmap; /**< A mmap for the main file in the store. */ - - store_type_t type; /**< What's stored in this store? */ - - /** The size of the router log, in bytes. */ - size_t journal_len; - /** The size of the router store, in bytes. */ - size_t store_len; - /** Total bytes dropped since last rebuild: this is space currently - * used in the cache and the journal that could be freed by a rebuild. */ - size_t bytes_dropped; -} desc_store_t; - -/** Contents of a directory of onion routers. */ -typedef struct { - /** Map from server identity digest to a member of routers. */ - struct digest_ri_map_t *identity_map; - /** Map from server descriptor digest to a signed_descriptor_t from - * routers or old_routers. */ - struct digest_sd_map_t *desc_digest_map; - /** Map from extra-info digest to an extrainfo_t. Only exists for - * routers in routers or old_routers. */ - struct digest_ei_map_t *extra_info_map; - /** Map from extra-info digests to a signed_descriptor_t for a router - * descriptor having that extra-info digest. Only exists for - * routers in routers or old_routers. */ - struct digest_sd_map_t *desc_by_eid_map; - /** List of routerinfo_t for all currently live routers we know. */ - smartlist_t *routers; - /** List of signed_descriptor_t for older router descriptors we're - * caching. */ - smartlist_t *old_routers; - /** Store holding server descriptors. If present, any router whose - * cache_info.saved_location == SAVED_IN_CACHE is stored in this file - * starting at cache_info.saved_offset */ - desc_store_t desc_store; - /** Store holding extra-info documents. */ - desc_store_t extrainfo_store; -} routerlist_t; - -/** Information on router used when extending a circuit. We don't need a - * full routerinfo_t to extend: we only need addr:port:keyid to build an OR - * connection, and onion_key to create the onionskin. Note that for onehop - * general-purpose tunnels, the onion_key is NULL. */ -typedef struct extend_info_t { - char nickname[MAX_HEX_NICKNAME_LEN+1]; /**< This router's nickname for - * display. */ - /** Hash of this router's RSA identity key. */ - char identity_digest[DIGEST_LEN]; - /** Ed25519 identity for this router, if any. */ - ed25519_public_key_t ed_identity; - uint16_t port; /**< OR port. */ - tor_addr_t addr; /**< IP address. */ - crypto_pk_t *onion_key; /**< Current onionskin key. */ - curve25519_public_key_t curve25519_onion_key; -} extend_info_t; - -/** Certificate for v3 directory protocol: binds long-term authority identity - * keys to medium-term authority signing keys. */ -typedef struct authority_cert_t { - /** Information relating to caching this cert on disk and looking it up. */ - signed_descriptor_t cache_info; - /** This authority's long-term authority identity key. */ - crypto_pk_t *identity_key; - /** This authority's medium-term signing key. */ - crypto_pk_t *signing_key; - /** The digest of <b>signing_key</b> */ - char signing_key_digest[DIGEST_LEN]; - /** The listed expiration time of this certificate. */ - time_t expires; - /** This authority's IPv4 address, in host order. */ - uint32_t addr; - /** This authority's directory port. */ - uint16_t dir_port; -} authority_cert_t; - -/** Bitfield enum type listing types of information that directory authorities - * can be authoritative about, and that directory caches may or may not cache. - * - * Note that the granularity here is based on authority granularity and on - * cache capabilities. Thus, one particular bit may correspond in practice to - * a few types of directory info, so long as every authority that pronounces - * officially about one of the types prounounces officially about all of them, - * and so long as every cache that caches one of them caches all of them. - */ -typedef enum { - NO_DIRINFO = 0, - /** Serves/signs v3 directory information: votes, consensuses, certs */ - V3_DIRINFO = 1 << 2, - /** Serves bridge descriptors. */ - BRIDGE_DIRINFO = 1 << 4, - /** Serves extrainfo documents. */ - EXTRAINFO_DIRINFO=1 << 5, - /** Serves microdescriptors. */ - MICRODESC_DIRINFO=1 << 6, -} dirinfo_type_t; - -#define ALL_DIRINFO ((dirinfo_type_t)((1<<7)-1)) - -#define CRYPT_PATH_MAGIC 0x70127012u - -struct fast_handshake_state_t; -struct ntor_handshake_state_t; -#define ONION_HANDSHAKE_TYPE_TAP 0x0000 -#define ONION_HANDSHAKE_TYPE_FAST 0x0001 -#define ONION_HANDSHAKE_TYPE_NTOR 0x0002 -#define MAX_ONION_HANDSHAKE_TYPE 0x0002 -typedef struct { - uint16_t tag; - union { - struct fast_handshake_state_t *fast; - crypto_dh_t *tap; - struct ntor_handshake_state_t *ntor; - } u; -} onion_handshake_state_t; - -typedef struct relay_crypto_t { - /* crypto environments */ - /** Encryption key and counter for cells heading towards the OR at this - * step. */ - crypto_cipher_t *f_crypto; - /** Encryption key and counter for cells heading back from the OR at this - * step. */ - crypto_cipher_t *b_crypto; - - /** Digest state for cells heading towards the OR at this step. */ - crypto_digest_t *f_digest; /* for integrity checking */ - /** Digest state for cells heading away from the OR at this step. */ - crypto_digest_t *b_digest; - -} relay_crypto_t; - -/** Holds accounting information for a single step in the layered encryption - * performed by a circuit. Used only at the client edge of a circuit. */ -typedef struct crypt_path_t { - uint32_t magic; - - /** Cryptographic state used for encrypting and authenticating relay - * cells to and from this hop. */ - relay_crypto_t crypto; - - /** Current state of the handshake as performed with the OR at this - * step. */ - onion_handshake_state_t handshake_state; - /** Diffie-hellman handshake state for performing an introduction - * operations */ - crypto_dh_t *rend_dh_handshake_state; - - /** Negotiated key material shared with the OR at this step. */ - char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ - - /** Information to extend to the OR at this step. */ - extend_info_t *extend_info; - - /** Is the circuit built to this step? Must be one of: - * - CPATH_STATE_CLOSED (The circuit has not been extended to this step) - * - CPATH_STATE_AWAITING_KEYS (We have sent an EXTEND/CREATE to this step - * and not received an EXTENDED/CREATED) - * - CPATH_STATE_OPEN (The circuit has been extended to this step) */ - uint8_t state; -#define CPATH_STATE_CLOSED 0 -#define CPATH_STATE_AWAITING_KEYS 1 -#define CPATH_STATE_OPEN 2 - struct crypt_path_t *next; /**< Link to next crypt_path_t in the circuit. - * (The list is circular, so the last node - * links to the first.) */ - struct crypt_path_t *prev; /**< Link to previous crypt_path_t in the - * circuit. */ - - int package_window; /**< How many cells are we allowed to originate ending - * at this step? */ - int deliver_window; /**< How many cells are we willing to deliver originating - * at this step? */ -} crypt_path_t; - -/** A reference-counted pointer to a crypt_path_t, used only to share - * the final rendezvous cpath to be used on a service-side rendezvous - * circuit among multiple circuits built in parallel to the same - * destination rendezvous point. */ -typedef struct { - /** The reference count. */ - unsigned int refcount; - /** The pointer. Set to NULL when the crypt_path_t is put into use - * on an opened rendezvous circuit. */ - crypt_path_t *cpath; -} crypt_path_reference_t; - -#define CPATH_KEY_MATERIAL_LEN (20*2+16*2) - -#define DH_KEY_LEN DH_BYTES - -/** Information used to build a circuit. */ -typedef struct { - /** Intended length of the final circuit. */ - int desired_path_len; - /** How to extend to the planned exit node. */ - extend_info_t *chosen_exit; - /** Whether every node in the circ must have adequate uptime. */ - unsigned int need_uptime : 1; - /** Whether every node in the circ must have adequate capacity. */ - unsigned int need_capacity : 1; - /** Whether the last hop was picked with exiting in mind. */ - unsigned int is_internal : 1; - /** Did we pick this as a one-hop tunnel (not safe for other streams)? - * These are for encrypted dir conns that exit to this router, not - * for arbitrary exits from the circuit. */ - unsigned int onehop_tunnel : 1; - /** The crypt_path_t to append after rendezvous: used for rendezvous. */ - crypt_path_t *pending_final_cpath; - /** A ref-counted reference to the crypt_path_t to append after - * rendezvous; used on the service side. */ - crypt_path_reference_t *service_pending_final_cpath_ref; - /** How many times has building a circuit for this task failed? */ - int failure_count; - /** At what time should we give up on this task? */ - time_t expiry_time; -} cpath_build_state_t; - -/** "magic" value for an origin_circuit_t */ -#define ORIGIN_CIRCUIT_MAGIC 0x35315243u -/** "magic" value for an or_circuit_t */ -#define OR_CIRCUIT_MAGIC 0x98ABC04Fu -/** "magic" value for a circuit that would have been freed by circuit_free, - * but which we're keeping around until a cpuworker reply arrives. See - * circuit_free() for more documentation. */ -#define DEAD_CIRCUIT_MAGIC 0xdeadc14c - -struct create_cell_t; - -/** Entry in the cell stats list of a circuit; used only if CELL_STATS - * events are enabled. */ -typedef struct testing_cell_stats_entry_t { - uint8_t command; /**< cell command number. */ - /** Waiting time in centiseconds if this event is for a removed cell, - * or 0 if this event is for adding a cell to the queue. 22 bits can - * store more than 11 hours, enough to assume that a circuit with this - * delay would long have been closed. */ - unsigned int waiting_time:22; - unsigned int removed:1; /**< 0 for added to, 1 for removed from queue. */ - unsigned int exitward:1; /**< 0 for app-ward, 1 for exit-ward. */ -} testing_cell_stats_entry_t; - -/** - * A circuit is a path over the onion routing - * network. Applications can connect to one end of the circuit, and can - * create exit connections at the other end of the circuit. AP and exit - * connections have only one circuit associated with them (and thus these - * connection types are closed when the circuit is closed), whereas - * OR connections multiplex many circuits at once, and stay standing even - * when there are no circuits running over them. - * - * A circuit_t structure can fill one of two roles. First, a or_circuit_t - * links two connections together: either an edge connection and an OR - * connection, or two OR connections. (When joined to an OR connection, a - * circuit_t affects only cells sent to a particular circID on that - * connection. When joined to an edge connection, a circuit_t affects all - * data.) - - * Second, an origin_circuit_t holds the cipher keys and state for sending data - * along a given circuit. At the OP, it has a sequence of ciphers, each - * of which is shared with a single OR along the circuit. Separate - * ciphers are used for data going "forward" (away from the OP) and - * "backward" (towards the OP). At the OR, a circuit has only two stream - * ciphers: one for data going forward, and one for data going backward. - */ -typedef struct circuit_t { - uint32_t magic; /**< For memory and type debugging: must equal - * ORIGIN_CIRCUIT_MAGIC or OR_CIRCUIT_MAGIC. */ - - /** The channel that is next in this circuit. */ - channel_t *n_chan; - - /** - * The circuit_id used in the next (forward) hop of this circuit; - * this is unique to n_chan, but this ordered pair is globally - * unique: - * - * (n_chan->global_identifier, n_circ_id) - */ - circid_t n_circ_id; - - /** - * Circuit mux associated with n_chan to which this circuit is attached; - * NULL if we have no n_chan. - */ - circuitmux_t *n_mux; - - /** Queue of cells waiting to be transmitted on n_chan */ - cell_queue_t n_chan_cells; - - /** - * The hop to which we want to extend this circuit. Should be NULL if - * the circuit has attached to a channel. - */ - extend_info_t *n_hop; - - /** True iff we are waiting for n_chan_cells to become less full before - * allowing p_streams to add any more cells. (Origin circuit only.) */ - unsigned int streams_blocked_on_n_chan : 1; - /** True iff we are waiting for p_chan_cells to become less full before - * allowing n_streams to add any more cells. (OR circuit only.) */ - unsigned int streams_blocked_on_p_chan : 1; - - /** True iff we have queued a delete backwards on this circuit, but not put - * it on the output buffer. */ - unsigned int p_delete_pending : 1; - /** True iff we have queued a delete forwards on this circuit, but not put - * it on the output buffer. */ - unsigned int n_delete_pending : 1; - - /** True iff this circuit has received a DESTROY cell in either direction */ - unsigned int received_destroy : 1; - - uint8_t state; /**< Current status of this circuit. */ - uint8_t purpose; /**< Why are we creating this circuit? */ - - /** How many relay data cells can we package (read from edge streams) - * on this circuit before we receive a circuit-level sendme cell asking - * for more? */ - int package_window; - /** How many relay data cells will we deliver (write to edge streams) - * on this circuit? When deliver_window gets low, we send some - * circuit-level sendme cells to indicate that we're willing to accept - * more. */ - int deliver_window; - - /** Temporary field used during circuits_handle_oom. */ - uint32_t age_tmp; - - /** For storage while n_chan is pending (state CIRCUIT_STATE_CHAN_WAIT). */ - struct create_cell_t *n_chan_create_cell; - - /** When did circuit construction actually begin (ie send the - * CREATE cell or begin cannibalization). - * - * Note: This timer will get reset if we decide to cannibalize - * a circuit. It may also get reset during certain phases of hidden - * service circuit use. - * - * We keep this timestamp with a higher resolution than most so that the - * circuit-build-time tracking code can get millisecond resolution. - */ - struct timeval timestamp_began; - - /** This timestamp marks when the init_circuit_base constructor ran. */ - struct timeval timestamp_created; - - /** When the circuit was first used, or 0 if the circuit is clean. - * - * XXXX Note that some code will artificially adjust this value backward - * in time in order to indicate that a circuit shouldn't be used for new - * streams, but that it can stay alive as long as it has streams on it. - * That's a kludge we should fix. - * - * XXX The CBT code uses this field to record when HS-related - * circuits entered certain states. This usage probably won't - * interfere with this field's primary purpose, but we should - * document it more thoroughly to make sure of that. - * - * XXX The SocksPort option KeepaliveIsolateSOCKSAuth will artificially - * adjust this value forward each time a suitable stream is attached to an - * already constructed circuit, potentially keeping the circuit alive - * indefinitely. - */ - time_t timestamp_dirty; - - uint16_t marked_for_close; /**< Should we close this circuit at the end of - * the main loop? (If true, holds the line number - * where this circuit was marked.) */ - const char *marked_for_close_file; /**< For debugging: in which file was this - * circuit marked for close? */ - /** For what reason (See END_CIRC_REASON...) is this circuit being closed? - * This field is set in circuit_mark_for_close and used later in - * circuit_about_to_free. */ - int marked_for_close_reason; - /** As marked_for_close_reason, but reflects the underlying reason for - * closing this circuit. - */ - int marked_for_close_orig_reason; - - /** Unique ID for measuring tunneled network status requests. */ - uint64_t dirreq_id; - - /** Index in smartlist of all circuits (global_circuitlist). */ - int global_circuitlist_idx; - - /** Various statistics about cells being added to or removed from this - * circuit's queues; used only if CELL_STATS events are enabled and - * cleared after being sent to control port. */ - smartlist_t *testing_cell_stats; - - /** If set, points to an HS token that this circuit might be carrying. - * Used by the HS circuitmap. */ - hs_token_t *hs_token; - /** Hashtable node: used to look up the circuit by its HS token using the HS - circuitmap. */ - HT_ENTRY(circuit_t) hs_circuitmap_node; -} circuit_t; - -/** Largest number of relay_early cells that we can send on a given - * circuit. */ -#define MAX_RELAY_EARLY_CELLS_PER_CIRCUIT 8 - -/** - * Describes the circuit building process in simplified terms based - * on the path bias accounting state for a circuit. - * - * NOTE: These state values are enumerated in the order for which we - * expect circuits to transition through them. If you add states, - * you need to preserve this overall ordering. The various pathbias - * state transition and accounting functions (pathbias_mark_* and - * pathbias_count_*) contain ordinal comparisons to enforce proper - * state transitions for corrections. - * - * This state machine and the associated logic was created to prevent - * miscounting due to unknown cases of circuit reuse. See also tickets - * #6475 and #7802. - */ -typedef enum { - /** This circuit is "new". It has not yet completed a first hop - * or been counted by the path bias code. */ - PATH_STATE_NEW_CIRC = 0, - /** This circuit has completed one/two hops, and has been counted by - * the path bias logic. */ - PATH_STATE_BUILD_ATTEMPTED = 1, - /** This circuit has been completely built */ - PATH_STATE_BUILD_SUCCEEDED = 2, - /** Did we try to attach any SOCKS streams or hidserv introductions to - * this circuit? - * - * Note: If we ever implement end-to-end stream timing through test - * stream probes (#5707), we must *not* set this for those probes - * (or any other automatic streams) because the adversary could - * just tag at a later point. - */ - PATH_STATE_USE_ATTEMPTED = 3, - /** Did any SOCKS streams or hidserv introductions actually succeed on - * this circuit? - * - * If any streams detatch/fail from this circuit, the code transitions - * the circuit back to PATH_STATE_USE_ATTEMPTED to ensure we probe. See - * pathbias_mark_use_rollback() for that. - */ - PATH_STATE_USE_SUCCEEDED = 4, - - /** - * This is a special state to indicate that we got a corrupted - * relay cell on a circuit and we don't intend to probe it. - */ - PATH_STATE_USE_FAILED = 5, - - /** - * This is a special state to indicate that we already counted - * the circuit. Used to guard against potential state machine - * violations. - */ - PATH_STATE_ALREADY_COUNTED = 6, -} path_state_t; -#define path_state_bitfield_t ENUM_BF(path_state_t) - -/** An origin_circuit_t holds data necessary to build and use a circuit. - */ -typedef struct origin_circuit_t { - circuit_t base_; - - /** Linked list of AP streams (or EXIT streams if hidden service) - * associated with this circuit. */ - edge_connection_t *p_streams; - - /** Bytes read on this circuit since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_read_circ_bw; - - /** Bytes written to on this circuit since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_written_circ_bw; - - /** Total known-valid relay cell bytes since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_delivered_read_circ_bw; - - /** Total written relay cell bytes since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_delivered_written_circ_bw; - - /** Total overhead data in all known-valid relay data cells since last - * call to control_event_circ_bandwidth_used(). Only used if we're - * configured to emit CIRC_BW events. */ - uint32_t n_overhead_read_circ_bw; - - /** Total written overhead data in all relay data cells since last call to - * control_event_circ_bandwidth_used(). Only used if we're configured - * to emit CIRC_BW events. */ - uint32_t n_overhead_written_circ_bw; - - /** Build state for this circuit. It includes the intended path - * length, the chosen exit router, rendezvous information, etc. - */ - cpath_build_state_t *build_state; - /** The doubly-linked list of crypt_path_t entries, one per hop, - * for this circuit. This includes ciphers for each hop, - * integrity-checking digests for each hop, and package/delivery - * windows for each hop. - */ - crypt_path_t *cpath; - - /** Holds all rendezvous data on either client or service side. */ - rend_data_t *rend_data; - - /** Holds hidden service identifier on either client or service side. This - * is for both introduction and rendezvous circuit. */ - struct hs_ident_circuit_t *hs_ident; - - /** Holds the data that the entry guard system uses to track the - * status of the guard this circuit is using, and thereby to determine - * whether this circuit can be used. */ - struct circuit_guard_state_t *guard_state; - - /** Index into global_origin_circuit_list for this circuit. -1 if not - * present. */ - int global_origin_circuit_list_idx; - - /** How many more relay_early cells can we send on this circuit, according - * to the specification? */ - unsigned int remaining_relay_early_cells : 4; - - /** Set if this circuit is insanely old and we already informed the user */ - unsigned int is_ancient : 1; - - /** Set if this circuit has already been opened. Used to detect - * cannibalized circuits. */ - unsigned int has_opened : 1; - - /** - * Path bias state machine. Used to ensure integrity of our - * circuit building and usage accounting. See path_state_t - * for more details. - */ - path_state_bitfield_t path_state : 3; - - /* If this flag is set, we should not consider attaching any more - * connections to this circuit. */ - unsigned int unusable_for_new_conns : 1; - - /** - * Tristate variable to guard against pathbias miscounting - * due to circuit purpose transitions changing the decision - * of pathbias_should_count(). This variable is informational - * only. The current results of pathbias_should_count() are - * the official decision for pathbias accounting. - */ - uint8_t pathbias_shouldcount; -#define PATHBIAS_SHOULDCOUNT_UNDECIDED 0 -#define PATHBIAS_SHOULDCOUNT_IGNORED 1 -#define PATHBIAS_SHOULDCOUNT_COUNTED 2 - - /** For path probing. Store the temporary probe stream ID - * for response comparison */ - streamid_t pathbias_probe_id; - - /** For path probing. Store the temporary probe address nonce - * (in host byte order) for response comparison. */ - uint32_t pathbias_probe_nonce; - - /** Set iff this is a hidden-service circuit which has timed out - * according to our current circuit-build timeout, but which has - * been kept around because it might still succeed in connecting to - * its destination, and which is not a fully-connected rendezvous - * circuit. - * - * (We clear this flag for client-side rendezvous circuits when they - * are 'joined' to the other side's rendezvous circuit, so that - * connection_ap_handshake_attach_circuit can put client streams on - * the circuit. We also clear this flag for service-side rendezvous - * circuits when they are 'joined' to a client's rend circ, but only - * for symmetry with the client case. Client-side introduction - * circuits are closed when we get a joined rend circ, and - * service-side introduction circuits never have this flag set.) */ - unsigned int hs_circ_has_timed_out : 1; - - /** Set iff this circuit has been given a relaxed timeout because - * no circuits have opened. Used to prevent spamming logs. */ - unsigned int relaxed_timeout : 1; - - /** Set iff this is a service-side rendezvous circuit for which a - * new connection attempt has been launched. We consider launching - * a new service-side rend circ to a client when the previous one - * fails; now that we don't necessarily close a service-side rend - * circ when we launch a new one to the same client, this flag keeps - * us from launching two retries for the same failed rend circ. */ - unsigned int hs_service_side_rend_circ_has_been_relaunched : 1; - - /** What commands were sent over this circuit that decremented the - * RELAY_EARLY counter? This is for debugging task 878. */ - uint8_t relay_early_commands[MAX_RELAY_EARLY_CELLS_PER_CIRCUIT]; - - /** How many RELAY_EARLY cells have been sent over this circuit? This is - * for debugging task 878, too. */ - int relay_early_cells_sent; - - /** The next stream_id that will be tried when we're attempting to - * construct a new AP stream originating at this circuit. */ - streamid_t next_stream_id; - - /* The intro key replaces the hidden service's public key if purpose is - * S_ESTABLISH_INTRO or S_INTRO, provided that no unversioned rendezvous - * descriptor is used. */ - crypto_pk_t *intro_key; - - /** Quasi-global identifier for this circuit; used for control.c */ - /* XXXX NM This can get re-used after 2**32 circuits. */ - uint32_t global_identifier; - - /** True if we have associated one stream to this circuit, thereby setting - * the isolation parameters for this circuit. Note that this doesn't - * necessarily mean that we've <em>attached</em> any streams to the circuit: - * we may only have marked up this circuit during the launch process. - */ - unsigned int isolation_values_set : 1; - /** True iff any stream has <em>ever</em> been attached to this circuit. - * - * In a better world we could use timestamp_dirty for this, but - * timestamp_dirty is far too overloaded at the moment. - */ - unsigned int isolation_any_streams_attached : 1; - - /** A bitfield of ISO_* flags for every isolation field such that this - * circuit has had streams with more than one value for that field - * attached to it. */ - uint8_t isolation_flags_mixed; - - /** @name Isolation parameters - * - * If any streams have been associated with this circ (isolation_values_set - * == 1), and all streams associated with the circuit have had the same - * value for some field ((isolation_flags_mixed & ISO_FOO) == 0), then these - * elements hold the value for that field. - * - * Note again that "associated" is not the same as "attached": we - * preliminarily associate streams with a circuit while the circuit is being - * launched, so that we can tell whether we need to launch more circuits. - * - * @{ - */ - uint8_t client_proto_type; - uint8_t client_proto_socksver; - uint16_t dest_port; - tor_addr_t client_addr; - char *dest_address; - int session_group; - unsigned nym_epoch; - size_t socks_username_len; - uint8_t socks_password_len; - /* Note that the next two values are NOT NUL-terminated; see - socks_username_len and socks_password_len for their lengths. */ - char *socks_username; - char *socks_password; - /** Global identifier for the first stream attached here; used by - * ISO_STREAM. */ - uint64_t associated_isolated_stream_global_id; - /**@}*/ - /** A list of addr_policy_t for this circuit in particular. Used by - * adjust_exit_policy_from_exitpolicy_failure. - */ - smartlist_t *prepend_policy; - - /** How long do we wait before closing this circuit if it remains - * completely idle after it was built, in seconds? This value - * is randomized on a per-circuit basis from CircuitsAvailableTimoeut - * to 2*CircuitsAvailableTimoeut. */ - int circuit_idle_timeout; - -} origin_circuit_t; - -struct onion_queue_t; - -/** An or_circuit_t holds information needed to implement a circuit at an - * OR. */ -typedef struct or_circuit_t { - circuit_t base_; - - /** Pointer to an entry on the onion queue, if this circuit is waiting for a - * chance to give an onionskin to a cpuworker. Used only in onion.c */ - struct onion_queue_t *onionqueue_entry; - /** Pointer to a workqueue entry, if this circuit has given an onionskin to - * a cpuworker and is waiting for a response. Used to decide whether it is - * safe to free a circuit or if it is still in use by a cpuworker. */ - struct workqueue_entry_s *workqueue_entry; - - /** The circuit_id used in the previous (backward) hop of this circuit. */ - circid_t p_circ_id; - /** Queue of cells waiting to be transmitted on p_conn. */ - cell_queue_t p_chan_cells; - /** The channel that is previous in this circuit. */ - channel_t *p_chan; - /** - * Circuit mux associated with p_chan to which this circuit is attached; - * NULL if we have no p_chan. - */ - circuitmux_t *p_mux; - /** Linked list of Exit streams associated with this circuit. */ - edge_connection_t *n_streams; - /** Linked list of Exit streams associated with this circuit that are - * still being resolved. */ - edge_connection_t *resolving_streams; - - /** Cryptographic state used for encrypting and authenticating relay - * cells to and from this hop. */ - relay_crypto_t crypto; - - /** Points to spliced circuit if purpose is REND_ESTABLISHED, and circuit - * is not marked for close. */ - struct or_circuit_t *rend_splice; - - /** Stores KH for the handshake. */ - char rend_circ_nonce[DIGEST_LEN];/* KH in tor-spec.txt */ - - /** How many more relay_early cells can we send on this circuit, according - * to the specification? */ - unsigned int remaining_relay_early_cells : 4; - - /* We have already received an INTRODUCE1 cell on this circuit. */ - unsigned int already_received_introduce1 : 1; - - /** If set, this circuit carries HS traffic. Consider it in any HS - * statistics. */ - unsigned int circuit_carries_hs_traffic_stats : 1; - - /** Number of cells that were removed from circuit queue; reset every - * time when writing buffer stats to disk. */ - uint32_t processed_cells; - - /** Total time in milliseconds that cells spent in both app-ward and - * exit-ward queues of this circuit; reset every time when writing - * buffer stats to disk. */ - uint64_t total_cell_waiting_time; -} or_circuit_t; - -#if REND_COOKIE_LEN != DIGEST_LEN -#error "The REND_TOKEN_LEN macro assumes REND_COOKIE_LEN == DIGEST_LEN" -#endif -#define REND_TOKEN_LEN DIGEST_LEN - -/** Convert a circuit subtype to a circuit_t. */ -#define TO_CIRCUIT(x) (&((x)->base_)) - -/** Convert a circuit_t* to a pointer to the enclosing or_circuit_t. Assert - * if the cast is impossible. */ -static or_circuit_t *TO_OR_CIRCUIT(circuit_t *); -static const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *); -/** Convert a circuit_t* to a pointer to the enclosing origin_circuit_t. - * Assert if the cast is impossible. */ -static origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *); -static const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT(const circuit_t *); - -/** Return 1 iff <b>node</b> has Exit flag and no BadExit flag. - * Otherwise, return 0. - */ -static inline int node_is_good_exit(const node_t *node) -{ - return node->is_exit && ! node->is_bad_exit; -} - -static inline or_circuit_t *TO_OR_CIRCUIT(circuit_t *x) -{ - tor_assert(x->magic == OR_CIRCUIT_MAGIC); - return DOWNCAST(or_circuit_t, x); -} -static inline const or_circuit_t *CONST_TO_OR_CIRCUIT(const circuit_t *x) -{ - tor_assert(x->magic == OR_CIRCUIT_MAGIC); - return DOWNCAST(or_circuit_t, x); -} -static inline origin_circuit_t *TO_ORIGIN_CIRCUIT(circuit_t *x) -{ - tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); - return DOWNCAST(origin_circuit_t, x); -} -static inline const origin_circuit_t *CONST_TO_ORIGIN_CIRCUIT( - const circuit_t *x) -{ - tor_assert(x->magic == ORIGIN_CIRCUIT_MAGIC); - return DOWNCAST(origin_circuit_t, x); -} - -/* limits for TCP send and recv buffer size used for constrained sockets */ -#define MIN_CONSTRAINED_TCP_BUFFER 2048 -#define MAX_CONSTRAINED_TCP_BUFFER 262144 /* 256k */ - -/** @name Isolation flags - - Ways to isolate client streams - - @{ -*/ -/** Isolate based on destination port */ -#define ISO_DESTPORT (1u<<0) -/** Isolate based on destination address */ -#define ISO_DESTADDR (1u<<1) -/** Isolate based on SOCKS authentication */ -#define ISO_SOCKSAUTH (1u<<2) -/** Isolate based on client protocol choice */ -#define ISO_CLIENTPROTO (1u<<3) -/** Isolate based on client address */ -#define ISO_CLIENTADDR (1u<<4) -/** Isolate based on session group (always on). */ -#define ISO_SESSIONGRP (1u<<5) -/** Isolate based on newnym epoch (always on). */ -#define ISO_NYM_EPOCH (1u<<6) -/** Isolate all streams (Internal only). */ -#define ISO_STREAM (1u<<7) -/**@}*/ - -/** Default isolation level for ports. */ -#define ISO_DEFAULT (ISO_CLIENTADDR|ISO_SOCKSAUTH|ISO_SESSIONGRP|ISO_NYM_EPOCH) - -/** Indicates that we haven't yet set a session group on a port_cfg_t. */ -#define SESSION_GROUP_UNSET -1 -/** Session group reserved for directory connections */ -#define SESSION_GROUP_DIRCONN -2 -/** Session group reserved for resolve requests launched by a controller */ -#define SESSION_GROUP_CONTROL_RESOLVE -3 -/** First automatically allocated session group number */ -#define SESSION_GROUP_FIRST_AUTO -4 - -/** Configuration for a single port that we're listening on. */ -typedef struct port_cfg_t { - tor_addr_t addr; /**< The actual IP to listen on, if !is_unix_addr. */ - int port; /**< The configured port, or CFG_AUTO_PORT to tell Tor to pick its - * own port. */ - uint8_t type; /**< One of CONN_TYPE_*_LISTENER */ - unsigned is_unix_addr : 1; /**< True iff this is an AF_UNIX address. */ - - unsigned is_group_writable : 1; - unsigned is_world_writable : 1; - unsigned relax_dirmode_check : 1; - - entry_port_cfg_t entry_cfg; - - server_port_cfg_t server_cfg; - - /* Unix sockets only: */ - /** Path for an AF_UNIX address */ - char unix_addr[FLEXIBLE_ARRAY_MEMBER]; -} port_cfg_t; - -typedef struct routerset_t routerset_t; - -/** A magic value for the (Socks|OR|...)Port options below, telling Tor - * to pick its own port. */ -#define CFG_AUTO_PORT 0xc4005e - -/** Enumeration of outbound address configuration types: - * Exit-only, OR-only, or both */ -typedef enum {OUTBOUND_ADDR_EXIT, OUTBOUND_ADDR_OR, - OUTBOUND_ADDR_EXIT_AND_OR, - OUTBOUND_ADDR_MAX} outbound_addr_t; - -/** Configuration options for a Tor process. */ -typedef struct { - uint32_t magic_; - - /** What should the tor process actually do? */ - enum { - CMD_RUN_TOR=0, CMD_LIST_FINGERPRINT, CMD_HASH_PASSWORD, - CMD_VERIFY_CONFIG, CMD_RUN_UNITTESTS, CMD_DUMP_CONFIG, - CMD_KEYGEN, - CMD_KEY_EXPIRATION, - } command; - char *command_arg; /**< Argument for command-line option. */ - - config_line_t *Logs; /**< New-style list of configuration lines - * for logs */ - int LogTimeGranularity; /**< Log resolution in milliseconds. */ - - int LogMessageDomains; /**< Boolean: Should we log the domain(s) in which - * each log message occurs? */ - int TruncateLogFile; /**< Boolean: Should we truncate the log file - before we start writing? */ - char *SyslogIdentityTag; /**< Identity tag to add for syslog logging. */ - char *AndroidIdentityTag; /**< Identity tag to add for Android logging. */ - - char *DebugLogFile; /**< Where to send verbose log messages. */ - char *DataDirectory_option; /**< Where to store long-term data, as - * configured by the user. */ - char *DataDirectory; /**< Where to store long-term data, as modified. */ - int DataDirectoryGroupReadable; /**< Boolean: Is the DataDirectory g+r? */ - - char *KeyDirectory_option; /**< Where to store keys, as - * configured by the user. */ - char *KeyDirectory; /**< Where to store keys data, as modified. */ - int KeyDirectoryGroupReadable; /**< Boolean: Is the KeyDirectory g+r? */ - - char *CacheDirectory_option; /**< Where to store cached data, as - * configured by the user. */ - char *CacheDirectory; /**< Where to store cached data, as modified. */ - int CacheDirectoryGroupReadable; /**< Boolean: Is the CacheDirectory g+r? */ - - char *Nickname; /**< OR only: nickname of this onion router. */ - char *Address; /**< OR only: configured address for this onion router. */ - char *PidFile; /**< Where to store PID of Tor process. */ - - routerset_t *ExitNodes; /**< Structure containing nicknames, digests, - * country codes and IP address patterns of ORs to - * consider as exits. */ - routerset_t *EntryNodes;/**< Structure containing nicknames, digests, - * country codes and IP address patterns of ORs to - * consider as entry points. */ - int StrictNodes; /**< Boolean: When none of our EntryNodes or ExitNodes - * are up, or we need to access a node in ExcludeNodes, - * do we just fail instead? */ - routerset_t *ExcludeNodes;/**< Structure containing nicknames, digests, - * country codes and IP address patterns of ORs - * not to use in circuits. But see StrictNodes - * above. */ - routerset_t *ExcludeExitNodes;/**< Structure containing nicknames, digests, - * country codes and IP address patterns of - * ORs not to consider as exits. */ - - /** Union of ExcludeNodes and ExcludeExitNodes */ - routerset_t *ExcludeExitNodesUnion_; - - int DisableAllSwap; /**< Boolean: Attempt to call mlockall() on our - * process for all current and future memory. */ - - config_line_t *ExitPolicy; /**< Lists of exit policy components. */ - int ExitPolicyRejectPrivate; /**< Should we not exit to reserved private - * addresses, and our own published addresses? - */ - int ExitPolicyRejectLocalInterfaces; /**< Should we not exit to local - * interface addresses? - * Includes OutboundBindAddresses and - * configured ports. */ - int ReducedExitPolicy; /**<Should we use the Reduced Exit Policy? */ - config_line_t *SocksPolicy; /**< Lists of socks policy components */ - config_line_t *DirPolicy; /**< Lists of dir policy components */ - /** Local address to bind outbound sockets */ - config_line_t *OutboundBindAddress; - /** Local address to bind outbound relay sockets */ - config_line_t *OutboundBindAddressOR; - /** Local address to bind outbound exit sockets */ - config_line_t *OutboundBindAddressExit; - /** Addresses derived from the various OutboundBindAddress lines. - * [][0] is IPv4, [][1] is IPv6 - */ - tor_addr_t OutboundBindAddresses[OUTBOUND_ADDR_MAX][2]; - /** Directory server only: which versions of - * Tor should we tell users to run? */ - config_line_t *RecommendedVersions; - config_line_t *RecommendedClientVersions; - config_line_t *RecommendedServerVersions; - config_line_t *RecommendedPackages; - /** Whether dirservers allow router descriptors with private IPs. */ - int DirAllowPrivateAddresses; - /** Whether routers accept EXTEND cells to routers with private IPs. */ - int ExtendAllowPrivateAddresses; - char *User; /**< Name of user to run Tor as. */ - config_line_t *ORPort_lines; /**< Ports to listen on for OR connections. */ - /** Ports to listen on for extended OR connections. */ - config_line_t *ExtORPort_lines; - /** Ports to listen on for SOCKS connections. */ - config_line_t *SocksPort_lines; - /** Ports to listen on for transparent pf/netfilter connections. */ - config_line_t *TransPort_lines; - char *TransProxyType; /**< What kind of transparent proxy - * implementation are we using? */ - /** Parsed value of TransProxyType. */ - enum { - TPT_DEFAULT, - TPT_PF_DIVERT, - TPT_IPFW, - TPT_TPROXY, - } TransProxyType_parsed; - config_line_t *NATDPort_lines; /**< Ports to listen on for transparent natd - * connections. */ - /** Ports to listen on for HTTP Tunnel connections. */ - config_line_t *HTTPTunnelPort_lines; - config_line_t *ControlPort_lines; /**< Ports to listen on for control - * connections. */ - config_line_t *ControlSocket; /**< List of Unix Domain Sockets to listen on - * for control connections. */ - - int ControlSocketsGroupWritable; /**< Boolean: Are control sockets g+rw? */ - int UnixSocksGroupWritable; /**< Boolean: Are SOCKS Unix sockets g+rw? */ - /** Ports to listen on for directory connections. */ - config_line_t *DirPort_lines; - config_line_t *DNSPort_lines; /**< Ports to listen on for DNS requests. */ - - /* MaxMemInQueues value as input by the user. We clean this up to be - * MaxMemInQueues. */ - uint64_t MaxMemInQueues_raw; - uint64_t MaxMemInQueues;/**< If we have more memory than this allocated - * for queues and buffers, run the OOM handler */ - /** Above this value, consider ourselves low on RAM. */ - uint64_t MaxMemInQueues_low_threshold; - - /** @name port booleans - * - * Derived booleans: For server ports and ControlPort, true iff there is a - * non-listener port on an AF_INET or AF_INET6 address of the given type - * configured in one of the _lines options above. - * For client ports, also true if there is a unix socket configured. - * If you are checking for client ports, you may want to use: - * SocksPort_set || TransPort_set || NATDPort_set || DNSPort_set || - * HTTPTunnelPort_set - * rather than SocksPort_set. - * - * @{ - */ - unsigned int ORPort_set : 1; - unsigned int SocksPort_set : 1; - unsigned int TransPort_set : 1; - unsigned int NATDPort_set : 1; - unsigned int ControlPort_set : 1; - unsigned int DirPort_set : 1; - unsigned int DNSPort_set : 1; - unsigned int ExtORPort_set : 1; - unsigned int HTTPTunnelPort_set : 1; - /**@}*/ - - int AssumeReachable; /**< Whether to publish our descriptor regardless. */ - int AuthoritativeDir; /**< Boolean: is this an authoritative directory? */ - int V3AuthoritativeDir; /**< Boolean: is this an authoritative directory - * for version 3 directories? */ - int VersioningAuthoritativeDir; /**< Boolean: is this an authoritative - * directory that's willing to recommend - * versions? */ - int BridgeAuthoritativeDir; /**< Boolean: is this an authoritative directory - * that aggregates bridge descriptors? */ - - /** If set on a bridge relay, it will include this value on a new - * "bridge-distribution-request" line in its bridge descriptor. */ - char *BridgeDistribution; - - /** If set on a bridge authority, it will answer requests on its dirport - * for bridge statuses -- but only if the requests use this password. */ - char *BridgePassword; - /** If BridgePassword is set, this is a SHA256 digest of the basic http - * authenticator for it. Used so we can do a time-independent comparison. */ - char *BridgePassword_AuthDigest_; - - int UseBridges; /**< Boolean: should we start all circuits with a bridge? */ - config_line_t *Bridges; /**< List of bootstrap bridge addresses. */ - - config_line_t *ClientTransportPlugin; /**< List of client - transport plugins. */ - - config_line_t *ServerTransportPlugin; /**< List of client - transport plugins. */ - - /** List of TCP/IP addresses that transports should listen at. */ - config_line_t *ServerTransportListenAddr; - - /** List of options that must be passed to pluggable transports. */ - config_line_t *ServerTransportOptions; - - int BridgeRelay; /**< Boolean: are we acting as a bridge relay? We make - * this explicit so we can change how we behave in the - * future. */ - - /** Boolean: if we know the bridge's digest, should we get new - * descriptors from the bridge authorities or from the bridge itself? */ - int UpdateBridgesFromAuthority; - - int AvoidDiskWrites; /**< Boolean: should we never cache things to disk? - * Not used yet. */ - int ClientOnly; /**< Boolean: should we never evolve into a server role? */ - - int ReducedConnectionPadding; /**< Boolean: Should we try to keep connections - open shorter and pad them less against - connection-level traffic analysis? */ - /** Autobool: if auto, then connection padding will be negotiated by client - * and server. If 0, it will be fully disabled. If 1, the client will still - * pad to the server regardless of server support. */ - int ConnectionPadding; - - /** To what authority types do we publish our descriptor? Choices are - * "v1", "v2", "v3", "bridge", or "". */ - smartlist_t *PublishServerDescriptor; - /** A bitfield of authority types, derived from PublishServerDescriptor. */ - dirinfo_type_t PublishServerDescriptor_; - /** Boolean: do we publish hidden service descriptors to the HS auths? */ - int PublishHidServDescriptors; - int FetchServerDescriptors; /**< Do we fetch server descriptors as normal? */ - int FetchHidServDescriptors; /**< and hidden service descriptors? */ - - int MinUptimeHidServDirectoryV2; /**< As directory authority, accept hidden - * service directories after what time? */ - - int FetchUselessDescriptors; /**< Do we fetch non-running descriptors too? */ - int AllDirActionsPrivate; /**< Should every directory action be sent - * through a Tor circuit? */ - - /** Run in 'tor2web mode'? (I.e. only make client connections to hidden - * services, and use a single hop for all hidden-service-related - * circuits.) */ - int Tor2webMode; - - /** A routerset that should be used when picking RPs for HS circuits. */ - routerset_t *Tor2webRendezvousPoints; - - /** A routerset that should be used when picking middle nodes for HS - * circuits. */ - routerset_t *HSLayer2Nodes; - - /** A routerset that should be used when picking third-hop nodes for HS - * circuits. */ - routerset_t *HSLayer3Nodes; - - /** Onion Services in HiddenServiceSingleHopMode make one-hop (direct) - * circuits between the onion service server, and the introduction and - * rendezvous points. (Onion service descriptors are still posted using - * 3-hop paths, to avoid onion service directories blocking the service.) - * This option makes every hidden service instance hosted by - * this tor instance a Single Onion Service. - * HiddenServiceSingleHopMode requires HiddenServiceNonAnonymousMode to be - * set to 1. - * Use rend_service_allow_non_anonymous_connection() or - * rend_service_reveal_startup_time() instead of using this option directly. - */ - int HiddenServiceSingleHopMode; - /* Makes hidden service clients and servers non-anonymous on this tor - * instance. Allows the non-anonymous HiddenServiceSingleHopMode. Enables - * non-anonymous behaviour in the hidden service protocol. - * Use rend_service_non_anonymous_mode_enabled() instead of using this option - * directly. - */ - int HiddenServiceNonAnonymousMode; - - int ConnLimit; /**< Demanded minimum number of simultaneous connections. */ - int ConnLimit_; /**< Maximum allowed number of simultaneous connections. */ - int ConnLimit_high_thresh; /**< start trying to lower socket usage if we - * have this many. */ - int ConnLimit_low_thresh; /**< try to get down to here after socket - * exhaustion. */ - int RunAsDaemon; /**< If true, run in the background. (Unix only) */ - int FascistFirewall; /**< Whether to prefer ORs reachable on open ports. */ - smartlist_t *FirewallPorts; /**< Which ports our firewall allows - * (strings). */ - config_line_t *ReachableAddresses; /**< IP:ports our firewall allows. */ - config_line_t *ReachableORAddresses; /**< IP:ports for OR conns. */ - config_line_t *ReachableDirAddresses; /**< IP:ports for Dir conns. */ - - int ConstrainedSockets; /**< Shrink xmit and recv socket buffers. */ - uint64_t ConstrainedSockSize; /**< Size of constrained buffers. */ - - /** Whether we should drop exit streams from Tors that we don't know are - * relays. One of "0" (never refuse), "1" (always refuse), or "-1" (do - * what the consensus says, defaulting to 'refuse' if the consensus says - * nothing). */ - int RefuseUnknownExits; - - /** Application ports that require all nodes in circ to have sufficient - * uptime. */ - smartlist_t *LongLivedPorts; - /** Application ports that are likely to be unencrypted and - * unauthenticated; we reject requests for them to prevent the - * user from screwing up and leaking plaintext secrets to an - * observer somewhere on the Internet. */ - smartlist_t *RejectPlaintextPorts; - /** Related to RejectPlaintextPorts above, except this config option - * controls whether we warn (in the log and via a controller status - * event) every time a risky connection is attempted. */ - smartlist_t *WarnPlaintextPorts; - /** Should we try to reuse the same exit node for a given host */ - smartlist_t *TrackHostExits; - int TrackHostExitsExpire; /**< Number of seconds until we expire an - * addressmap */ - config_line_t *AddressMap; /**< List of address map directives. */ - int AutomapHostsOnResolve; /**< If true, when we get a resolve request for a - * hostname ending with one of the suffixes in - * <b>AutomapHostsSuffixes</b>, map it to a - * virtual address. */ - /** List of suffixes for <b>AutomapHostsOnResolve</b>. The special value - * "." means "match everything." */ - smartlist_t *AutomapHostsSuffixes; - int RendPostPeriod; /**< How often do we post each rendezvous service - * descriptor? Remember to publish them independently. */ - int KeepalivePeriod; /**< How often do we send padding cells to keep - * connections alive? */ - int SocksTimeout; /**< How long do we let a socks connection wait - * unattached before we fail it? */ - int LearnCircuitBuildTimeout; /**< If non-zero, we attempt to learn a value - * for CircuitBuildTimeout based on timeout - * history. Use circuit_build_times_disabled() - * rather than checking this value directly. */ - int CircuitBuildTimeout; /**< Cull non-open circuits that were born at - * least this many seconds ago. Used until - * adaptive algorithm learns a new value. */ - int CircuitsAvailableTimeout; /**< Try to have an open circuit for at - least this long after last activity */ - int CircuitStreamTimeout; /**< If non-zero, detach streams from circuits - * and try a new circuit if the stream has been - * waiting for this many seconds. If zero, use - * our default internal timeout schedule. */ - int MaxOnionQueueDelay; /*< DOCDOC */ - int NewCircuitPeriod; /**< How long do we use a circuit before building - * a new one? */ - int MaxCircuitDirtiness; /**< Never use circs that were first used more than - this interval ago. */ - uint64_t BandwidthRate; /**< How much bandwidth, on average, are we willing - * to use in a second? */ - uint64_t BandwidthBurst; /**< How much bandwidth, at maximum, are we willing - * to use in a second? */ - uint64_t MaxAdvertisedBandwidth; /**< How much bandwidth are we willing to - * tell other nodes we have? */ - uint64_t RelayBandwidthRate; /**< How much bandwidth, on average, are we - * willing to use for all relayed conns? */ - uint64_t RelayBandwidthBurst; /**< How much bandwidth, at maximum, will we - * use in a second for all relayed conns? */ - uint64_t PerConnBWRate; /**< Long-term bw on a single TLS conn, if set. */ - uint64_t PerConnBWBurst; /**< Allowed burst on a single TLS conn, if set. */ - int NumCPUs; /**< How many CPUs should we try to use? */ - config_line_t *RendConfigLines; /**< List of configuration lines - * for rendezvous services. */ - config_line_t *HidServAuth; /**< List of configuration lines for client-side - * authorizations for hidden services */ - char *ContactInfo; /**< Contact info to be published in the directory. */ - - int HeartbeatPeriod; /**< Log heartbeat messages after this many seconds - * have passed. */ - int MainloopStats; /**< Log main loop statistics as part of the - * heartbeat messages. */ - - char *HTTPProxy; /**< hostname[:port] to use as http proxy, if any. */ - tor_addr_t HTTPProxyAddr; /**< Parsed IPv4 addr for http proxy, if any. */ - uint16_t HTTPProxyPort; /**< Parsed port for http proxy, if any. */ - char *HTTPProxyAuthenticator; /**< username:password string, if any. */ - - char *HTTPSProxy; /**< hostname[:port] to use as https proxy, if any. */ - tor_addr_t HTTPSProxyAddr; /**< Parsed addr for https proxy, if any. */ - uint16_t HTTPSProxyPort; /**< Parsed port for https proxy, if any. */ - char *HTTPSProxyAuthenticator; /**< username:password string, if any. */ - - char *Socks4Proxy; /**< hostname:port to use as a SOCKS4 proxy, if any. */ - tor_addr_t Socks4ProxyAddr; /**< Derived from Socks4Proxy. */ - uint16_t Socks4ProxyPort; /**< Derived from Socks4Proxy. */ - - char *Socks5Proxy; /**< hostname:port to use as a SOCKS5 proxy, if any. */ - tor_addr_t Socks5ProxyAddr; /**< Derived from Sock5Proxy. */ - uint16_t Socks5ProxyPort; /**< Derived from Socks5Proxy. */ - char *Socks5ProxyUsername; /**< Username for SOCKS5 authentication, if any */ - char *Socks5ProxyPassword; /**< Password for SOCKS5 authentication, if any */ - - /** List of configuration lines for replacement directory authorities. - * If you just want to replace one class of authority at a time, - * use the "Alternate*Authority" options below instead. */ - config_line_t *DirAuthorities; - - /** List of fallback directory servers */ - config_line_t *FallbackDir; - /** Whether to use the default hard-coded FallbackDirs */ - int UseDefaultFallbackDirs; - - /** Weight to apply to all directory authority rates if considering them - * along with fallbackdirs */ - double DirAuthorityFallbackRate; - - /** If set, use these main (currently v3) directory authorities and - * not the default ones. */ - config_line_t *AlternateDirAuthority; - - /** If set, use these bridge authorities and not the default one. */ - config_line_t *AlternateBridgeAuthority; - - config_line_t *MyFamily_lines; /**< Declared family for this OR. */ - config_line_t *MyFamily; /**< Declared family for this OR, normalized */ - config_line_t *NodeFamilies; /**< List of config lines for - * node families */ - smartlist_t *NodeFamilySets; /**< List of parsed NodeFamilies values. */ - config_line_t *AuthDirBadExit; /**< Address policy for descriptors to - * mark as bad exits. */ - config_line_t *AuthDirReject; /**< Address policy for descriptors to - * reject. */ - config_line_t *AuthDirInvalid; /**< Address policy for descriptors to - * never mark as valid. */ - /** @name AuthDir...CC - * - * Lists of country codes to mark as BadExit, or Invalid, or to - * reject entirely. - * - * @{ - */ - smartlist_t *AuthDirBadExitCCs; - smartlist_t *AuthDirInvalidCCs; - smartlist_t *AuthDirRejectCCs; - /**@}*/ - - int AuthDirListBadExits; /**< True iff we should list bad exits, - * and vote for all other exits as good. */ - int AuthDirMaxServersPerAddr; /**< Do not permit more than this - * number of servers per IP address. */ - int AuthDirHasIPv6Connectivity; /**< Boolean: are we on IPv6? */ - int AuthDirPinKeys; /**< Boolean: Do we enforce key-pinning? */ - - /** If non-zero, always vote the Fast flag for any relay advertising - * this amount of capacity or more. */ - uint64_t AuthDirFastGuarantee; - - /** If non-zero, this advertised capacity or more is always sufficient - * to satisfy the bandwidth requirement for the Guard flag. */ - uint64_t AuthDirGuardBWGuarantee; - - char *AccountingStart; /**< How long is the accounting interval, and when - * does it start? */ - uint64_t AccountingMax; /**< How many bytes do we allow per accounting - * interval before hibernation? 0 for "never - * hibernate." */ - /** How do we determine when our AccountingMax has been reached? - * "max" for when in or out reaches AccountingMax - * "sum" for when in plus out reaches AccountingMax - * "in" for when in reaches AccountingMax - * "out" for when out reaches AccountingMax */ - char *AccountingRule_option; - enum { ACCT_MAX, ACCT_SUM, ACCT_IN, ACCT_OUT } AccountingRule; - - /** Base64-encoded hash of accepted passwords for the control system. */ - config_line_t *HashedControlPassword; - /** As HashedControlPassword, but not saved. */ - config_line_t *HashedControlSessionPassword; - - int CookieAuthentication; /**< Boolean: do we enable cookie-based auth for - * the control system? */ - char *CookieAuthFile; /**< Filesystem location of a ControlPort - * authentication cookie. */ - char *ExtORPortCookieAuthFile; /**< Filesystem location of Extended - * ORPort authentication cookie. */ - int CookieAuthFileGroupReadable; /**< Boolean: Is the CookieAuthFile g+r? */ - int ExtORPortCookieAuthFileGroupReadable; /**< Boolean: Is the - * ExtORPortCookieAuthFile g+r? */ - int LeaveStreamsUnattached; /**< Boolean: Does Tor attach new streams to - * circuits itself (0), or does it expect a controller - * to cope? (1) */ - int DisablePredictedCircuits; /**< Boolean: does Tor preemptively - * make circuits in the background (0), - * or not (1)? */ - - /** Process specifier for a controller that ‘owns’ this Tor - * instance. Tor will terminate if its owning controller does. */ - char *OwningControllerProcess; - /** FD specifier for a controller that owns this Tor instance. */ - int OwningControllerFD; - - int ShutdownWaitLength; /**< When we get a SIGINT and we're a server, how - * long do we wait before exiting? */ - char *SafeLogging; /**< Contains "relay", "1", "0" (meaning no scrubbing). */ - - /* Derived from SafeLogging */ - enum { - SAFELOG_SCRUB_ALL, SAFELOG_SCRUB_RELAY, SAFELOG_SCRUB_NONE - } SafeLogging_; - - int Sandbox; /**< Boolean: should sandboxing be enabled? */ - int SafeSocks; /**< Boolean: should we outright refuse application - * connections that use socks4 or socks5-with-local-dns? */ - int ProtocolWarnings; /**< Boolean: when other parties screw up the Tor - * protocol, is it a warn or an info in our logs? */ - int TestSocks; /**< Boolean: when we get a socks connection, do we loudly - * log whether it was DNS-leaking or not? */ - int HardwareAccel; /**< Boolean: Should we enable OpenSSL hardware - * acceleration where available? */ - /** Token Bucket Refill resolution in milliseconds. */ - int TokenBucketRefillInterval; - char *AccelName; /**< Optional hardware acceleration engine name. */ - char *AccelDir; /**< Optional hardware acceleration engine search dir. */ - - /** Boolean: Do we try to enter from a smallish number - * of fixed nodes? */ - int UseEntryGuards_option; - /** Internal variable to remember whether we're actually acting on - * UseEntryGuards_option -- when we're a non-anonymous Tor2web client or - * Single Onion Service, it is always false, otherwise we use the value of - * UseEntryGuards_option. */ - int UseEntryGuards; - - int NumEntryGuards; /**< How many entry guards do we try to establish? */ - - /** If 1, we use any guardfraction information we see in the - * consensus. If 0, we don't. If -1, let the consensus parameter - * decide. */ - int UseGuardFraction; - - int NumDirectoryGuards; /**< How many dir guards do we try to establish? - * If 0, use value from NumEntryGuards. */ - int NumPrimaryGuards; /**< How many primary guards do we want? */ - - int RephistTrackTime; /**< How many seconds do we keep rephist info? */ - /** Should we always fetch our dir info on the mirror schedule (which - * means directly from the authorities) no matter our other config? */ - int FetchDirInfoEarly; - - /** Should we fetch our dir info at the start of the consensus period? */ - int FetchDirInfoExtraEarly; - - int DirCache; /**< Cache all directory documents and accept requests via - * tunnelled dir conns from clients. If 1, enabled (default); - * If 0, disabled. */ - - char *VirtualAddrNetworkIPv4; /**< Address and mask to hand out for virtual - * MAPADDRESS requests for IPv4 addresses */ - char *VirtualAddrNetworkIPv6; /**< Address and mask to hand out for virtual - * MAPADDRESS requests for IPv6 addresses */ - int ServerDNSSearchDomains; /**< Boolean: If set, we don't force exit - * addresses to be FQDNs, but rather search for them in - * the local domains. */ - int ServerDNSDetectHijacking; /**< Boolean: If true, check for DNS failure - * hijacking. */ - int ServerDNSRandomizeCase; /**< Boolean: Use the 0x20-hack to prevent - * DNS poisoning attacks. */ - char *ServerDNSResolvConfFile; /**< If provided, we configure our internal - * resolver from the file here rather than from - * /etc/resolv.conf (Unix) or the registry (Windows). */ - char *DirPortFrontPage; /**< This is a full path to a file with an html - disclaimer. This allows a server administrator to show - that they're running Tor and anyone visiting their server - will know this without any specialized knowledge. */ - int DisableDebuggerAttachment; /**< Currently Linux only specific attempt to - disable ptrace; needs BSD testing. */ - /** Boolean: if set, we start even if our resolv.conf file is missing - * or broken. */ - int ServerDNSAllowBrokenConfig; - /** Boolean: if set, then even connections to private addresses will get - * rate-limited. */ - int CountPrivateBandwidth; - smartlist_t *ServerDNSTestAddresses; /**< A list of addresses that definitely - * should be resolvable. Used for - * testing our DNS server. */ - int EnforceDistinctSubnets; /**< If true, don't allow multiple routers in the - * same network zone in the same circuit. */ - int AllowNonRFC953Hostnames; /**< If true, we allow connections to hostnames - * with weird characters. */ - /** If true, we try resolving hostnames with weird characters. */ - int ServerDNSAllowNonRFC953Hostnames; - - /** If true, we try to download extra-info documents (and we serve them, - * if we are a cache). For authorities, this is always true. */ - int DownloadExtraInfo; - - /** If true, we're configured to collect statistics on clients - * requesting network statuses from us as directory. */ - int DirReqStatistics_option; - /** Internal variable to remember whether we're actually acting on - * DirReqStatistics_option -- yes if it's set and we're a server, else no. */ - int DirReqStatistics; - - /** If true, the user wants us to collect statistics on port usage. */ - int ExitPortStatistics; - - /** If true, the user wants us to collect connection statistics. */ - int ConnDirectionStatistics; - - /** If true, the user wants us to collect cell statistics. */ - int CellStatistics; - - /** If true, the user wants us to collect padding statistics. */ - int PaddingStatistics; - - /** If true, the user wants us to collect statistics as entry node. */ - int EntryStatistics; - - /** If true, the user wants us to collect statistics as hidden service - * directory, introduction point, or rendezvous point. */ - int HiddenServiceStatistics_option; - /** Internal variable to remember whether we're actually acting on - * HiddenServiceStatistics_option -- yes if it's set and we're a server, - * else no. */ - int HiddenServiceStatistics; - - /** If true, include statistics file contents in extra-info documents. */ - int ExtraInfoStatistics; - - /** If true, do not believe anybody who tells us that a domain resolves - * to an internal address, or that an internal address has a PTR mapping. - * Helps avoid some cross-site attacks. */ - int ClientDNSRejectInternalAddresses; - - /** If true, do not accept any requests to connect to internal addresses - * over randomly chosen exits. */ - int ClientRejectInternalAddresses; - - /** If true, clients may connect over IPv4. If false, they will avoid - * connecting over IPv4. We enforce this for OR and Dir connections. */ - int ClientUseIPv4; - /** If true, clients may connect over IPv6. If false, they will avoid - * connecting over IPv4. We enforce this for OR and Dir connections. - * Use fascist_firewall_use_ipv6() instead of accessing this value - * directly. */ - int ClientUseIPv6; - /** If true, prefer an IPv6 OR port over an IPv4 one for entry node - * connections. If auto, bridge clients prefer IPv6, and other clients - * prefer IPv4. Use node_ipv6_or_preferred() instead of accessing this value - * directly. */ - int ClientPreferIPv6ORPort; - /** If true, prefer an IPv6 directory port over an IPv4 one for direct - * directory connections. If auto, bridge clients prefer IPv6, and other - * clients prefer IPv4. Use fascist_firewall_prefer_ipv6_dirport() instead of - * accessing this value directly. */ - int ClientPreferIPv6DirPort; - - /** The length of time that we think a consensus should be fresh. */ - int V3AuthVotingInterval; - /** The length of time we think it will take to distribute votes. */ - int V3AuthVoteDelay; - /** The length of time we think it will take to distribute signatures. */ - int V3AuthDistDelay; - /** The number of intervals we think a consensus should be valid. */ - int V3AuthNIntervalsValid; - - /** Should advertise and sign consensuses with a legacy key, for key - * migration purposes? */ - int V3AuthUseLegacyKey; - - /** Location of bandwidth measurement file */ - char *V3BandwidthsFile; - - /** Location of guardfraction file */ - char *GuardfractionFile; - - /** Authority only: key=value pairs that we add to our networkstatus - * consensus vote on the 'params' line. */ - char *ConsensusParams; - - /** Authority only: minimum number of measured bandwidths we must see - * before we only believe measured bandwidths to assign flags. */ - int MinMeasuredBWsForAuthToIgnoreAdvertised; - - /** The length of time that we think an initial consensus should be fresh. - * Only altered on testing networks. */ - int TestingV3AuthInitialVotingInterval; - - /** The length of time we think it will take to distribute initial votes. - * Only altered on testing networks. */ - int TestingV3AuthInitialVoteDelay; - - /** The length of time we think it will take to distribute initial - * signatures. Only altered on testing networks.*/ - int TestingV3AuthInitialDistDelay; - - /** Offset in seconds added to the starting time for consensus - voting. Only altered on testing networks. */ - int TestingV3AuthVotingStartOffset; - - /** If an authority has been around for less than this amount of time, it - * does not believe its reachability information is accurate. Only - * altered on testing networks. */ - int TestingAuthDirTimeToLearnReachability; - - /** Clients don't download any descriptor this recent, since it will - * probably not have propagated to enough caches. Only altered on testing - * networks. */ - int TestingEstimatedDescriptorPropagationTime; - - /** Schedule for when servers should download things in general. Only - * altered on testing networks. */ - int TestingServerDownloadInitialDelay; - - /** Schedule for when clients should download things in general. Only - * altered on testing networks. */ - int TestingClientDownloadInitialDelay; - - /** Schedule for when servers should download consensuses. Only altered - * on testing networks. */ - int TestingServerConsensusDownloadInitialDelay; - - /** Schedule for when clients should download consensuses. Only altered - * on testing networks. */ - int TestingClientConsensusDownloadInitialDelay; - - /** Schedule for when clients should download consensuses from authorities - * if they are bootstrapping (that is, they don't have a usable, reasonably - * live consensus). Only used by clients fetching from a list of fallback - * directory mirrors. - * - * This schedule is incremented by (potentially concurrent) connection - * attempts, unlike other schedules, which are incremented by connection - * failures. Only altered on testing networks. */ - int ClientBootstrapConsensusAuthorityDownloadInitialDelay; - - /** Schedule for when clients should download consensuses from fallback - * directory mirrors if they are bootstrapping (that is, they don't have a - * usable, reasonably live consensus). Only used by clients fetching from a - * list of fallback directory mirrors. - * - * This schedule is incremented by (potentially concurrent) connection - * attempts, unlike other schedules, which are incremented by connection - * failures. Only altered on testing networks. */ - int ClientBootstrapConsensusFallbackDownloadInitialDelay; - - /** Schedule for when clients should download consensuses from authorities - * if they are bootstrapping (that is, they don't have a usable, reasonably - * live consensus). Only used by clients which don't have or won't fetch - * from a list of fallback directory mirrors. - * - * This schedule is incremented by (potentially concurrent) connection - * attempts, unlike other schedules, which are incremented by connection - * failures. Only altered on testing networks. */ - int ClientBootstrapConsensusAuthorityOnlyDownloadInitialDelay; - - /** Schedule for when clients should download bridge descriptors. Only - * altered on testing networks. */ - int TestingBridgeDownloadInitialDelay; - - /** Schedule for when clients should download bridge descriptors when they - * have no running bridges. Only altered on testing networks. */ - int TestingBridgeBootstrapDownloadInitialDelay; - - /** When directory clients have only a few descriptors to request, they - * batch them until they have more, or until this amount of time has - * passed. Only altered on testing networks. */ - int TestingClientMaxIntervalWithoutRequest; - - /** How long do we let a directory connection stall before expiring - * it? Only altered on testing networks. */ - int TestingDirConnectionMaxStall; - - /** How many simultaneous in-progress connections will we make when trying - * to fetch a consensus before we wait for one to complete, timeout, or - * error out? Only altered on testing networks. */ - int ClientBootstrapConsensusMaxInProgressTries; - - /** If true, we take part in a testing network. Change the defaults of a - * couple of other configuration options and allow to change the values - * of certain configuration options. */ - int TestingTorNetwork; - - /** Minimum value for the Exit flag threshold on testing networks. */ - uint64_t TestingMinExitFlagThreshold; - - /** Minimum value for the Fast flag threshold on testing networks. */ - uint64_t TestingMinFastFlagThreshold; - - /** Relays in a testing network which should be voted Exit - * regardless of exit policy. */ - routerset_t *TestingDirAuthVoteExit; - int TestingDirAuthVoteExitIsStrict; - - /** Relays in a testing network which should be voted Guard - * regardless of uptime and bandwidth. */ - routerset_t *TestingDirAuthVoteGuard; - int TestingDirAuthVoteGuardIsStrict; - - /** Relays in a testing network which should be voted HSDir - * regardless of uptime and DirPort. */ - routerset_t *TestingDirAuthVoteHSDir; - int TestingDirAuthVoteHSDirIsStrict; - - /** Enable CONN_BW events. Only altered on testing networks. */ - int TestingEnableConnBwEvent; - - /** Enable CELL_STATS events. Only altered on testing networks. */ - int TestingEnableCellStatsEvent; - - /** If true, and we have GeoIP data, and we're a bridge, keep a per-country - * count of how many client addresses have contacted us so that we can help - * the bridge authority guess which countries have blocked access to us. */ - int BridgeRecordUsageByCountry; - - /** Optionally, IPv4 and IPv6 GeoIP data. */ - char *GeoIPFile; - char *GeoIPv6File; - - /** Autobool: if auto, then any attempt to Exclude{Exit,}Nodes a particular - * country code will exclude all nodes in ?? and A1. If true, all nodes in - * ?? and A1 are excluded. Has no effect if we don't know any GeoIP data. */ - int GeoIPExcludeUnknown; - - /** If true, SIGHUP should reload the torrc. Sometimes controllers want - * to make this false. */ - int ReloadTorrcOnSIGHUP; - - /* The main parameter for picking circuits within a connection. - * - * If this value is positive, when picking a cell to relay on a connection, - * we always relay from the circuit whose weighted cell count is lowest. - * Cells are weighted exponentially such that if one cell is sent - * 'CircuitPriorityHalflife' seconds before another, it counts for half as - * much. - * - * If this value is zero, we're disabling the cell-EWMA algorithm. - * - * If this value is negative, we're using the default approach - * according to either Tor or a parameter set in the consensus. - */ - double CircuitPriorityHalflife; - - /** Set to true if the TestingTorNetwork configuration option is set. - * This is used so that options_validate() has a chance to realize that - * the defaults have changed. */ - int UsingTestNetworkDefaults_; - - /** If 1, we try to use microdescriptors to build circuits. If 0, we don't. - * If -1, Tor decides. */ - int UseMicrodescriptors; - - /** File where we should write the ControlPort. */ - char *ControlPortWriteToFile; - /** Should that file be group-readable? */ - int ControlPortFileGroupReadable; - -#define MAX_MAX_CLIENT_CIRCUITS_PENDING 1024 - /** Maximum number of non-open general-purpose origin circuits to allow at - * once. */ - int MaxClientCircuitsPending; - - /** If 1, we always send optimistic data when it's supported. If 0, we - * never use it. If -1, we do what the consensus says. */ - int OptimisticData; - - /** If 1, we accept and launch no external network connections, except on - * control ports. */ - int DisableNetwork; - - /** - * Parameters for path-bias detection. - * @{ - * These options override the default behavior of Tor's (**currently - * experimental**) path bias detection algorithm. To try to find broken or - * misbehaving guard nodes, Tor looks for nodes where more than a certain - * fraction of circuits through that guard fail to get built. - * - * The PathBiasCircThreshold option controls how many circuits we need to - * build through a guard before we make these checks. The - * PathBiasNoticeRate, PathBiasWarnRate and PathBiasExtremeRate options - * control what fraction of circuits must succeed through a guard so we - * won't write log messages. If less than PathBiasExtremeRate circuits - * succeed *and* PathBiasDropGuards is set to 1, we disable use of that - * guard. - * - * When we have seen more than PathBiasScaleThreshold circuits through a - * guard, we scale our observations by 0.5 (governed by the consensus) so - * that new observations don't get swamped by old ones. - * - * By default, or if a negative value is provided for one of these options, - * Tor uses reasonable defaults from the networkstatus consensus document. - * If no defaults are available there, these options default to 150, .70, - * .50, .30, 0, and 300 respectively. - */ - int PathBiasCircThreshold; - double PathBiasNoticeRate; - double PathBiasWarnRate; - double PathBiasExtremeRate; - int PathBiasDropGuards; - int PathBiasScaleThreshold; - /** @} */ - - /** - * Parameters for path-bias use detection - * @{ - * Similar to the above options, these options override the default behavior - * of Tor's (**currently experimental**) path use bias detection algorithm. - * - * Where as the path bias parameters govern thresholds for successfully - * building circuits, these four path use bias parameters govern thresholds - * only for circuit usage. Circuits which receive no stream usage are not - * counted by this detection algorithm. A used circuit is considered - * successful if it is capable of carrying streams or otherwise receiving - * well-formed responses to RELAY cells. - * - * By default, or if a negative value is provided for one of these options, - * Tor uses reasonable defaults from the networkstatus consensus document. - * If no defaults are available there, these options default to 20, .80, - * .60, and 100, respectively. - */ - int PathBiasUseThreshold; - double PathBiasNoticeUseRate; - double PathBiasExtremeUseRate; - int PathBiasScaleUseThreshold; - /** @} */ - - int IPv6Exit; /**< Do we support exiting to IPv6 addresses? */ - - /** Fraction: */ - double PathsNeededToBuildCircuits; - - /** What expiry time shall we place on our SSL certs? "0" means we - * should guess a suitable value. */ - int SSLKeyLifetime; - - /** How long (seconds) do we keep a guard before picking a new one? */ - int GuardLifetime; - - /** Is this an exit node? This is a tristate, where "1" means "yes, and use - * the default exit policy if none is given" and "0" means "no; exit policy - * is 'reject *'" and "auto" (-1) means "same as 1, but warn the user." - * - * XXXX Eventually, the default will be 0. */ - int ExitRelay; - - /** For how long (seconds) do we declare our signing keys to be valid? */ - int SigningKeyLifetime; - /** For how long (seconds) do we declare our link keys to be valid? */ - int TestingLinkCertLifetime; - /** For how long (seconds) do we declare our auth keys to be valid? */ - int TestingAuthKeyLifetime; - - /** How long before signing keys expire will we try to make a new one? */ - int TestingSigningKeySlop; - /** How long before link keys expire will we try to make a new one? */ - int TestingLinkKeySlop; - /** How long before auth keys expire will we try to make a new one? */ - int TestingAuthKeySlop; - - /** Force use of offline master key features: never generate a master - * ed25519 identity key except from tor --keygen */ - int OfflineMasterKey; - - enum { - FORCE_PASSPHRASE_AUTO=0, - FORCE_PASSPHRASE_ON, - FORCE_PASSPHRASE_OFF - } keygen_force_passphrase; - int use_keygen_passphrase_fd; - int keygen_passphrase_fd; - int change_key_passphrase; - char *master_key_fname; - - /** Autobool: Do we try to retain capabilities if we can? */ - int KeepBindCapabilities; - - /** Maximum total size of unparseable descriptors to log during the - * lifetime of this Tor process. - */ - uint64_t MaxUnparseableDescSizeToLog; - - /** Bool (default: 1): Switch for the shared random protocol. Only - * relevant to a directory authority. If off, the authority won't - * participate in the protocol. If on (default), a flag is added to the - * vote indicating participation. */ - int AuthDirSharedRandomness; - - /** If 1, we skip all OOS checks. */ - int DisableOOSCheck; - - /** Autobool: Should we include Ed25519 identities in extend2 cells? - * If -1, we should do whatever the consensus parameter says. */ - int ExtendByEd25519ID; - - /** Bool (default: 1): When testing routerinfos as a directory authority, - * do we enforce Ed25519 identity match? */ - /* NOTE: remove this option someday. */ - int AuthDirTestEd25519LinkKeys; - - /** Bool (default: 0): Tells if a %include was used on torrc */ - int IncludeUsed; - - /** The seconds after expiration which we as a relay should keep old - * consensuses around so that we can generate diffs from them. If 0, - * use the default. */ - int MaxConsensusAgeForDiffs; - - /** Bool (default: 0). Tells Tor to never try to exec another program. - */ - int NoExec; - - /** Have the KIST scheduler run every X milliseconds. If less than zero, do - * not use the KIST scheduler but use the old vanilla scheduler instead. If - * zero, do what the consensus says and fall back to using KIST as if this is - * set to "10 msec" if the consensus doesn't say anything. */ - int KISTSchedRunInterval; - - /** A multiplier for the KIST per-socket limit calculation. */ - double KISTSockBufSizeFactor; - - /** The list of scheduler type string ordered by priority that is first one - * has to be tried first. Default: KIST,KISTLite,Vanilla */ - smartlist_t *Schedulers; - /* An ordered list of scheduler_types mapped from Schedulers. */ - smartlist_t *SchedulerTypes_; - - /** List of files that were opened by %include in torrc and torrc-defaults */ - smartlist_t *FilesOpenedByIncludes; - - /** If true, Tor shouldn't install any posix signal handlers, since it is - * running embedded inside another process. - */ - int DisableSignalHandlers; - - /** Autobool: Is the circuit creation DoS mitigation subsystem enabled? */ - int DoSCircuitCreationEnabled; - /** Minimum concurrent connection needed from one single address before any - * defense is used. */ - int DoSCircuitCreationMinConnections; - /** Circuit rate used to refill the token bucket. */ - int DoSCircuitCreationRate; - /** Maximum allowed burst of circuits. Reaching that value, the address is - * detected as malicious and a defense might be used. */ - int DoSCircuitCreationBurst; - /** When an address is marked as malicous, what defense should be used - * against it. See the dos_cc_defense_type_t enum. */ - int DoSCircuitCreationDefenseType; - /** For how much time (in seconds) the defense is applicable for a malicious - * address. A random time delta is added to the defense time of an address - * which will be between 1 second and half of this value. */ - int DoSCircuitCreationDefenseTimePeriod; - - /** Autobool: Is the DoS connection mitigation subsystem enabled? */ - int DoSConnectionEnabled; - /** Maximum concurrent connection allowed per address. */ - int DoSConnectionMaxConcurrentCount; - /** When an address is reaches the maximum count, what defense should be - * used against it. See the dos_conn_defense_type_t enum. */ - int DoSConnectionDefenseType; - - /** Autobool: Do we refuse single hop client rendezvous? */ - int DoSRefuseSingleHopClientRendezvous; -} or_options_t; - -#define LOG_PROTOCOL_WARN (get_protocol_warning_severity_level()) - -/** Persistent state for an onion router, as saved to disk. */ -typedef struct { - uint32_t magic_; - /** The time at which we next plan to write the state to the disk. Equal to - * TIME_MAX if there are no savable changes, 0 if there are changes that - * should be saved right away. */ - time_t next_write; - - /** When was the state last written to disk? */ - time_t LastWritten; - - /** Fields for accounting bandwidth use. */ - time_t AccountingIntervalStart; - uint64_t AccountingBytesReadInInterval; - uint64_t AccountingBytesWrittenInInterval; - int AccountingSecondsActive; - int AccountingSecondsToReachSoftLimit; - time_t AccountingSoftLimitHitAt; - uint64_t AccountingBytesAtSoftLimit; - uint64_t AccountingExpectedUsage; - - /** A list of Entry Guard-related configuration lines. (pre-prop271) */ - config_line_t *EntryGuards; - - /** A list of guard-related configuration lines. (post-prop271) */ - config_line_t *Guard; - - config_line_t *TransportProxies; - - /** Cached revision counters for active hidden services on this host */ - config_line_t *HidServRevCounter; - - /** These fields hold information on the history of bandwidth usage for - * servers. The "Ends" fields hold the time when we last updated the - * bandwidth usage. The "Interval" fields hold the granularity, in seconds, - * of the entries of Values. The "Values" lists hold decimal string - * representations of the number of bytes read or written in each - * interval. The "Maxima" list holds decimal strings describing the highest - * rate achieved during the interval. - */ - time_t BWHistoryReadEnds; - int BWHistoryReadInterval; - smartlist_t *BWHistoryReadValues; - smartlist_t *BWHistoryReadMaxima; - time_t BWHistoryWriteEnds; - int BWHistoryWriteInterval; - smartlist_t *BWHistoryWriteValues; - smartlist_t *BWHistoryWriteMaxima; - time_t BWHistoryDirReadEnds; - int BWHistoryDirReadInterval; - smartlist_t *BWHistoryDirReadValues; - smartlist_t *BWHistoryDirReadMaxima; - time_t BWHistoryDirWriteEnds; - int BWHistoryDirWriteInterval; - smartlist_t *BWHistoryDirWriteValues; - smartlist_t *BWHistoryDirWriteMaxima; - - /** Build time histogram */ - config_line_t * BuildtimeHistogram; - int TotalBuildTimes; - int CircuitBuildAbandonedCount; - - /** What version of Tor wrote this state file? */ - char *TorVersion; - - /** Holds any unrecognized values we found in the state file, in the order - * in which we found them. */ - config_line_t *ExtraLines; - - /** When did we last rotate our onion key? "0" for 'no idea'. */ - time_t LastRotatedOnionKey; -} or_state_t; - -#define MAX_SOCKS_REPLY_LEN 1024 -#define MAX_SOCKS_ADDR_LEN 256 -#define SOCKS_NO_AUTH 0x00 -#define SOCKS_USER_PASS 0x02 - -/** Please open a TCP connection to this addr:port. */ -#define SOCKS_COMMAND_CONNECT 0x01 -/** Please turn this FQDN into an IP address, privately. */ -#define SOCKS_COMMAND_RESOLVE 0xF0 -/** Please turn this IP address into an FQDN, privately. */ -#define SOCKS_COMMAND_RESOLVE_PTR 0xF1 - -/* || 0 is for -Wparentheses-equality (-Wall?) appeasement under clang */ -#define SOCKS_COMMAND_IS_CONNECT(c) (((c)==SOCKS_COMMAND_CONNECT) || 0) -#define SOCKS_COMMAND_IS_RESOLVE(c) ((c)==SOCKS_COMMAND_RESOLVE || \ - (c)==SOCKS_COMMAND_RESOLVE_PTR) - -/** State of a SOCKS request from a user to an OP. Also used to encode other - * information for non-socks user request (such as those on TransPort and - * DNSPort) */ -struct socks_request_t { - /** Which version of SOCKS did the client use? One of "0, 4, 5" -- where - * 0 means that no socks handshake ever took place, and this is just a - * stub connection (e.g. see connection_ap_make_link()). */ - uint8_t socks_version; - /** If using socks5 authentication, which authentication type did we - * negotiate? currently we support 0 (no authentication) and 2 - * (username/password). */ - uint8_t auth_type; - /** What is this stream's goal? One of the SOCKS_COMMAND_* values */ - uint8_t command; - /** Which kind of listener created this stream? */ - uint8_t listener_type; - size_t replylen; /**< Length of <b>reply</b>. */ - uint8_t reply[MAX_SOCKS_REPLY_LEN]; /**< Write an entry into this string if - * we want to specify our own socks reply, - * rather than using the default socks4 or - * socks5 socks reply. We use this for the - * two-stage socks5 handshake. - */ - char address[MAX_SOCKS_ADDR_LEN]; /**< What address did the client ask to - connect to/resolve? */ - uint16_t port; /**< What port did the client ask to connect to? */ - unsigned int has_finished : 1; /**< Has the SOCKS handshake finished? Used to - * make sure we send back a socks reply for - * every connection. */ - unsigned int got_auth : 1; /**< Have we received any authentication data? */ - /** If this is set, we will choose "no authentication" instead of - * "username/password" authentication if both are offered. Used as input to - * parse_socks. */ - unsigned int socks_prefer_no_auth : 1; - - /** Number of bytes in username; 0 if username is NULL */ - size_t usernamelen; - /** Number of bytes in password; 0 if password is NULL */ - uint8_t passwordlen; - /** The negotiated username value if any (for socks5), or the entire - * authentication string (for socks4). This value is NOT nul-terminated; - * see usernamelen for its length. */ - char *username; - /** The negotiated password value if any (for socks5). This value is NOT - * nul-terminated; see passwordlen for its length. */ - char *password; -}; - -/********************************* circuitbuild.c **********************/ - -/** How many hops does a general-purpose circuit have by default? */ -#define DEFAULT_ROUTE_LEN 3 - -/* Circuit Build Timeout "public" structures. */ - -/** Precision multiplier for the Bw weights */ -#define BW_WEIGHT_SCALE 10000 -#define BW_MIN_WEIGHT_SCALE 1 -#define BW_MAX_WEIGHT_SCALE INT32_MAX - -/** Total size of the circuit timeout history to accumulate. - * 1000 is approx 2.5 days worth of continual-use circuits. */ -#define CBT_NCIRCUITS_TO_OBSERVE 1000 - -/** Width of the histogram bins in milliseconds */ -#define CBT_BIN_WIDTH ((build_time_t)50) - -/** Number of modes to use in the weighted-avg computation of Xm */ -#define CBT_DEFAULT_NUM_XM_MODES 3 -#define CBT_MIN_NUM_XM_MODES 1 -#define CBT_MAX_NUM_XM_MODES 20 - -/** A build_time_t is milliseconds */ -typedef uint32_t build_time_t; - -/** - * CBT_BUILD_ABANDONED is our flag value to represent a force-closed - * circuit (Aka a 'right-censored' pareto value). - */ -#define CBT_BUILD_ABANDONED ((build_time_t)(INT32_MAX-1)) -#define CBT_BUILD_TIME_MAX ((build_time_t)(INT32_MAX)) - -/** Save state every 10 circuits */ -#define CBT_SAVE_STATE_EVERY 10 - -/* Circuit build times consensus parameters */ - -/** - * How long to wait before actually closing circuits that take too long to - * build in terms of CDF quantile. - */ -#define CBT_DEFAULT_CLOSE_QUANTILE 95 -#define CBT_MIN_CLOSE_QUANTILE CBT_MIN_QUANTILE_CUTOFF -#define CBT_MAX_CLOSE_QUANTILE CBT_MAX_QUANTILE_CUTOFF - -/** - * How many circuits count as recent when considering if the - * connection has gone gimpy or changed. - */ -#define CBT_DEFAULT_RECENT_CIRCUITS 20 -#define CBT_MIN_RECENT_CIRCUITS 3 -#define CBT_MAX_RECENT_CIRCUITS 1000 - -/** - * Maximum count of timeouts that finish the first hop in the past - * RECENT_CIRCUITS before calculating a new timeout. - * - * This tells us whether to abandon timeout history and set - * the timeout back to whatever circuit_build_times_get_initial_timeout() - * gives us. - */ -#define CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT (CBT_DEFAULT_RECENT_CIRCUITS*9/10) -#define CBT_MIN_MAX_RECENT_TIMEOUT_COUNT 3 -#define CBT_MAX_MAX_RECENT_TIMEOUT_COUNT 10000 - -/** Minimum circuits before estimating a timeout */ -#define CBT_DEFAULT_MIN_CIRCUITS_TO_OBSERVE 100 -#define CBT_MIN_MIN_CIRCUITS_TO_OBSERVE 1 -#define CBT_MAX_MIN_CIRCUITS_TO_OBSERVE 10000 - -/** Cutoff percentile on the CDF for our timeout estimation. */ -#define CBT_DEFAULT_QUANTILE_CUTOFF 80 -#define CBT_MIN_QUANTILE_CUTOFF 10 -#define CBT_MAX_QUANTILE_CUTOFF 99 -double circuit_build_times_quantile_cutoff(void); - -/** How often in seconds should we build a test circuit */ -#define CBT_DEFAULT_TEST_FREQUENCY 10 -#define CBT_MIN_TEST_FREQUENCY 1 -#define CBT_MAX_TEST_FREQUENCY INT32_MAX - -/** Lowest allowable value for CircuitBuildTimeout in milliseconds */ -#define CBT_DEFAULT_TIMEOUT_MIN_VALUE (1500) -#define CBT_MIN_TIMEOUT_MIN_VALUE 500 -#define CBT_MAX_TIMEOUT_MIN_VALUE INT32_MAX - -/** Initial circuit build timeout in milliseconds */ -#define CBT_DEFAULT_TIMEOUT_INITIAL_VALUE (60*1000) -#define CBT_MIN_TIMEOUT_INITIAL_VALUE CBT_MIN_TIMEOUT_MIN_VALUE -#define CBT_MAX_TIMEOUT_INITIAL_VALUE INT32_MAX -int32_t circuit_build_times_initial_timeout(void); - -#if CBT_DEFAULT_MAX_RECENT_TIMEOUT_COUNT < CBT_MIN_MAX_RECENT_TIMEOUT_COUNT -#error "RECENT_CIRCUITS is set too low." -#endif - -/** Information about the state of our local network connection */ -typedef struct { - /** The timestamp we last completed a TLS handshake or received a cell */ - time_t network_last_live; - /** If the network is not live, how many timeouts has this caused? */ - int nonlive_timeouts; - /** Circular array of circuits that have made it to the first hop. Slot is - * 1 if circuit timed out, 0 if circuit succeeded */ - int8_t *timeouts_after_firsthop; - /** Number of elements allocated for the above array */ - int num_recent_circs; - /** Index into circular array. */ - int after_firsthop_idx; -} network_liveness_t; - -typedef struct circuit_build_times_s circuit_build_times_t; - -/********************************* config.c ***************************/ - -/** An error from options_trial_assign() or options_init_from_string(). */ -typedef enum setopt_err_t { - SETOPT_OK = 0, - SETOPT_ERR_MISC = -1, - SETOPT_ERR_PARSE = -2, - SETOPT_ERR_TRANSITION = -3, - SETOPT_ERR_SETTING = -4, -} setopt_err_t; - -/********************************* connection_edge.c *************************/ - -/** Enumerates possible origins of a client-side address mapping. */ -typedef enum { - /** We're remapping this address because the controller told us to. */ - ADDRMAPSRC_CONTROLLER, - /** We're remapping this address because of an AutomapHostsOnResolve - * configuration. */ - ADDRMAPSRC_AUTOMAP, - /** We're remapping this address because our configuration (via torrc, the - * command line, or a SETCONF command) told us to. */ - ADDRMAPSRC_TORRC, - /** We're remapping this address because we have TrackHostExit configured, - * and we want to remember to use the same exit next time. */ - ADDRMAPSRC_TRACKEXIT, - /** We're remapping this address because we got a DNS resolution from a - * Tor server that told us what its value was. */ - ADDRMAPSRC_DNS, - - /** No remapping has occurred. This isn't a possible value for an - * addrmap_entry_t; it's used as a null value when we need to answer "Why - * did this remapping happen." */ - ADDRMAPSRC_NONE -} addressmap_entry_source_t; -#define addressmap_entry_source_bitfield_t ENUM_BF(addressmap_entry_source_t) - -/********************************* control.c ***************************/ - -/** Used to indicate the type of a circuit event passed to the controller. - * The various types are defined in control-spec.txt */ -typedef enum circuit_status_event_t { - CIRC_EVENT_LAUNCHED = 0, - CIRC_EVENT_BUILT = 1, - CIRC_EVENT_EXTENDED = 2, - CIRC_EVENT_FAILED = 3, - CIRC_EVENT_CLOSED = 4, -} circuit_status_event_t; - -/** Used to indicate the type of a CIRC_MINOR event passed to the controller. - * The various types are defined in control-spec.txt . */ -typedef enum circuit_status_minor_event_t { - CIRC_MINOR_EVENT_PURPOSE_CHANGED, - CIRC_MINOR_EVENT_CANNIBALIZED, -} circuit_status_minor_event_t; - -/** Used to indicate the type of a stream event passed to the controller. - * The various types are defined in control-spec.txt */ -typedef enum stream_status_event_t { - STREAM_EVENT_SENT_CONNECT = 0, - STREAM_EVENT_SENT_RESOLVE = 1, - STREAM_EVENT_SUCCEEDED = 2, - STREAM_EVENT_FAILED = 3, - STREAM_EVENT_CLOSED = 4, - STREAM_EVENT_NEW = 5, - STREAM_EVENT_NEW_RESOLVE = 6, - STREAM_EVENT_FAILED_RETRIABLE = 7, - STREAM_EVENT_REMAP = 8 -} stream_status_event_t; - -/** Used to indicate the type of an OR connection event passed to the - * controller. The various types are defined in control-spec.txt */ -typedef enum or_conn_status_event_t { - OR_CONN_EVENT_LAUNCHED = 0, - OR_CONN_EVENT_CONNECTED = 1, - OR_CONN_EVENT_FAILED = 2, - OR_CONN_EVENT_CLOSED = 3, - OR_CONN_EVENT_NEW = 4, -} or_conn_status_event_t; - -/** Used to indicate the type of a buildtime event */ -typedef enum buildtimeout_set_event_t { - BUILDTIMEOUT_SET_EVENT_COMPUTED = 0, - BUILDTIMEOUT_SET_EVENT_RESET = 1, - BUILDTIMEOUT_SET_EVENT_SUSPENDED = 2, - BUILDTIMEOUT_SET_EVENT_DISCARD = 3, - BUILDTIMEOUT_SET_EVENT_RESUME = 4 -} buildtimeout_set_event_t; - -/** Execute the statement <b>stmt</b>, which may log events concerning the - * connection <b>conn</b>. To prevent infinite loops, disable log messages - * being sent to controllers if <b>conn</b> is a control connection. - * - * Stmt must not contain any return or goto statements. - */ -#define CONN_LOG_PROTECT(conn, stmt) \ - STMT_BEGIN \ - int _log_conn_is_control; \ - tor_assert(conn); \ - _log_conn_is_control = (conn->type == CONN_TYPE_CONTROL); \ - if (_log_conn_is_control) \ - disable_control_logging(); \ - STMT_BEGIN stmt; STMT_END; \ - if (_log_conn_is_control) \ - enable_control_logging(); \ - STMT_END - -/** Enum describing various stages of bootstrapping, for use with controller - * bootstrap status events. The values range from 0 to 100. */ -typedef enum { - BOOTSTRAP_STATUS_UNDEF=-1, - BOOTSTRAP_STATUS_STARTING=0, - BOOTSTRAP_STATUS_CONN_DIR=5, - BOOTSTRAP_STATUS_HANDSHAKE=-2, - BOOTSTRAP_STATUS_HANDSHAKE_DIR=10, - BOOTSTRAP_STATUS_ONEHOP_CREATE=15, - BOOTSTRAP_STATUS_REQUESTING_STATUS=20, - BOOTSTRAP_STATUS_LOADING_STATUS=25, - BOOTSTRAP_STATUS_LOADING_KEYS=40, - BOOTSTRAP_STATUS_REQUESTING_DESCRIPTORS=45, - BOOTSTRAP_STATUS_LOADING_DESCRIPTORS=50, - BOOTSTRAP_STATUS_CONN_OR=80, - BOOTSTRAP_STATUS_HANDSHAKE_OR=85, - BOOTSTRAP_STATUS_CIRCUIT_CREATE=90, - BOOTSTRAP_STATUS_DONE=100 -} bootstrap_status_t; - -/********************************* directory.c ***************************/ - -/** A pair of digests created by dir_split_resource_info_fingerprint_pairs() */ -typedef struct { - char first[DIGEST_LEN]; - char second[DIGEST_LEN]; -} fp_pair_t; - -/********************************* dirserv.c ***************************/ - -/** An enum to describe what format we're generating a routerstatus line in. - */ -typedef enum { - /** For use in a v2 opinion */ - NS_V2, - /** For use in a consensus networkstatus document (ns flavor) */ - NS_V3_CONSENSUS, - /** For use in a vote networkstatus document */ - NS_V3_VOTE, - /** For passing to the controlport in response to a GETINFO request */ - NS_CONTROL_PORT, - /** For use in a consensus networkstatus document (microdesc flavor) */ - NS_V3_CONSENSUS_MICRODESC -} routerstatus_format_type_t; - -#ifdef DIRSERV_PRIVATE -typedef struct measured_bw_line_t { - char node_id[DIGEST_LEN]; - char node_hex[MAX_HEX_NICKNAME_LEN+1]; - long int bw_kb; -} measured_bw_line_t; - -#endif /* defined(DIRSERV_PRIVATE) */ - -/********************************* dirvote.c ************************/ - -/** Describes the schedule by which votes should be generated. */ -typedef struct vote_timing_t { - /** Length in seconds between one consensus becoming valid and the next - * becoming valid. */ - int vote_interval; - /** For how many intervals is a consensus valid? */ - int n_intervals_valid; - /** Time in seconds allowed to propagate votes */ - int vote_delay; - /** Time in seconds allowed to propagate signatures */ - int dist_delay; -} vote_timing_t; - -/********************************* geoip.c **************************/ - -/** Indicates an action that we might be noting geoip statistics on. - * Note that if we're noticing CONNECT, we're a bridge, and if we're noticing - * the others, we're not. - */ -typedef enum { - /** We've noticed a connection as a bridge relay or entry guard. */ - GEOIP_CLIENT_CONNECT = 0, - /** We've served a networkstatus consensus as a directory server. */ - GEOIP_CLIENT_NETWORKSTATUS = 1, -} geoip_client_action_t; -/** Indicates either a positive reply or a reason for rejectng a network - * status request that will be included in geoip statistics. */ -typedef enum { - /** Request is answered successfully. */ - GEOIP_SUCCESS = 0, - /** V3 network status is not signed by a sufficient number of requested - * authorities. */ - GEOIP_REJECT_NOT_ENOUGH_SIGS = 1, - /** Requested network status object is unavailable. */ - GEOIP_REJECT_UNAVAILABLE = 2, - /** Requested network status not found. */ - GEOIP_REJECT_NOT_FOUND = 3, - /** Network status has not been modified since If-Modified-Since time. */ - GEOIP_REJECT_NOT_MODIFIED = 4, - /** Directory is busy. */ - GEOIP_REJECT_BUSY = 5, -} geoip_ns_response_t; -#define GEOIP_NS_RESPONSE_NUM 6 - -/** Directory requests that we are measuring can be either direct or - * tunneled. */ -typedef enum { - DIRREQ_DIRECT = 0, - DIRREQ_TUNNELED = 1, -} dirreq_type_t; - -/** Possible states for either direct or tunneled directory requests that - * are relevant for determining network status download times. */ -typedef enum { - /** Found that the client requests a network status; applies to both - * direct and tunneled requests; initial state of a request that we are - * measuring. */ - DIRREQ_IS_FOR_NETWORK_STATUS = 0, - /** Finished writing a network status to the directory connection; - * applies to both direct and tunneled requests; completes a direct - * request. */ - DIRREQ_FLUSHING_DIR_CONN_FINISHED = 1, - /** END cell sent to circuit that initiated a tunneled request. */ - DIRREQ_END_CELL_SENT = 2, - /** Flushed last cell from queue of the circuit that initiated a - * tunneled request to the outbuf of the OR connection. */ - DIRREQ_CIRC_QUEUE_FLUSHED = 3, - /** Flushed last byte from buffer of the channel belonging to the - * circuit that initiated a tunneled request; completes a tunneled - * request. */ - DIRREQ_CHANNEL_BUFFER_FLUSHED = 4 -} dirreq_state_t; - -#define WRITE_STATS_INTERVAL (24*60*60) - -/********************************* microdesc.c *************************/ - -typedef struct microdesc_cache_t microdesc_cache_t; - -/********************************* networkstatus.c *********************/ - -/** Possible statuses of a version of Tor, given opinions from the directory - * servers. */ -typedef enum version_status_t { - VS_RECOMMENDED=0, /**< This version is listed as recommended. */ - VS_OLD=1, /**< This version is older than any recommended version. */ - VS_NEW=2, /**< This version is newer than any recommended version. */ - VS_NEW_IN_SERIES=3, /**< This version is newer than any recommended version - * in its series, but later recommended versions exist. - */ - VS_UNRECOMMENDED=4, /**< This version is not recommended (general case). */ - VS_EMPTY=5, /**< The version list was empty; no agreed-on versions. */ - VS_UNKNOWN, /**< We have no idea. */ -} version_status_t; - -/********************************* policies.c ************************/ - -/** Outcome of applying an address policy to an address. */ -typedef enum { - /** The address was accepted */ - ADDR_POLICY_ACCEPTED=0, - /** The address was rejected */ - ADDR_POLICY_REJECTED=-1, - /** Part of the address was unknown, but as far as we can tell, it was - * accepted. */ - ADDR_POLICY_PROBABLY_ACCEPTED=1, - /** Part of the address was unknown, but as far as we can tell, it was - * rejected. */ - ADDR_POLICY_PROBABLY_REJECTED=2, -} addr_policy_result_t; - -/********************************* rephist.c ***************************/ - -/** Possible public/private key operations in Tor: used to keep track of where - * we're spending our time. */ -typedef enum { - SIGN_DIR, SIGN_RTR, - VERIFY_DIR, VERIFY_RTR, - ENC_ONIONSKIN, DEC_ONIONSKIN, - TLS_HANDSHAKE_C, TLS_HANDSHAKE_S, - REND_CLIENT, REND_MID, REND_SERVER, -} pk_op_t; - -/********************************* rendcommon.c ***************************/ - -/** Hidden-service side configuration of client authorization. */ -typedef struct rend_authorized_client_t { - char *client_name; - uint8_t descriptor_cookie[REND_DESC_COOKIE_LEN]; - crypto_pk_t *client_key; -} rend_authorized_client_t; - -/** ASCII-encoded v2 hidden service descriptor. */ -typedef struct rend_encoded_v2_service_descriptor_t { - char desc_id[DIGEST_LEN]; /**< Descriptor ID. */ - char *desc_str; /**< Descriptor string. */ -} rend_encoded_v2_service_descriptor_t; - -/** The maximum number of non-circuit-build-timeout failures a hidden - * service client will tolerate while trying to build a circuit to an - * introduction point. See also rend_intro_point_t.unreachable_count. */ -#define MAX_INTRO_POINT_REACHABILITY_FAILURES 5 - -/** The minimum and maximum number of distinct INTRODUCE2 cells which a - * hidden service's introduction point will receive before it begins to - * expire. */ -#define INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS 16384 -/* Double the minimum value so the interval is [min, min * 2]. */ -#define INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS \ - (INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS * 2) - -/** The minimum number of seconds that an introduction point will last - * before expiring due to old age. (If it receives - * INTRO_POINT_LIFETIME_INTRODUCTIONS INTRODUCE2 cells, it may expire - * sooner.) - * - * XXX Should this be configurable? */ -#define INTRO_POINT_LIFETIME_MIN_SECONDS (18*60*60) -/** The maximum number of seconds that an introduction point will last - * before expiring due to old age. - * - * XXX Should this be configurable? */ -#define INTRO_POINT_LIFETIME_MAX_SECONDS (24*60*60) - -/** The maximum number of circuit creation retry we do to an intro point - * before giving up. We try to reuse intro point that fails during their - * lifetime so this is a hard limit on the amount of time we do that. */ -#define MAX_INTRO_POINT_CIRCUIT_RETRIES 3 - -/** Introduction point information. Used both in rend_service_t (on - * the service side) and in rend_service_descriptor_t (on both the - * client and service side). */ -typedef struct rend_intro_point_t { - extend_info_t *extend_info; /**< Extend info for connecting to this - * introduction point via a multi-hop path. */ - crypto_pk_t *intro_key; /**< Introduction key that replaces the service - * key, if this descriptor is V2. */ - - /** (Client side only) Flag indicating that a timeout has occurred - * after sending an INTRODUCE cell to this intro point. After a - * timeout, an intro point should not be tried again during the same - * hidden service connection attempt, but it may be tried again - * during a future connection attempt. */ - unsigned int timed_out : 1; - - /** (Client side only) The number of times we have failed to build a - * circuit to this intro point for some reason other than our - * circuit-build timeout. See also MAX_INTRO_POINT_REACHABILITY_FAILURES. */ - unsigned int unreachable_count : 3; - - /** (Service side only) Flag indicating that this intro point was - * included in the last HS descriptor we generated. */ - unsigned int listed_in_last_desc : 1; - - /** (Service side only) A replay cache recording the RSA-encrypted parts - * of INTRODUCE2 cells this intro point's circuit has received. This is - * used to prevent replay attacks. */ - replaycache_t *accepted_intro_rsa_parts; - - /** (Service side only) Count of INTRODUCE2 cells accepted from this - * intro point. - */ - int accepted_introduce2_count; - - /** (Service side only) Maximum number of INTRODUCE2 cells that this IP - * will accept. This is a random value between - * INTRO_POINT_MIN_LIFETIME_INTRODUCTIONS and - * INTRO_POINT_MAX_LIFETIME_INTRODUCTIONS. */ - int max_introductions; - - /** (Service side only) The time at which this intro point was first - * published, or -1 if this intro point has not yet been - * published. */ - time_t time_published; - - /** (Service side only) The time at which this intro point should - * (start to) expire, or -1 if we haven't decided when this intro - * point should expire. */ - time_t time_to_expire; - - /** (Service side only) The amount of circuit creation we've made to this - * intro point. This is incremented every time we do a circuit relaunch on - * this object which is triggered when the circuit dies but the node is - * still in the consensus. After MAX_INTRO_POINT_CIRCUIT_RETRIES, we give - * up on it. */ - unsigned int circuit_retries; - - /** (Service side only) Set if this intro point has an established circuit - * and unset if it doesn't. */ - unsigned int circuit_established:1; -} rend_intro_point_t; - -#define REND_PROTOCOL_VERSION_BITMASK_WIDTH 16 - -/** Information used to connect to a hidden service. Used on both the - * service side and the client side. */ -typedef struct rend_service_descriptor_t { - crypto_pk_t *pk; /**< This service's public key. */ - int version; /**< Version of the descriptor format: 0 or 2. */ - time_t timestamp; /**< Time when the descriptor was generated. */ - /** Bitmask: which introduce/rendezvous protocols are supported? - * (We allow bits '0', '1', '2' and '3' to be set.) */ - unsigned protocols : REND_PROTOCOL_VERSION_BITMASK_WIDTH; - /** List of the service's introduction points. Elements are removed if - * introduction attempts fail. */ - smartlist_t *intro_nodes; - /** Has descriptor been uploaded to all hidden service directories? */ - int all_uploads_performed; - /** List of hidden service directories to which an upload request for - * this descriptor could be sent. Smartlist exists only when at least one - * of the previous upload requests failed (otherwise it's not important - * to know which uploads succeeded and which not). */ - smartlist_t *successful_uploads; -} rend_service_descriptor_t; - -/********************************* routerlist.c ***************************/ - -/** Represents information about a single trusted or fallback directory - * server. */ -typedef struct dir_server_t { - char *description; - char *nickname; - char *address; /**< Hostname. */ - /* XX/teor - why do we duplicate the address and port fields here and in - * fake_status? Surely we could just use fake_status (#17867). */ - tor_addr_t ipv6_addr; /**< IPv6 address if present; AF_UNSPEC if not */ - uint32_t addr; /**< IPv4 address. */ - uint16_t dir_port; /**< Directory port. */ - uint16_t or_port; /**< OR port: Used for tunneling connections. */ - uint16_t ipv6_orport; /**< OR port corresponding to ipv6_addr. */ - double weight; /** Weight used when selecting this node at random */ - char digest[DIGEST_LEN]; /**< Digest of identity key. */ - char v3_identity_digest[DIGEST_LEN]; /**< Digest of v3 (authority only, - * high-security) identity key. */ - - unsigned int is_running:1; /**< True iff we think this server is running. */ - unsigned int is_authority:1; /**< True iff this is a directory authority - * of some kind. */ - - /** True iff this server has accepted the most recent server descriptor - * we tried to upload to it. */ - unsigned int has_accepted_serverdesc:1; - - /** What kind of authority is this? (Bitfield.) */ - dirinfo_type_t type; - - time_t addr_current_at; /**< When was the document that we derived the - * address information from published? */ - - routerstatus_t fake_status; /**< Used when we need to pass this trusted - * dir_server_t to - * directory_request_set_routerstatus. - * as a routerstatus_t. Not updated by the - * router-status management code! - **/ -} dir_server_t; - -#define RELAY_REQUIRED_MIN_BANDWIDTH (75*1024) -#define BRIDGE_REQUIRED_MIN_BANDWIDTH (50*1024) - -#define ROUTER_MAX_DECLARED_BANDWIDTH INT32_MAX - -/* Flags for pick_directory_server() and pick_trusteddirserver(). */ -/** Flag to indicate that we should not automatically be willing to use - * ourself to answer a directory request. - * Passed to router_pick_directory_server (et al).*/ -#define PDS_ALLOW_SELF (1<<0) -/** Flag to indicate that if no servers seem to be up, we should mark all - * directory servers as up and try again. - * Passed to router_pick_directory_server (et al).*/ -#define PDS_RETRY_IF_NO_SERVERS (1<<1) -/** Flag to indicate that we should not exclude directory servers that - * our ReachableAddress settings would exclude. This usually means that - * we're going to connect to the server over Tor, and so we don't need to - * worry about our firewall telling us we can't. - * Passed to router_pick_directory_server (et al).*/ -#define PDS_IGNORE_FASCISTFIREWALL (1<<2) -/** Flag to indicate that we should not use any directory authority to which - * we have an existing directory connection for downloading server descriptors - * or extrainfo documents. - * - * Passed to router_pick_directory_server (et al) - */ -#define PDS_NO_EXISTING_SERVERDESC_FETCH (1<<3) -/** Flag to indicate that we should not use any directory authority to which - * we have an existing directory connection for downloading microdescs. - * - * Passed to router_pick_directory_server (et al) - */ -#define PDS_NO_EXISTING_MICRODESC_FETCH (1<<4) - -/** Possible ways to weight routers when choosing one randomly. See - * routerlist_sl_choose_by_bandwidth() for more information.*/ -typedef enum bandwidth_weight_rule_t { - NO_WEIGHTING, WEIGHT_FOR_EXIT, WEIGHT_FOR_MID, WEIGHT_FOR_GUARD, - WEIGHT_FOR_DIR -} bandwidth_weight_rule_t; - -/** Flags to be passed to control router_choose_random_node() to indicate what - * kind of nodes to pick according to what algorithm. */ -typedef enum { - CRN_NEED_UPTIME = 1<<0, - CRN_NEED_CAPACITY = 1<<1, - CRN_NEED_GUARD = 1<<2, - /* XXXX not used, apparently. */ - CRN_WEIGHT_AS_EXIT = 1<<5, - CRN_NEED_DESC = 1<<6, - /* On clients, only provide nodes that satisfy ClientPreferIPv6OR */ - CRN_PREF_ADDR = 1<<7, - /* On clients, only provide nodes that we can connect to directly, based on - * our firewall rules */ - CRN_DIRECT_CONN = 1<<8, - /* On clients, only provide nodes with HSRend >= 2 protocol version which - * is required for hidden service version >= 3. */ - CRN_RENDEZVOUS_V3 = 1<<9, -} router_crn_flags_t; - -/** Return value for router_add_to_routerlist() and dirserv_add_descriptor() */ -typedef enum was_router_added_t { - /* Router was added successfully. */ - ROUTER_ADDED_SUCCESSFULLY = 1, - /* Extrainfo document was rejected because no corresponding router - * descriptor was found OR router descriptor was rejected because - * it was incompatible with its extrainfo document. */ - ROUTER_BAD_EI = -1, - /* Router descriptor was rejected because it is already known. */ - ROUTER_IS_ALREADY_KNOWN = -2, - /* General purpose router was rejected, because it was not listed - * in consensus. */ - ROUTER_NOT_IN_CONSENSUS = -3, - /* Router was neither in directory consensus nor in any of - * networkstatus documents. Caching it to access later. - * (Applies to fetched descriptors only.) */ - ROUTER_NOT_IN_CONSENSUS_OR_NETWORKSTATUS = -4, - /* Router was rejected by directory authority. */ - ROUTER_AUTHDIR_REJECTS = -5, - /* Bridge descriptor was rejected because such bridge was not one - * of the bridges we have listed in our configuration. */ - ROUTER_WAS_NOT_WANTED = -6, - /* Router descriptor was rejected because it was older than - * OLD_ROUTER_DESC_MAX_AGE. */ - ROUTER_WAS_TOO_OLD = -7, /* note contrast with 'NOT_NEW' */ - /* DOCDOC */ - ROUTER_CERTS_EXPIRED = -8 -} was_router_added_t; - -/********************************* routerparse.c ************************/ - -#define MAX_STATUS_TAG_LEN 32 -/** Structure to hold parsed Tor versions. This is a little messier - * than we would like it to be, because we changed version schemes with 0.1.0. - * - * See version-spec.txt for the whole business. - */ -typedef struct tor_version_t { - int major; - int minor; - int micro; - /** Release status. For version in the post-0.1 format, this is always - * VER_RELEASE. */ - enum { VER_PRE=0, VER_RC=1, VER_RELEASE=2, } status; - int patchlevel; - char status_tag[MAX_STATUS_TAG_LEN]; - int svn_revision; - - int git_tag_len; - char git_tag[DIGEST_LEN]; -} tor_version_t; - -#endif /* !defined(TOR_OR_H) */ - diff --git a/src/rust/build.rs b/src/rust/build.rs index b943aa5535..2cf85b404a 100644 --- a/src/rust/build.rs +++ b/src/rust/build.rs @@ -138,8 +138,7 @@ pub fn main() { cfg.from_cflags("TOR_LDFLAGS_openssl"); cfg.from_cflags("TOR_LDFLAGS_libevent"); - cfg.link_relpath("src/common"); - cfg.link_relpath("src/ext/keccak-tiny"); + cfg.link_relpath("src/lib"); cfg.link_relpath("src/ext/keccak-tiny"); cfg.link_relpath("src/ext/ed25519/ref10"); cfg.link_relpath("src/ext/ed25519/donna"); @@ -149,11 +148,23 @@ pub fn main() { // will have dependencies on all the other rust packages that // tor uses. We must be careful with factoring and dependencies // moving forward! - cfg.component("or-crypto-testing"); - cfg.component("or-ctime-testing"); - cfg.component("or-testing"); - cfg.component("or-event-testing"); - cfg.component("or-ctime-testing"); + cfg.component("tor-crypt-ops-testing"); + cfg.component("tor-sandbox"); + cfg.component("tor-encoding-testing"); + cfg.component("tor-net"); + cfg.component("tor-thread-testing"); + cfg.component("tor-memarea-testing"); + cfg.component("tor-log"); + cfg.component("tor-lock"); + cfg.component("tor-fdio"); + cfg.component("tor-container-testing"); + cfg.component("tor-smartlist-core-testing"); + cfg.component("tor-string-testing"); + cfg.component("tor-malloc"); + cfg.component("tor-wallclock"); + cfg.component("tor-err-testing"); + cfg.component("tor-intmath-testing"); + cfg.component("tor-ctime-testing"); cfg.component("curve25519_donna"); cfg.component("keccak-tiny"); cfg.component("ed25519_ref10"); diff --git a/src/rust/external/external.rs b/src/rust/external/external.rs index b9e17f021d..059fdd0df7 100644 --- a/src/rust/external/external.rs +++ b/src/rust/external/external.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ use libc::{c_char, c_int}; @@ -11,7 +11,7 @@ extern "C" { ) -> c_int; } -/// Wrap calls to tor_version_as_new_as, defined in src/or/routerparse.c +/// Wrap calls to tor_version_as_new_as, defined in routerparse.c pub fn c_tor_version_as_new_as(platform: &str, cutoff: &str) -> bool { // CHK: These functions should log a warning if an error occurs. This // can be added when integration with tor's logger is added to rust diff --git a/src/rust/protover/ffi.rs b/src/rust/protover/ffi.rs index e3e545db75..3055893d43 100644 --- a/src/rust/protover/ffi.rs +++ b/src/rust/protover/ffi.rs @@ -1,9 +1,9 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! FFI functions, only to be called from C. //! -//! Equivalent C versions of this api are in `src/or/protover.c` +//! Equivalent C versions of this api are in `protover.c` use libc::{c_char, c_int, uint32_t}; use std::ffi::CStr; @@ -18,7 +18,7 @@ use protover::*; /// Translate C enums to Rust Proto enums, using the integer value of the C /// enum to map to its associated Rust enum. /// -/// C_RUST_COUPLED: src/or/protover.h `protocol_type_t` +/// C_RUST_COUPLED: protover.h `protocol_type_t` fn translate_to_rust(c_proto: uint32_t) -> Result<Protocol, ProtoverError> { match c_proto { 0 => Ok(Protocol::Link), diff --git a/src/rust/protover/lib.rs b/src/rust/protover/lib.rs index ce964196fd..5da562c1e0 100644 --- a/src/rust/protover/lib.rs +++ b/src/rust/protover/lib.rs @@ -1,4 +1,4 @@ -//! Copyright (c) 2016-2017, The Tor Project, Inc. */ +//! Copyright (c) 2016-2018, The Tor Project, Inc. */ //! See LICENSE for licensing information */ //! Versioning information for different pieces of the Tor protocol. diff --git a/src/rust/protover/protover.rs b/src/rust/protover/protover.rs index d6ed2739fe..299e433722 100644 --- a/src/rust/protover/protover.rs +++ b/src/rust/protover/protover.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ use std::collections::HashMap; @@ -19,13 +19,13 @@ use protoset::ProtoSet; /// Authorities should use this to decide whether to guess proto lines. /// /// C_RUST_COUPLED: -/// src/or/protover.h `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS` +/// protover.h `FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS` const FIRST_TOR_VERSION_TO_ADVERTISE_PROTOCOLS: &'static str = "0.2.9.3-alpha"; /// The maximum number of subprotocol version numbers we will attempt to expand /// before concluding that someone is trying to DoS us /// -/// C_RUST_COUPLED: src/or/protover.c `MAX_PROTOCOLS_TO_EXPAND` +/// C_RUST_COUPLED: protover.c `MAX_PROTOCOLS_TO_EXPAND` const MAX_PROTOCOLS_TO_EXPAND: usize = (1<<16); /// The maximum size an `UnknownProtocol`'s name may be. @@ -33,7 +33,7 @@ pub(crate) const MAX_PROTOCOL_NAME_LENGTH: usize = 100; /// Known subprotocols in Tor. Indicates which subprotocol a relay supports. /// -/// C_RUST_COUPLED: src/or/protover.h `protocol_type_t` +/// C_RUST_COUPLED: protover.h `protocol_type_t` #[derive(Clone, Hash, Eq, PartialEq, Debug)] pub enum Protocol { Cons, @@ -57,7 +57,7 @@ impl fmt::Display for Protocol { /// Translates a string representation of a protocol into a Proto type. /// Error if the string is an unrecognized protocol name. /// -/// C_RUST_COUPLED: src/or/protover.c `PROTOCOL_NAMES` +/// C_RUST_COUPLED: protover.c `PROTOCOL_NAMES` impl FromStr for Protocol { type Err = ProtoverError; @@ -130,7 +130,7 @@ impl From<Protocol> for UnknownProtocol { /// Rust code can use the `&'static CStr` as a normal `&'a str` by /// calling `protover::get_supported_protocols`. /// -// C_RUST_COUPLED: src/or/protover.c `protover_get_supported_protocols` +// C_RUST_COUPLED: protover.c `protover_get_supported_protocols` pub(crate) fn get_supported_protocols_cstr() -> &'static CStr { cstr!("Cons=1-2 \ Desc=1-2 \ @@ -601,7 +601,7 @@ impl ProtoverVote { /// let vote = ProtoverVote::compute(protos, &2); /// assert_eq!("Link=3", vote.to_string()); /// ``` - // C_RUST_COUPLED: /src/or/protover.c protover_compute_vote + // C_RUST_COUPLED: protover.c protover_compute_vote pub fn compute(proto_entries: &[UnvalidatedProtoEntry], threshold: &usize) -> UnvalidatedProtoEntry { let mut all_count: ProtoverVote = ProtoverVote::default(); let mut final_output: UnvalidatedProtoEntry = UnvalidatedProtoEntry::default(); diff --git a/src/rust/protover/tests/protover.rs b/src/rust/protover/tests/protover.rs index 2db01a1634..ac78d34b7a 100644 --- a/src/rust/protover/tests/protover.rs +++ b/src/rust/protover/tests/protover.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ extern crate protover; diff --git a/src/rust/smartlist/lib.rs b/src/rust/smartlist/lib.rs index 14a8148315..2716842af2 100644 --- a/src/rust/smartlist/lib.rs +++ b/src/rust/smartlist/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ extern crate libc; diff --git a/src/rust/smartlist/smartlist.rs b/src/rust/smartlist/smartlist.rs index 2a822d89f4..747d22f78c 100644 --- a/src/rust/smartlist/smartlist.rs +++ b/src/rust/smartlist/smartlist.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ use std::slice; diff --git a/src/rust/tor_allocate/lib.rs b/src/rust/tor_allocate/lib.rs index 937a5dcf63..5a355bc8d6 100644 --- a/src/rust/tor_allocate/lib.rs +++ b/src/rust/tor_allocate/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! Allocation helper functions that allow data to be allocated in Rust diff --git a/src/rust/tor_allocate/tor_allocate.rs b/src/rust/tor_allocate/tor_allocate.rs index 3c0037f139..47fa5fc593 100644 --- a/src/rust/tor_allocate/tor_allocate.rs +++ b/src/rust/tor_allocate/tor_allocate.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ // No-op defined purely for testing at the module level use libc::c_char; diff --git a/src/rust/tor_log/lib.rs b/src/rust/tor_log/lib.rs index 72f9e38339..21855ae73b 100644 --- a/src/rust/tor_log/lib.rs +++ b/src/rust/tor_log/lib.rs @@ -1,4 +1,4 @@ -//! Copyright (c) 2016-2017, The Tor Project, Inc. */ +//! Copyright (c) 2016-2018, The Tor Project, Inc. */ //! See LICENSE for licensing information */ //! Logging wrapper for Rust to utilize Tor's logger, found at diff --git a/src/rust/tor_log/tor_log.rs b/src/rust/tor_log/tor_log.rs index ad6725f0f2..49a1e7b158 100644 --- a/src/rust/tor_log/tor_log.rs +++ b/src/rust/tor_log/tor_log.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ // Note that these functions are untested due to the fact that there are no @@ -129,7 +129,7 @@ pub mod log { } /// The main entry point into Tor's logger. When in non-test mode, this - /// will link directly with `tor_log_string` in /src/or/log.c + /// will link directly with `tor_log_string` in torlog.c extern "C" { pub fn tor_log_string( severity: c_int, diff --git a/src/rust/tor_rust/include.am b/src/rust/tor_rust/include.am index bcf94193f4..ecc821a887 100644 --- a/src/rust/tor_rust/include.am +++ b/src/rust/tor_rust/include.am @@ -9,16 +9,16 @@ EXTRA_CARGO_OPTIONS= CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \ CARGO_HOME="$(abs_top_builddir)/src/rust" \ $(CARGO) build --release $(EXTRA_CARGO_OPTIONS) \ - $(CARGO_ONLINE) \ - --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" ) + $(CARGO_ONLINE) \ + --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" ) distclean-rust: ( cd "$(abs_top_builddir)/src/rust" ; \ CARGO_TARGET_DIR="$(abs_top_builddir)/src/rust/target" \ CARGO_HOME="$(abs_top_builddir)/src/rust" \ $(CARGO) clean $(EXTRA_CARGO_OPTIONS) \ - $(CARGO_ONLINE) \ - --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" ) + $(CARGO_ONLINE) \ + --manifest-path "$(abs_top_srcdir)/src/rust/tor_rust/Cargo.toml" ) rm -rf "$(abs_top_builddir)/src/rust/registry" if USE_RUST diff --git a/src/rust/tor_util/ffi.rs b/src/rust/tor_util/ffi.rs index 32779ed476..4be154ff1e 100644 --- a/src/rust/tor_util/ffi.rs +++ b/src/rust/tor_util/ffi.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! FFI functions to announce Rust support during tor startup, only to be diff --git a/src/rust/tor_util/lib.rs b/src/rust/tor_util/lib.rs index 94697b6069..4ce5fc9374 100644 --- a/src/rust/tor_util/lib.rs +++ b/src/rust/tor_util/lib.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! Small module to announce Rust support during startup for demonstration diff --git a/src/rust/tor_util/strings.rs b/src/rust/tor_util/strings.rs index 505191d913..c365564e97 100644 --- a/src/rust/tor_util/strings.rs +++ b/src/rust/tor_util/strings.rs @@ -1,4 +1,4 @@ -// Copyright (c) 2016-2017, The Tor Project, Inc. */ +// Copyright (c) 2016-2018, The Tor Project, Inc. */ // See LICENSE for licensing information */ //! Utilities for working with static strings. diff --git a/src/test/bench.c b/src/test/bench.c index 9ab23c9921..7919a4224f 100644 --- a/src/test/bench.c +++ b/src/test/bench.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,21 +10,29 @@ #include "orconfig.h" -#include "or.h" -#include "onion_tap.h" -#include "relay_crypto.h" +#include "core/or/or.h" +#include "core/crypto/onion_tap.h" +#include "core/crypto/relay_crypto.h" #include <openssl/opensslv.h> #include <openssl/evp.h> #include <openssl/ec.h> #include <openssl/ecdh.h> #include <openssl/obj_mac.h> -#include "config.h" -#include "crypto_curve25519.h" -#include "onion_ntor.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" -#include "consdiff.h" +#include "core/or/circuitlist.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "core/crypto/onion_ntor.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircommon/consdiff.h" +#include "lib/compress/compress.h" + +#include "core/or/cell_st.h" +#include "core/or/or_circuit_st.h" + +#include "lib/crypt_ops/digestset.h" #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) static uint64_t nanostart; @@ -371,7 +379,7 @@ bench_dmap(void) crypto_rand(d, 20); smartlist_add(sl2, tor_memdup(d, 20)); } - printf("nbits=%d\n", ds->mask+1); + //printf("nbits=%d\n", ds->mask+1); reset_perftime(); @@ -399,18 +407,20 @@ bench_dmap(void) NANOCOUNT(pt3, pt4, iters*elts)); for (i = 0; i < iters; ++i) { - SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_contains(ds, cp)); - SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_contains(ds, cp)); + SMARTLIST_FOREACH(sl, const char *, cp, + n += digestset_probably_contains(ds, cp)); + SMARTLIST_FOREACH(sl2, const char *, cp, + n += digestset_probably_contains(ds, cp)); } end = perftime(); - printf("digestset_contains: %.2f ns per element.\n", + printf("digestset_probably_contains: %.2f ns per element.\n", NANOCOUNT(pt4, end, iters*elts*2)); /* We need to use this, or else the whole loop gets optimized out. */ printf("Hits == %d\n", n); for (i = 0; i < fpostests; ++i) { crypto_rand(d, 20); - if (digestset_contains(ds, d)) ++fp; + if (digestset_probably_contains(ds, d)) ++fp; } printf("False positive rate on digestset: %.2f%%\n", (fp/(double)fpostests)*100); @@ -544,8 +554,8 @@ bench_dh(void) reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { - char dh_pubkey_a[DH_BYTES], dh_pubkey_b[DH_BYTES]; - char secret_a[DH_BYTES], secret_b[DH_BYTES]; + char dh_pubkey_a[DH1024_KEY_LEN], dh_pubkey_b[DH1024_KEY_LEN]; + char secret_a[DH1024_KEY_LEN], secret_b[DH1024_KEY_LEN]; ssize_t slen_a, slen_b; crypto_dh_t *dh_a = crypto_dh_new(DH_TYPE_TLS); crypto_dh_t *dh_b = crypto_dh_new(DH_TYPE_TLS); @@ -579,7 +589,7 @@ bench_ecdh_impl(int nid, const char *name) reset_perftime(); start = perftime(); for (i = 0; i < iters; ++i) { - char secret_a[DH_BYTES], secret_b[DH_BYTES]; + char secret_a[DH1024_KEY_LEN], secret_b[DH1024_KEY_LEN]; ssize_t slen_a, slen_b; EC_KEY *dh_a = EC_KEY_new_by_curve_name(nid); EC_KEY *dh_b = EC_KEY_new_by_curve_name(nid); @@ -590,10 +600,10 @@ bench_ecdh_impl(int nid, const char *name) EC_KEY_generate_key(dh_a); EC_KEY_generate_key(dh_b); - slen_a = ECDH_compute_key(secret_a, DH_BYTES, + slen_a = ECDH_compute_key(secret_a, DH1024_KEY_LEN, EC_KEY_get0_public_key(dh_b), dh_a, NULL); - slen_b = ECDH_compute_key(secret_b, DH_BYTES, + slen_b = ECDH_compute_key(secret_b, DH1024_KEY_LEN, EC_KEY_get0_public_key(dh_a), dh_b, NULL); @@ -738,4 +748,3 @@ main(int argc, const char **argv) return 0; } - diff --git a/src/test/bt_test.py b/src/test/bt_test.py index 4cb3326042..0eeb58c16c 100755 --- a/src/test/bt_test.py +++ b/src/test/bt_test.py @@ -1,4 +1,4 @@ -# Copyright 2013-2017, The Tor Project, Inc +# Copyright 2013-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/ed25519_exts_ref.py b/src/test/ed25519_exts_ref.py index f84d3002d3..a9090c9ed2 100644 --- a/src/test/ed25519_exts_ref.py +++ b/src/test/ed25519_exts_ref.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2014-2017, The Tor Project, Inc +# Copyright 2014-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/fakechans.h b/src/test/fakechans.h index ab5d8461b6..0770be8e04 100644 --- a/src/test/fakechans.h +++ b/src/test/fakechans.h @@ -1,4 +1,4 @@ - /* Copyright (c) 2014-2017, The Tor Project, Inc. */ + /* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_FAKECHANS_H diff --git a/src/test/fuzz/dict/http b/src/test/fuzz/dict/http index 3b0531579d..63627ac380 100644 --- a/src/test/fuzz/dict/http +++ b/src/test/fuzz/dict/http @@ -4,7 +4,7 @@ # # Extracted from directory_handle_command() in the tor source code # -# Copyright (c) 2016-2017, The Tor Project, Inc. +# Copyright (c) 2016-2018, The Tor Project, Inc. # See LICENSE for licensing information # # Usage: diff --git a/src/test/fuzz/fuzz_consensus.c b/src/test/fuzz/fuzz_consensus.c index 6610ade7ad..b170fd33d8 100644 --- a/src/test/fuzz/fuzz_consensus.c +++ b/src/test/fuzz/fuzz_consensus.c @@ -1,10 +1,12 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "networkstatus.h" -#include "fuzzing.h" +#include "core/or/or.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/networkstatus.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/nodelist/networkstatus_st.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) @@ -75,4 +77,3 @@ fuzz_main(const uint8_t *data, size_t sz) tor_free(str); return 0; } - diff --git a/src/test/fuzz/fuzz_descriptor.c b/src/test/fuzz/fuzz_descriptor.c index 1a50beae17..5a56f4081a 100644 --- a/src/test/fuzz/fuzz_descriptor.c +++ b/src/test/fuzz/fuzz_descriptor.c @@ -1,11 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "routerlist.h" -#include "routerkeys.h" -#include "fuzzing.h" +#include "core/or/or.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerlist.h" +#include "feature/relay/routerkeys.h" +#include "test/fuzz/fuzzing.h" static int mock_check_tap_onion_key_crosscert__nocheck(const uint8_t *crosscert, diff --git a/src/test/fuzz/fuzz_diff.c b/src/test/fuzz/fuzz_diff.c index 642380b512..1079856fdb 100644 --- a/src/test/fuzz/fuzz_diff.c +++ b/src/test/fuzz/fuzz_diff.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE #include "orconfig.h" -#include "or.h" -#include "consdiff.h" +#include "core/or/or.h" +#include "feature/dircommon/consdiff.h" -#include "fuzzing.h" +#include "test/fuzz/fuzzing.h" static int mock_consensus_compute_digest_(const char *c, consensus_digest_t *d) diff --git a/src/test/fuzz/fuzz_diff_apply.c b/src/test/fuzz/fuzz_diff_apply.c index 8d7bf751bf..165d0e6126 100644 --- a/src/test/fuzz/fuzz_diff_apply.c +++ b/src/test/fuzz/fuzz_diff_apply.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE #include "orconfig.h" -#include "or.h" -#include "consdiff.h" +#include "core/or/or.h" +#include "feature/dircommon/consdiff.h" -#include "fuzzing.h" +#include "test/fuzz/fuzzing.h" static int mock_consensus_compute_digest_(const char *c, consensus_digest_t *d) diff --git a/src/test/fuzz/fuzz_extrainfo.c b/src/test/fuzz/fuzz_extrainfo.c index 2a3de7ecf7..6c88f80122 100644 --- a/src/test/fuzz/fuzz_extrainfo.c +++ b/src/test/fuzz/fuzz_extrainfo.c @@ -1,11 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "routerlist.h" -#include "routerkeys.h" -#include "fuzzing.h" +#include "core/or/or.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerlist.h" +#include "feature/relay/routerkeys.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_hsdescv2.c b/src/test/fuzz/fuzz_hsdescv2.c index 19db265716..fd5da41635 100644 --- a/src/test/fuzz/fuzz_hsdescv2.c +++ b/src/test/fuzz/fuzz_hsdescv2.c @@ -1,10 +1,11 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "rendcommon.h" -#include "fuzzing.h" +#include "core/or/or.h" +#include "feature/nodelist/routerparse.h" +#include "feature/rend/rendcommon.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) @@ -49,4 +50,3 @@ fuzz_main(const uint8_t *data, size_t sz) tor_free(str); return 0; } - diff --git a/src/test/fuzz/fuzz_hsdescv3.c b/src/test/fuzz/fuzz_hsdescv3.c index 428774e330..4ec8db0a87 100644 --- a/src/test/fuzz/fuzz_hsdescv3.c +++ b/src/test/fuzz/fuzz_hsdescv3.c @@ -1,17 +1,16 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE #define HS_DESCRIPTOR_PRIVATE -#include "or.h" -#include "ed25519_cert.h" /* Trunnel interface. */ -#include "crypto_ed25519.h" -#include "hs_descriptor.h" -#include "routerparse.h" -#include "util.h" +#include "core/or/or.h" +#include "trunnel/ed25519_cert.h" /* Trunnel interface. */ +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/hs/hs_descriptor.h" +#include "feature/nodelist/routerparse.h" -#include "fuzzing.h" +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) diff --git a/src/test/fuzz/fuzz_http.c b/src/test/fuzz/fuzz_http.c index 2ffeb60244..61dc2144b4 100644 --- a/src/test/fuzz/fuzz_http.c +++ b/src/test/fuzz/fuzz_http.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,15 +6,17 @@ #define BUFFERS_PRIVATE #define DIRECTORY_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "buffers.h" -#include "config.h" -#include "connection.h" -#include "directory.h" -#include "torlog.h" +#include "core/or/or.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/dircache/directory.h" +#include "lib/log/torlog.h" -#include "fuzzing.h" +#include "feature/dircommon/dir_connection_st.h" + +#include "test/fuzz/fuzzing.h" static void mock_connection_write_to_buf_impl_(const char *string, size_t len, diff --git a/src/test/fuzz/fuzz_http_connect.c b/src/test/fuzz/fuzz_http_connect.c index dc674070b2..184bb52ee2 100644 --- a/src/test/fuzz/fuzz_http_connect.c +++ b/src/test/fuzz/fuzz_http_connect.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,16 +6,19 @@ #define BUFFERS_PRIVATE #define CONNECTION_EDGE_PRIVATE -#include "or.h" -#include "backtrace.h" -#include "buffers.h" -#include "config.h" -#include "connection.h" -#include "connection_edge.h" -#include "proto_socks.h" -#include "torlog.h" +#include "core/or/or.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "core/proto/proto_socks.h" +#include "lib/log/torlog.h" -#include "fuzzing.h" +#include "core/or/entry_connection_st.h" +#include "core/or/socks_request_st.h" + +#include "test/fuzz/fuzzing.h" static void mock_connection_write_to_buf_impl_(const char *string, size_t len, diff --git a/src/test/fuzz/fuzz_iptsv2.c b/src/test/fuzz/fuzz_iptsv2.c index 4abde0c16d..a3082f4d0e 100644 --- a/src/test/fuzz/fuzz_iptsv2.c +++ b/src/test/fuzz/fuzz_iptsv2.c @@ -1,10 +1,14 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "rendcommon.h" -#include "fuzzing.h" +#include "core/or/or.h" +#include "feature/nodelist/routerparse.h" +#include "feature/rend/rendcommon.h" +#include "lib/crypt_ops/crypto_ed25519.h" + +#include "feature/rend/rend_service_descriptor_st.h" + +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) @@ -43,4 +47,3 @@ fuzz_main(const uint8_t *data, size_t sz) rend_service_descriptor_free(desc); return 0; } - diff --git a/src/test/fuzz/fuzz_microdesc.c b/src/test/fuzz/fuzz_microdesc.c index 396115026e..fa9676372d 100644 --- a/src/test/fuzz/fuzz_microdesc.c +++ b/src/test/fuzz/fuzz_microdesc.c @@ -1,10 +1,12 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "microdesc.h" -#include "fuzzing.h" +#include "core/or/or.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/microdesc.h" +#include "lib/crypt_ops/crypto_ed25519.h" + +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) @@ -44,4 +46,3 @@ fuzz_main(const uint8_t *data, size_t sz) } return 0; } - diff --git a/src/test/fuzz/fuzz_vrs.c b/src/test/fuzz/fuzz_vrs.c index baf0610a0b..8c96851b1f 100644 --- a/src/test/fuzz/fuzz_vrs.c +++ b/src/test/fuzz/fuzz_vrs.c @@ -1,13 +1,18 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERPARSE_PRIVATE #define NETWORKSTATUS_PRIVATE -#include "or.h" -#include "routerparse.h" -#include "memarea.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "fuzzing.h" +#include "core/or/or.h" +#include "feature/nodelist/routerparse.h" +#include "lib/memarea/memarea.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" + +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" +#include "lib/crypt_ops/crypto_ed25519.h" + +#include "test/fuzz/fuzzing.h" static void mock_dump_desc__nodump(const char *desc, const char *type) @@ -79,4 +84,3 @@ fuzz_main(const uint8_t *data, size_t sz) tor_free(str); return 0; } - diff --git a/src/test/fuzz/fuzzing.h b/src/test/fuzz/fuzzing.h index aecdbb4e52..e90e5d58e0 100644 --- a/src/test/fuzz/fuzzing.h +++ b/src/test/fuzz/fuzzing.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef FUZZING_H #define FUZZING_H diff --git a/src/test/fuzz/fuzzing_common.c b/src/test/fuzz/fuzzing_common.c index a96552f0fc..0b3483bf66 100644 --- a/src/test/fuzz/fuzzing_common.c +++ b/src/test/fuzz/fuzzing_common.c @@ -1,13 +1,14 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CRYPTO_ED25519_PRIVATE #include "orconfig.h" -#include "or.h" -#include "backtrace.h" -#include "config.h" -#include "fuzzing.h" -#include "crypto.h" -#include "crypto_ed25519.h" +#include "core/or/or.h" +#include "lib/err/backtrace.h" +#include "app/config/config.h" +#include "test/fuzz/fuzzing.h" +#include "lib/compress/compress.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_ed25519.h" static or_options_t *mock_options = NULL; static const or_options_t * @@ -189,4 +190,3 @@ main(int argc, char **argv) } #endif - diff --git a/src/test/fuzz/include.am b/src/test/fuzz/include.am index cd16dc05be..87dfe91675 100644 --- a/src/test/fuzz/include.am +++ b/src/test/fuzz/include.am @@ -7,31 +7,17 @@ FUZZING_CFLAGS = \ FUZZING_LDFLAG = \ @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ @TOR_LDFLAGS_libevent@ FUZZING_LIBS = \ - src/or/libtor-testing.a \ - src/common/libor-crypto-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-event-testing.a \ - src/trunnel/libor-trunnel-testing.a \ + $(TOR_INTERNAL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ @TOR_LIBEVENT_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ \ @TOR_SYSTEMD_LIBS@ \ @TOR_LZMA_LIBS@ \ @TOR_ZSTD_LIBS@ oss-fuzz-prereqs: \ - src/or/libtor-testing.a \ - src/common/libor-crypto-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-event-testing.a \ - src/trunnel/libor-trunnel-testing.a + $(TOR_INTERNAL_TESTING_LIBS) noinst_HEADERS += \ src/test/fuzz/fuzzing.h diff --git a/src/test/fuzz_static_testcases.sh b/src/test/fuzz_static_testcases.sh index 3cb45ad5e6..138f85b106 100755 --- a/src/test/fuzz_static_testcases.sh +++ b/src/test/fuzz_static_testcases.sh @@ -1,6 +1,6 @@ #!/bin/sh -# Copyright (c) 2016-2017, The Tor Project, Inc. +# Copyright (c) 2016-2018, The Tor Project, Inc. # See LICENSE for licensing information set -e diff --git a/src/test/hs_ntor_ref.py b/src/test/hs_ntor_ref.py index 542b02d2e0..0c5756ad73 100644 --- a/src/test/hs_ntor_ref.py +++ b/src/test/hs_ntor_ref.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2017, The Tor Project, Inc +# Copyright 2017-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/hs_test_helpers.c b/src/test/hs_test_helpers.c index 5c1b9123d8..afe3eafa2f 100644 --- a/src/test/hs_test_helpers.c +++ b/src/test/hs_test_helpers.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_ed25519.h" -#include "test.h" -#include "torcert.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "test/test.h" +#include "feature/nodelist/torcert.h" -#include "hs_common.h" -#include "hs_test_helpers.h" +#include "feature/hs/hs_common.h" +#include "test/hs_test_helpers.h" hs_desc_intro_point_t * hs_helper_build_intro_point(const ed25519_keypair_t *signing_kp, time_t now, diff --git a/src/test/hs_test_helpers.h b/src/test/hs_test_helpers.h index b1b0490f05..b7c2714769 100644 --- a/src/test/hs_test_helpers.h +++ b/src/test/hs_test_helpers.h @@ -1,11 +1,11 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_HS_TEST_HELPERS_H #define TOR_HS_TEST_HELPERS_H -#include "ed25519_cert.h" -#include "hs_descriptor.h" +#include "trunnel/ed25519_cert.h" +#include "feature/hs/hs_descriptor.h" /* Set of functions to help build and test descriptors. */ hs_desc_intro_point_t *hs_helper_build_intro_point( diff --git a/src/test/include.am b/src/test/include.am index 6b35c248e6..a749ff1436 100644 --- a/src/test/include.am +++ b/src/test/include.am @@ -11,9 +11,9 @@ TESTS_ENVIRONMENT = \ export CARGO="$(CARGO)"; \ export EXTRA_CARGO_OPTIONS="$(EXTRA_CARGO_OPTIONS)"; \ export CARGO_ONLINE="$(CARGO_ONLINE)"; \ - export CCLD="$(CCLD)"; \ - chmod +x "$(abs_top_builddir)/link_rust.sh"; \ - export RUSTFLAGS="-C linker=$(abs_top_builddir)/link_rust.sh"; + export CCLD="$(CCLD)"; \ + chmod +x "$(abs_top_builddir)/link_rust.sh"; \ + export RUSTFLAGS="-C linker=$(abs_top_builddir)/link_rust.sh"; TESTSCRIPTS = \ src/test/fuzz_static_testcases.sh \ @@ -72,12 +72,10 @@ noinst_PROGRAMS+= \ endif src_test_AM_CPPFLAGS = -DSHARE_DATADIR="\"$(datadir)\"" \ - -DLOCALSTATEDIR="\"$(localstatedir)\"" \ - -DBINDIR="\"$(bindir)\"" \ - -I"$(top_srcdir)/src/or" -I"$(top_srcdir)/src/ext" \ - -I"$(top_srcdir)/src/trunnel" \ - -I"$(top_srcdir)/src/ext/trunnel" \ - -DTOR_UNIT_TESTS + -DLOCALSTATEDIR="\"$(localstatedir)\"" \ + -DBINDIR="\"$(bindir)\"" \ + -DTOR_UNIT_TESTS \ + $(AM_CPPFLAGS) # -L flags need to go in LDFLAGS. -l flags need to go in LDADD. # This seems to matter nowhere but on Windows, but I assure you that it @@ -159,7 +157,6 @@ src_test_test_SOURCES += \ src/test/test_proto_misc.c \ src/test/test_protover.c \ src/test/test_pt.c \ - src/test/test_pubsub.c \ src/test/test_relay.c \ src/test/test_relaycell.c \ src/test/test_relaycrypt.c \ @@ -222,27 +219,19 @@ src_test_test_switch_id_CPPFLAGS= $(src_test_AM_CPPFLAGS) src_test_test_switch_id_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_test_test_switch_id_LDFLAGS = @TOR_LDFLAGS_zlib@ src_test_test_switch_id_LDADD = \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ + $(TOR_UTIL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ - @TOR_LIB_WS32@ @TOR_LIB_USERENV@ \ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ \ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ src_test_test_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ - @TOR_LDFLAGS_libevent@ -src_test_test_LDADD = src/or/libtor-testing.a \ - src/common/libor-crypto-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-event-testing.a \ - src/trunnel/libor-trunnel-testing.a \ - src/trace/libor-trace.a \ + @TOR_LDFLAGS_libevent@ +src_test_test_LDADD = \ + $(TOR_INTERNAL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ @@ -260,42 +249,34 @@ src_test_test_memwipe_LDADD = $(src_test_test_LDADD) src_test_test_memwipe_LDFLAGS = $(src_test_test_LDFLAGS) @CFLAGS_BUGTRAP@ src_test_bench_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ - @TOR_LDFLAGS_libevent@ -src_test_bench_LDADD = src/or/libtor.a src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event.a src/trunnel/libor-trunnel.a \ - src/trace/libor-trace.a \ + @TOR_LDFLAGS_libevent@ +src_test_bench_LDADD = \ + $(TOR_INTERNAL_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_SYSTEMD_LIBS@ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ src_test_test_workqueue_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ \ - @TOR_LDFLAGS_libevent@ -src_test_test_workqueue_LDADD = src/or/libtor-testing.a \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/common/libor-event-testing.a \ - src/trace/libor-trace.a \ + @TOR_LDFLAGS_libevent@ +src_test_test_workqueue_LDADD = \ + $(TOR_INTERNAL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_LZMA_LIBS@ @TOR_ZSTD_LIBS@ src_test_test_timers_CPPFLAGS = $(src_test_test_CPPFLAGS) src_test_test_timers_CFLAGS = $(src_test_test_CFLAGS) src_test_test_timers_LDADD = \ - src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/common/libor-event-testing.a \ - src/common/libor-crypto-testing.a $(LIBKECCAK_TINY) $(LIBDONNA) \ + src/lib/libtor-evloop-testing.a \ + $(TOR_CRYPTO_TESTING_LIBS) \ + $(TOR_UTIL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ @TOR_LIBEVENT_LIBS@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ \ @TOR_LZMA_LIBS@ src_test_test_timers_LDFLAGS = $(src_test_test_LDFLAGS) @@ -321,36 +302,32 @@ noinst_PROGRAMS+= src/test/test-ntor-cl noinst_PROGRAMS+= src/test/test-hs-ntor-cl src_test_test_ntor_cl_SOURCES = src/test/test_ntor_cl.c src_test_test_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_test_test_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ - src/trace/libor-trace.a \ +src_test_test_ntor_cl_LDADD = \ + $(TOR_INTERNAL_LIBS) \ $(rust_ldadd) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ \ @CURVE25519_LIBS@ @TOR_LZMA_LIBS@ src_test_test_ntor_cl_AM_CPPFLAGS = \ - -I"$(top_srcdir)/src/or" + $(AM_CPPFLAGS) src_test_test_hs_ntor_cl_SOURCES = src/test/test_hs_ntor_cl.c src_test_test_hs_ntor_cl_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_test_test_hs_ntor_cl_LDADD = src/or/libtor.a src/common/libor.a \ - src/common/libor-ctime.a \ - src/common/libor-crypto.a $(LIBKECCAK_TINY) $(LIBDONNA) \ +src_test_test_hs_ntor_cl_LDADD = \ + $(TOR_INTERNAL_LIBS) \ @TOR_ZLIB_LIBS@ @TOR_LIB_MATH@ \ - @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ + @TOR_OPENSSL_LIBS@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ src_test_test_hs_ntor_cl_AM_CPPFLAGS = \ - -I"$(top_srcdir)/src/or" + $(AM_CPPFLAGS) noinst_PROGRAMS += src/test/test-bt-cl src_test_test_bt_cl_SOURCES = src/test/test_bt_cl.c -src_test_test_bt_cl_LDADD = src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ - src/trace/libor-trace.a \ +src_test_test_bt_cl_LDADD = \ + $(TOR_UTIL_TESTING_LIBS) \ $(rust_ldadd) \ @TOR_LIB_MATH@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ src_test_test_bt_cl_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_test_test_bt_cl_CPPFLAGS= $(src_test_AM_CPPFLAGS) $(TEST_CPPFLAGS) @@ -363,7 +340,7 @@ EXTRA_DIST += \ src/test/fuzz_static_testcases.sh \ src/test/slownacl_curve25519.py \ src/test/zero_length_keys.sh \ - src/test/rust_supp.txt \ + src/test/rust_supp.txt \ src/test/test_keygen.sh \ src/test/test_key_expiration.sh \ src/test/test_zero_length_keys.sh \ diff --git a/src/test/log_test_helpers.c b/src/test/log_test_helpers.c index d5a39cfeee..e814555ba1 100644 --- a/src/test/log_test_helpers.c +++ b/src/test/log_test_helpers.c @@ -1,8 +1,8 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define LOG_PRIVATE -#include "torlog.h" -#include "log_test_helpers.h" +#include "lib/log/torlog.h" +#include "test/log_test_helpers.h" /** * \file log_test_helpers.c diff --git a/src/test/log_test_helpers.h b/src/test/log_test_helpers.h index f5bbfcf3ff..fc9768c125 100644 --- a/src/test/log_test_helpers.h +++ b/src/test/log_test_helpers.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "core/or/or.h" #ifndef TOR_LOG_TEST_HELPERS_H #define TOR_LOG_TEST_HELPERS_H diff --git a/src/test/ntor_ref.py b/src/test/ntor_ref.py index 51f218f512..56e97ece36 100755 --- a/src/test/ntor_ref.py +++ b/src/test/ntor_ref.py @@ -1,5 +1,5 @@ #!/usr/bin/python -# Copyright 2012-2017, The Tor Project, Inc +# Copyright 2012-2018, The Tor Project, Inc # See LICENSE for licensing information """ diff --git a/src/test/rend_test_helpers.c b/src/test/rend_test_helpers.c index 9ac3894b0b..85a679a967 100644 --- a/src/test/rend_test_helpers.c +++ b/src/test/rend_test_helpers.c @@ -1,11 +1,15 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_rand.h" -#include "test.h" -#include "rendcommon.h" -#include "rend_test_helpers.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "test/test.h" +#include "feature/rend/rendcommon.h" +#include "test/rend_test_helpers.h" + +#include "core/or/extend_info_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" void generate_desc(int time_diff, rend_encoded_v2_service_descriptor_t **desc, diff --git a/src/test/rend_test_helpers.h b/src/test/rend_test_helpers.h index abf4324988..103e143ec6 100644 --- a/src/test/rend_test_helpers.h +++ b/src/test/rend_test_helpers.h @@ -1,7 +1,7 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "core/or/or.h" #ifndef TOR_REND_TEST_HELPERS_H #define TOR_REND_TEST_HELPERS_H diff --git a/src/test/test-child.c b/src/test/test-child.c index f78a829107..14df1a9b76 100644 --- a/src/test/test-child.c +++ b/src/test/test-child.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Tor Project, Inc. */ +/* Copyright (c) 2011-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" diff --git a/src/test/test-memwipe.c b/src/test/test-memwipe.c index aaaf2e7f68..8a4610e904 100644 --- a/src/test/test-memwipe.c +++ b/src/test/test-memwipe.c @@ -1,16 +1,17 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" +#include "lib/crypt_ops/crypto_util.h" + +#include "lib/intmath/cmp.h" +#include "lib/malloc/util_malloc.h" + #include <string.h> #include <stdio.h> #include <sys/types.h> #include <stdlib.h> -#include "crypto_util.h" -#include "compat.h" -#include "util.h" - static unsigned fill_a_buffer_memset(void) __attribute__((noinline)); static unsigned fill_a_buffer_memwipe(void) __attribute__((noinline)); static unsigned fill_a_buffer_nothing(void) __attribute__((noinline)); @@ -215,4 +216,3 @@ main(int argc, char **argv) return 0; } } - diff --git a/src/test/test-network.sh b/src/test/test-network.sh index 6e0f286573..b7a9f1b3c0 100755 --- a/src/test/test-network.sh +++ b/src/test/test-network.sh @@ -52,12 +52,12 @@ done # - if $PWD looks like a tor build directory, set it to $PWD, or # - unset $TOR_DIR, and let chutney fall back to finding tor binaries in $PATH if [ ! -d "$TOR_DIR" ]; then - if [ -d "$BUILDDIR/src/or" -a -d "$BUILDDIR/src/tools" ]; then + if [ -d "$BUILDDIR/src/core/or" -a -d "$BUILDDIR/src/tools" ]; then # Choose the build directory # But only if it looks like one $ECHO "$myname: \$TOR_DIR not set, trying \$BUILDDIR" TOR_DIR="$BUILDDIR" - elif [ -d "$PWD/src/or" -a -d "$PWD/src/tools" ]; then + elif [ -d "$PWD/src/core/or" -a -d "$PWD/src/tools" ]; then # Guess the tor directory is the current directory # But only if it looks like one $ECHO "$myname: \$TOR_DIR not set, trying \$PWD" diff --git a/src/test/test-timers.c b/src/test/test-timers.c index f20f29578b..f9276c25d6 100644 --- a/src/test/test-timers.c +++ b/src/test/test-timers.c @@ -1,4 +1,4 @@ -/* Copyright 2016-2017, The Tor Project, Inc. */ +/* Copyright 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -7,11 +7,12 @@ #include <stdio.h> #include <string.h> -#include "compat.h" -#include "compat_libevent.h" -#include "crypto_rand.h" -#include "timers.h" -#include "util.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/evloop/timers.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/log/util_bug.h" +#include "lib/time/compat_time.h" +#include "lib/wallclock/timeval.h" #define N_TIMERS 1000 #define MAX_DURATION 30 @@ -105,8 +106,8 @@ main(int argc, char **argv) total_square_difference += diff*diff; } const int64_t mean_diff = total_difference / n_active_timers; - printf("mean difference: "I64_FORMAT" usec\n", - I64_PRINTF_ARG(mean_diff)); + printf("mean difference: %"PRId64" usec\n", + (mean_diff)); const double mean_sq = ((double)total_square_difference)/ n_active_timers; const double sq_mean = mean_diff * mean_diff; @@ -139,4 +140,3 @@ main(int argc, char **argv) timers_shutdown(); return ret; } - diff --git a/src/test/test.c b/src/test/test.c index f0e8b9b728..2addeec968 100644 --- a/src/test/test.c +++ b/src/test/test.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,7 +9,10 @@ **/ #include "orconfig.h" -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_rand.h" + +#include "app/config/or_state_st.h" #include <stdio.h> #ifdef HAVE_FCNTL_H @@ -39,28 +42,34 @@ long int lround(double x); double fabs(double x); -#include "or.h" -#include "backtrace.h" -#include "buffers.h" -#include "circuitlist.h" -#include "circuitstats.h" -#include "compress.h" -#include "config.h" -#include "connection_edge.h" -#include "rendcommon.h" -#include "rendcache.h" -#include "test.h" -#include "main.h" -#include "memarea.h" -#include "onion.h" -#include "onion_ntor.h" -#include "onion_fast.h" -#include "onion_tap.h" -#include "policies.h" -#include "rephist.h" -#include "routerparse.h" -#include "statefile.h" -#include "crypto_curve25519.h" +#include "core/or/or.h" +#include "lib/err/backtrace.h" +#include "lib/container/buffers.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitstats.h" +#include "lib/compress/compress.h" +#include "app/config/config.h" +#include "core/or/connection_edge.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendcache.h" +#include "test/test.h" +#include "core/mainloop/main.h" +#include "lib/memarea/memarea.h" +#include "core/crypto/onion.h" +#include "core/crypto/onion_ntor.h" +#include "core/crypto/onion_fast.h" +#include "core/crypto/onion_tap.h" +#include "core/or/policies.h" +#include "feature/stats/rephist.h" +#include "feature/nodelist/routerparse.h" +#include "app/config/statefile.h" +#include "lib/crypt_ops/crypto_curve25519.h" + +#include "core/or/extend_info_st.h" +#include "core/or/or_circuit_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" /** Run unit tests for the onion handshake code. */ static void @@ -142,7 +151,8 @@ test_bad_onion_handshake(void *arg) memset(junk_buf, 0, sizeof(junk_buf)); crypto_pk_obsolete_public_hybrid_encrypt(pk, junk_buf2, TAP_ONIONSKIN_CHALLENGE_LEN, - junk_buf, DH_KEY_LEN, PK_PKCS1_OAEP_PADDING, 1); + junk_buf, DH1024_KEY_LEN, + PK_PKCS1_OAEP_PADDING, 1); tt_int_op(-1, OP_EQ, onion_skin_TAP_server_handshake(junk_buf2, pk, NULL, s_buf, s_keys, 40)); @@ -911,10 +921,8 @@ struct testgroup_t testgroups[] = { { "util/format/", util_format_tests }, { "util/logging/", logging_tests }, { "util/process/", util_process_tests }, - { "util/pubsub/", pubsub_tests }, { "util/thread/", thread_tests }, { "util/handle/", handle_tests }, { "dns/", dns_tests }, END_OF_GROUPS }; - diff --git a/src/test/test.h b/src/test/test.h index 63b2b30746..602acca1cd 100644 --- a/src/test/test.h +++ b/src/test/test.h @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2003, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_H @@ -13,7 +13,6 @@ #define DEBUG_SMARTLIST 1 -#include "compat.h" #include "tinytest.h" #define TT_EXIT_TEST_FUNCTION STMT_BEGIN goto done; STMT_END #include "tinytest_macros.h" @@ -51,28 +50,20 @@ tt_double_op((a), OP_LE, (b)); \ STMT_END -#ifdef _MSC_VER -#define U64_PRINTF_TYPE uint64_t -#define I64_PRINTF_TYPE int64_t -#else -#define U64_PRINTF_TYPE unsigned long long -#define I64_PRINTF_TYPE long long -#endif /* defined(_MSC_VER) */ - #define tt_size_op(a,op,b) \ tt_assert_test_fmt_type(a,b,#a" "#op" "#b,size_t,(val1_ op val2_), \ - U64_PRINTF_TYPE, U64_FORMAT, \ - {print_ = (U64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION) + size_t, "%"TOR_PRIuSZ, \ + {print_ = (size_t) value_;}, {}, TT_EXIT_TEST_FUNCTION) #define tt_u64_op(a,op,b) \ tt_assert_test_fmt_type(a,b,#a" "#op" "#b,uint64_t,(val1_ op val2_), \ - U64_PRINTF_TYPE, U64_FORMAT, \ - {print_ = (U64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION) + uint64_t, "%"PRIu64, \ + {print_ = (uint64_t) value_;}, {}, TT_EXIT_TEST_FUNCTION) #define tt_i64_op(a,op,b) \ - tt_assert_test_fmt_type(a,b,#a" "#op" "#b,int64_t,(val1_ op val2_), \ - I64_PRINTF_TYPE, I64_FORMAT, \ - {print_ = (I64_PRINTF_TYPE) value_;}, {}, TT_EXIT_TEST_FUNCTION) + tt_assert_test_fmt_type(a,b,#a" "#op" "#b,int64_t,(val1_ op val2_), \ + int64_t, "%"PRId64, \ + {print_ = (int64_t) value_;}, {}, TT_EXIT_TEST_FUNCTION) /** * Declare that the test is done, even though no tt___op() calls were made. @@ -248,7 +239,6 @@ extern struct testcase_t procmon_tests[]; extern struct testcase_t proto_http_tests[]; extern struct testcase_t proto_misc_tests[]; extern struct testcase_t protover_tests[]; -extern struct testcase_t pubsub_tests[]; extern struct testcase_t pt_tests[]; extern struct testcase_t relay_tests[]; extern struct testcase_t relaycell_tests[]; @@ -292,4 +282,3 @@ extern const char AUTHORITY_SIGNKEY_C_DIGEST[]; extern const char AUTHORITY_SIGNKEY_C_DIGEST256[]; #endif /* !defined(TOR_TEST_H) */ - diff --git a/src/test/test_accounting.c b/src/test/test_accounting.c index b0d37b2989..7721a9eb99 100644 --- a/src/test/test_accounting.c +++ b/src/test/test_accounting.c @@ -1,13 +1,15 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" #define HIBERNATE_PRIVATE -#include "hibernate.h" -#include "config.h" +#include "feature/hibernate/hibernate.h" +#include "app/config/config.h" #define STATEFILE_PRIVATE -#include "statefile.h" +#include "app/config/statefile.h" + +#include "app/config/or_state_st.h" #define NS_MODULE accounting @@ -102,4 +104,3 @@ struct testcase_t accounting_tests[] = { { "bwlimits", test_accounting_limits, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_addr.c b/src/test/test_addr.c index 40db31320f..9ab921c5b6 100644 --- a/src/test/test_addr.c +++ b/src/test/test_addr.c @@ -1,15 +1,19 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ADDRESSMAP_PRIVATE #include "orconfig.h" -#include "or.h" -#include "crypto_rand.h" -#include "test.h" -#include "addressmap.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "test/test.h" +#include "feature/client/addressmap.h" +#include "test/log_test_helpers.h" + +#ifdef HAVE_SYS_UN_H +#include <sys/un.h> +#endif /** Mocking replacement: only handles localhost. */ static int @@ -1257,4 +1261,3 @@ struct testcase_t addr_tests[] = { { "make_null", test_addr_make_null, 0, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_address.c b/src/test/test_address.c index 9c88d37a41..abe7c2c0ad 100644 --- a/src/test/test_address.c +++ b/src/test/test_address.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ADDRESS_PRIVATE @@ -23,10 +23,10 @@ #include <net/if.h> #endif /* defined(HAVE_IFCONF_TO_SMARTLIST) */ -#include "or.h" -#include "address.h" -#include "test.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "lib/net/address.h" +#include "test/test.h" +#include "test/log_test_helpers.h" /** Return 1 iff <b>sockaddr1</b> and <b>sockaddr2</b> represent * the same IP address and port combination. Otherwise, return 0. diff --git a/src/test/test_address_set.c b/src/test/test_address_set.c index f7441a6491..f231740011 100644 --- a/src/test/test_address_set.c +++ b/src/test/test_address_set.c @@ -1,16 +1,21 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_rand.h" -#include "address_set.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "routerlist.h" -#include "torcert.h" - -#include "test.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/or/address_set.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/torcert.h" + +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "test/test.h" static networkstatus_t *dummy_ns = NULL; static networkstatus_t * diff --git a/src/test/test_bridges.c b/src/test/test_bridges.c index c44f791e0d..07d6b88ed9 100644 --- a/src/test/test_bridges.c +++ b/src/test/test_bridges.c @@ -3,7 +3,7 @@ /** * \file test_bridges.c - * \brief Unittests for code in src/or/bridges.c + * \brief Unittests for code in bridges.c **/ #define TOR_BRIDGES_PRIVATE @@ -11,16 +11,14 @@ #include <stdbool.h> -#include "or.h" -#include "address.h" -#include "bridges.h" -#include "config.h" -#include "container.h" -#include "transports.h" -#include "util.h" +#include "core/or/or.h" +#include "lib/net/address.h" +#include "feature/client/bridges.h" +#include "app/config/config.h" +#include "feature/client/transports.h" /* Test suite stuff */ -#include "test.h" +#include "test/test.h" /** * A mocked transport_t, constructed via mock_transport_get_by_name(). @@ -611,4 +609,3 @@ struct testcase_t bridges_tests[] = { B_TEST(transport_is_needed, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_bt_cl.c b/src/test/test_bt_cl.c index b5c8d7cf9e..716cff36e0 100644 --- a/src/test/test_bt_cl.c +++ b/src/test/test_bt_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -7,10 +7,13 @@ /* To prevent 'assert' from going away. */ #undef TOR_COVERAGE -#include "or.h" -#include "util.h" -#include "backtrace.h" -#include "torlog.h" +#include "core/or/or.h" +#include "lib/err/backtrace.h" +#include "lib/log/torlog.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* -1: no crash. * 0: crash with a segmentation fault. @@ -118,4 +121,3 @@ main(int argc, char **argv) return 0; } - diff --git a/src/test/test_buffers.c b/src/test/test_buffers.c index 868f6a8ba4..477066f699 100644 --- a/src/test/test_buffers.c +++ b/src/test/test_buffers.c @@ -1,17 +1,19 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define BUFFERS_PRIVATE #define PROTO_HTTP_PRIVATE -#include "or.h" -#include "buffers.h" -#include "buffers_tls.h" -#include "crypto_rand.h" -#include "proto_http.h" -#include "proto_socks.h" -#include "test.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "lib/tls/buffers_tls.h" +#include "lib/tls/tortls.h" +#include "lib/compress/compress.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/proto/proto_http.h" +#include "core/proto/proto_socks.h" +#include "test/test.h" /** Run unit tests for buffers.c */ static void @@ -819,4 +821,3 @@ struct testcase_t buffer_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_bwmgt.c b/src/test/test_bwmgt.c index 268917005e..7aa053f6c3 100644 --- a/src/test/test_bwmgt.c +++ b/src/test/test_bwmgt.c @@ -8,15 +8,15 @@ #define TOKEN_BUCKET_PRIVATE -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" -#include "token_bucket.h" +#include "lib/evloop/token_bucket.h" // an imaginary time, in timestamp units. Chosen so it will roll over. static const uint32_t START_TS = UINT32_MAX-10; static const int32_t KB = 1024; -static const uint32_t GB = (U64_LITERAL(1) << 30); +static const uint32_t GB = (UINT64_C(1) << 30); static void test_bwmgt_token_buf_init(void *arg) diff --git a/src/test/test_cell_formats.c b/src/test/test_cell_formats.c index 54d9716780..2753c42191 100644 --- a/src/test/test_cell_formats.c +++ b/src/test/test_cell_formats.c @@ -1,24 +1,29 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CONNECTION_EDGE_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "channel.h" -#include "connection_edge.h" -#include "connection_or.h" -#include "config.h" -#include "crypto_rand.h" -#include "onion.h" -#include "onion_tap.h" -#include "onion_fast.h" -#include "onion_ntor.h" -#include "relay.h" -#include "test.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/connection_edge.h" +#include "core/or/connection_or.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/crypto/onion.h" +#include "core/crypto/onion_tap.h" +#include "core/crypto/onion_fast.h" +#include "core/crypto/onion_ntor.h" +#include "core/or/relay.h" + +#include "core/or/cell_st.h" +#include "core/or/cell_queue_st.h" +#include "core/or/var_cell_st.h" + +#include "test/test.h" #include <stdlib.h> #include <string.h> @@ -1297,4 +1302,3 @@ struct testcase_t cell_format_tests[] = { TEST(is_destroy, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_cell_queue.c b/src/test/test_cell_queue.c index df987f82ce..d74bb9c622 100644 --- a/src/test/test_cell_queue.c +++ b/src/test/test_cell_queue.c @@ -1,12 +1,17 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITLIST_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "circuitlist.h" -#include "relay.h" -#include "test.h" +#include "core/or/or.h" +#include "core/or/circuitlist.h" +#include "core/or/relay.h" +#include "test/test.h" + +#include "core/or/cell_st.h" +#include "core/or/cell_queue_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" static void test_cq_manip(void *arg) diff --git a/src/test/test_channel.c b/src/test/test_channel.c index 76124a6e75..26af8de917 100644 --- a/src/test/test_channel.c +++ b/src/test/test_channel.c @@ -1,29 +1,35 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define CHANNEL_PRIVATE_ -#include "or.h" -#include "channel.h" +#include "core/or/or.h" +#include "core/or/channel.h" /* For channel_note_destroy_not_pending */ #define CIRCUITLIST_PRIVATE -#include "circuitlist.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitmux.h" +#include "core/or/circuitmux_ewma.h" /* For var_cell_free */ -#include "connection_or.h" -#include "crypto_rand.h" +#include "core/or/connection_or.h" +#include "lib/crypt_ops/crypto_rand.h" /* For packed_cell stuff */ #define RELAY_PRIVATE -#include "relay.h" +#include "core/or/relay.h" /* For init/free stuff */ -#include "scheduler.h" -#include "networkstatus.h" +#include "core/or/scheduler.h" +#include "feature/nodelist/networkstatus.h" + +#include "core/or/cell_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/nodelist/routerstatus_st.h" +#include "core/or/var_cell_st.h" /* Test suite stuff */ -#include "log_test_helpers.h" -#include "test.h" -#include "fakechans.h" +#include "test/log_test_helpers.h" +#include "test/test.h" +#include "test/fakechans.h" static int test_chan_accept_cells = 0; static int test_chan_fixed_cells_recved = 0; @@ -548,7 +554,7 @@ test_channel_outbound_cell(void *arg) /* Set the test time to be mocked, since this test assumes that no * time will pass, ewma values will not need to be re-scaled, and so on */ monotime_enable_test_mocking(); - monotime_set_mock_time_nsec(U64_LITERAL(1000000000) * 12345); + monotime_set_mock_time_nsec(UINT64_C(1000000000) * 12345); cmux_ewma_set_options(NULL,NULL); diff --git a/src/test/test_channelpadding.c b/src/test/test_channelpadding.c index 4261bc1b67..5d696b8b80 100644 --- a/src/test/test_channelpadding.c +++ b/src/test/test_channelpadding.c @@ -1,24 +1,32 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define MAIN_PRIVATE #define NETWORKSTATUS_PRIVATE #define TOR_TIMERS_PRIVATE -#include "or.h" -#include "test.h" -#include "testsupport.h" -#include "connection.h" -#include "connection_or.h" -#include "channel.h" -#include "channeltls.h" -#include "channelpadding.h" -#include "compat_libevent.h" -#include "config.h" -#include "compat_time.h" -#include "main.h" -#include "networkstatus.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "test/test.h" +#include "lib/testsupport/testsupport.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/channelpadding.h" +#include "lib/evloop/compat_libevent.h" +#include "app/config/config.h" +#include "lib/time/compat_time.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "test/log_test_helpers.h" +#include "lib/tls/tortls.h" +#include "lib/evloop/timers.h" +#include "lib/container/buffers.h" + +#include "core/or/cell_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/or_connection_st.h" +#include "feature/nodelist/routerstatus_st.h" int channelpadding_get_netflow_inactive_timeout_ms(channel_t *chan); int64_t channelpadding_compute_time_until_pad_for_netflow(channel_t *chan); @@ -1163,4 +1171,3 @@ struct testcase_t channelpadding_tests[] = { TEST_CHANNELPADDING(channelpadding_timers, TT_FORK), END_OF_TESTCASES }; - diff --git a/src/test/test_channeltls.c b/src/test/test_channeltls.c index 94f1893cae..787a30a85d 100644 --- a/src/test/test_channeltls.c +++ b/src/test/test_channeltls.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,20 +6,23 @@ #include <math.h> #define TOR_CHANNEL_INTERNAL_ -#include "or.h" -#include "address.h" -#include "buffers.h" -#include "channel.h" -#include "channeltls.h" -#include "connection_or.h" -#include "config.h" +#include "core/or/or.h" +#include "lib/net/address.h" +#include "lib/container/buffers.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "app/config/config.h" /* For init/free stuff */ -#include "scheduler.h" -#include "tortls.h" +#include "core/or/scheduler.h" +#include "lib/tls/tortls.h" + +#include "core/or/or_connection_st.h" /* Test suite stuff */ -#include "test.h" -#include "fakechans.h" +#include "test/test.h" +#include "test/fakechans.h" /* The channeltls unit tests */ static void test_channeltls_create(void *arg); @@ -334,4 +337,3 @@ struct testcase_t channeltls_tests[] = { TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_checkdir.c b/src/test/test_checkdir.c index bf6a8376b3..652e308ed8 100644 --- a/src/test/test_checkdir.c +++ b/src/test/test_checkdir.c @@ -1,8 +1,8 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "core/or/or.h" #ifdef _WIN32 #include <direct.h> @@ -10,9 +10,12 @@ #include <dirent.h> #endif -#include "config.h" -#include "test.h" -#include "util.h" +#include "app/config/config.h" +#include "test/test.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif #ifdef _WIN32 #define mkdir(a,b) mkdir(a) @@ -146,4 +149,3 @@ struct testcase_t checkdir_tests[] = { CHECKDIR(perms, TT_FORK), END_OF_TESTCASES }; - diff --git a/src/test/test_circuitbuild.c b/src/test/test_circuitbuild.c index a5282df69d..02eadecd98 100644 --- a/src/test/test_circuitbuild.c +++ b/src/test/test_circuitbuild.c @@ -1,16 +1,19 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2016, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE -#include "or.h" -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "config.h" -#include "circuitbuild.h" +#include "core/or/or.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "app/config/config.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" + +#include "core/or/extend_info_st.h" /* Dummy nodes smartlist for testing */ static smartlist_t dummy_nodes; @@ -130,4 +133,3 @@ struct testcase_t circuitbuild_tests[] = { { "unhandled_exit", test_new_route_len_unhandled_exit, 0, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c index 3794ffc2c6..8dd7f5f5a9 100644 --- a/src/test/test_circuitlist.c +++ b/src/test/test_circuitlist.c @@ -1,18 +1,23 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITBUILD_PRIVATE #define CIRCUITLIST_PRIVATE #define HS_CIRCUITMAP_PRIVATE -#include "or.h" -#include "channel.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuitmux_ewma.h" -#include "hs_circuitmap.h" -#include "test.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitmux_ewma.h" +#include "feature/hs/hs_circuitmap.h" +#include "test/test.h" +#include "test/log_test_helpers.h" + +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" + +#include "lib/container/bitarray.h" static channel_t * new_fake_channel(void) @@ -467,4 +472,3 @@ struct testcase_t circuitlist_tests[] = { TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_circuitmux.c b/src/test/test_circuitmux.c index 14c7598703..1d46f8de0d 100644 --- a/src/test/test_circuitmux.c +++ b/src/test/test_circuitmux.c @@ -1,17 +1,19 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITMUX_PRIVATE #define CIRCUITMUX_EWMA_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "channel.h" -#include "circuitmux.h" -#include "circuitmux_ewma.h" -#include "relay.h" -#include "scheduler.h" -#include "test.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/circuitmux.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/relay.h" +#include "core/or/scheduler.h" +#include "test/test.h" + +#include "core/or/destroy_cell_queue_st.h" /* XXXX duplicated function from test_circuitlist.c */ static channel_t * @@ -84,7 +86,7 @@ static void test_cmux_compute_ticks(void *arg) { const int64_t NS_PER_S = 1000 * 1000 * 1000; - const int64_t START_NS = U64_LITERAL(1217709000)*NS_PER_S; + const int64_t START_NS = UINT64_C(1217709000)*NS_PER_S; int64_t now; double rem; unsigned tick; diff --git a/src/test/test_circuitstats.c b/src/test/test_circuitstats.c index 8ebef659ca..c3cfad88da 100644 --- a/src/test/test_circuitstats.c +++ b/src/test/test_circuitstats.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITBUILD_PRIVATE @@ -6,16 +6,21 @@ #define CIRCUITLIST_PRIVATE #define CHANNEL_PRIVATE_ -#include "or.h" -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "config.h" -#include "circuitlist.h" -#include "circuitbuild.h" -#include "circuitstats.h" -#include "circuituse.h" -#include "channel.h" +#include "core/or/or.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "app/config/config.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitstats.h" +#include "core/or/circuituse.h" +#include "core/or/channel.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/extend_info_st.h" +#include "core/or/origin_circuit_st.h" void test_circuitstats_timeout(void *arg); void test_circuitstats_hoplen(void *arg); diff --git a/src/test/test_circuituse.c b/src/test/test_circuituse.c index df1b43807f..720adeac84 100644 --- a/src/test/test_circuituse.c +++ b/src/test/test_circuituse.c @@ -1,18 +1,21 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CIRCUITLIST_PRIVATE -#include "or.h" -#include "test.h" -#include "test_helpers.h" -#include "config.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "circuitbuild.h" -#include "nodelist.h" +#include "core/or/or.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "app/config/config.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "core/or/circuitbuild.h" +#include "feature/nodelist/nodelist.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/origin_circuit_st.h" static void test_circuit_is_available_for_use_ret_false_when_marked_for_close(void *arg) diff --git a/src/test/test_compat_libevent.c b/src/test/test_compat_libevent.c index 85f69bd626..3f505d013b 100644 --- a/src/test/test_compat_libevent.c +++ b/src/test/test_compat_libevent.c @@ -1,17 +1,17 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define COMPAT_LIBEVENT_PRIVATE #include "orconfig.h" -#include "or.h" +#include "core/or/or.h" -#include "test.h" +#include "test/test.h" -#include "compat_libevent.h" +#include "lib/evloop/compat_libevent.h" #include <event2/event.h> -#include "log_test_helpers.h" +#include "test/log_test_helpers.h" #define NS_MODULE compat_libevent diff --git a/src/test/test_config.c b/src/test/test_config.c index 461aa646d6..af3a8a7cfe 100644 --- a/src/test/test_config.c +++ b/src/test/test_config.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,41 +8,56 @@ #define CONFIG_PRIVATE #define PT_PRIVATE #define ROUTERSET_PRIVATE -#include "or.h" -#include "address.h" -#include "addressmap.h" -#include "bridges.h" -#include "circuitmux_ewma.h" -#include "circuitbuild.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "test.h" -#include "util.h" -#include "connection_or.h" -#include "control.h" -#include "cpuworker.h" -#include "dirserv.h" -#include "dirauth/dirvote.h" -#include "dns.h" -#include "entrynodes.h" -#include "transports.h" -#include "ext_orport.h" -#include "geoip.h" -#include "hibernate.h" -#include "main.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "rendclient.h" -#include "rendservice.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "statefile.h" - -#include "test_helpers.h" +#include "core/or/or.h" +#include "lib/net/address.h" +#include "feature/client/addressmap.h" +#include "feature/client/bridges.h" +#include "core/or/circuitmux_ewma.h" +#include "core/or/circuitbuild.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "test/test.h" +#include "core/or/connection_or.h" +#include "feature/control/control.h" +#include "core/mainloop/cpuworker.h" +#include "feature/dircache/dirserv.h" +#include "feature/dirauth/dirvote.h" +#include "feature/relay/dns.h" +#include "feature/client/entrynodes.h" +#include "feature/client/transports.h" +#include "feature/relay/ext_orport.h" +#include "feature/stats/geoip.h" +#include "feature/hibernate/hibernate.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/rend/rendclient.h" +#include "feature/rend/rendservice.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "app/config/statefile.h" + +#include "test/test_helpers.h" + +#include "feature/dirclient/dir_server_st.h" +#include "core/or/port_cfg_st.h" +#include "feature/nodelist/routerinfo_st.h" + +#include "lib/fs/conffile.h" +#include "lib/meminfo/meminfo.h" +#include "lib/net/gethostname.h" +#include "lib/encoding/confline.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif static void test_config_addressmap(void *arg) @@ -1619,6 +1634,40 @@ test_config_parsing_trusted_dir_server(void *arg) #undef TEST_DIR_AUTH_LINE_END #undef TEST_DIR_AUTH_IPV6_FLAG +#define TEST_DIR_AUTH_LINE_START \ + "foobar orport=12345 " \ + "v3ident=14C131DFC5C6F93646BE72FA1401C02A8DF2E8B4 " +#define TEST_DIR_AUTH_LINE_END_BAD_IP \ + "0.256.3.4:54321 " \ + "FDB2 FBD2 AAA5 25FA 2999 E617 5091 5A32 C777 3B17" +#define TEST_DIR_AUTH_LINE_END_WITH_DNS_ADDR \ + "torproject.org:54321 " \ + "FDB2 FBD2 AAA5 25FA 2999 E617 5091 5A32 C777 3B17" + +static void +test_config_parsing_invalid_dir_address(void *arg) +{ + (void)arg; + int rv; + + rv = parse_dir_authority_line(TEST_DIR_AUTH_LINE_START + TEST_DIR_AUTH_LINE_END_BAD_IP, + V3_DIRINFO, 1); + tt_int_op(rv, OP_EQ, -1); + + rv = parse_dir_authority_line(TEST_DIR_AUTH_LINE_START + TEST_DIR_AUTH_LINE_END_WITH_DNS_ADDR, + V3_DIRINFO, 1); + tt_int_op(rv, OP_EQ, -1); + + done: + return; +} + +#undef TEST_DIR_AUTH_LINE_START +#undef TEST_DIR_AUTH_LINE_END_BAD_IP +#undef TEST_DIR_AUTH_LINE_END_WITH_DNS_ADDR + /* No secrets here: * id is `echo "syn-propanethial-S-oxide" | shasum | cut -d" " -f1` */ @@ -3724,7 +3773,7 @@ static void test_config_default_fallback_dirs(void *arg) { const char *fallback[] = { -#include "../or/fallback_dirs.inc" +#include "app/config/fallback_dirs.inc" NULL }; @@ -5611,8 +5660,8 @@ test_config_include_opened_file_list(void *data) static void test_config_compute_max_mem_in_queues(void *data) { -#define GIGABYTE(x) (U64_LITERAL(x) << 30) -#define MEGABYTE(x) (U64_LITERAL(x) << 20) +#define GIGABYTE(x) (UINT64_C(x) << 30) +#define MEGABYTE(x) (UINT64_C(x) << 20) (void)data; MOCK(get_total_system_memory, get_total_system_memory_mock); @@ -5683,6 +5732,7 @@ struct testcase_t config_tests[] = { CONFIG_TEST(adding_trusted_dir_server, TT_FORK), CONFIG_TEST(adding_fallback_dir_server, TT_FORK), CONFIG_TEST(parsing_trusted_dir_server, 0), + CONFIG_TEST(parsing_invalid_dir_address, 0), CONFIG_TEST(parsing_fallback_dir_server, 0), CONFIG_TEST(adding_default_trusted_dir_servers, TT_FORK), CONFIG_TEST(adding_dir_servers, TT_FORK), @@ -5727,4 +5777,3 @@ struct testcase_t config_tests[] = { CONFIG_TEST(compute_max_mem_in_queues, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_connection.c b/src/test/test_connection.c index dc0f6860d9..c423c6573f 100644 --- a/src/test/test_connection.c +++ b/src/test/test_connection.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -7,21 +7,29 @@ #define MAIN_PRIVATE #define CONNECTION_OR_PRIVATE -#include "or.h" -#include "test.h" - -#include "connection.h" -#include "hs_common.h" -#include "main.h" -#include "microdesc.h" -#include "nodelist.h" -#include "networkstatus.h" -#include "rendcache.h" -#include "directory.h" -#include "connection_or.h" - -#include "test_connection.h" -#include "test_helpers.h" +#include "core/or/or.h" +#include "test/test.h" + +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/hs/hs_common.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/rend/rendcache.h" +#include "feature/dircache/directory.h" +#include "core/or/connection_or.h" + +#include "test/test_connection.h" +#include "test/test_helpers.h" + +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/or_connection_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "core/or/socks_request_st.h" static void * test_conn_get_basic_setup(const struct testcase_t *tc); static int test_conn_get_basic_teardown(const struct testcase_t *tc, diff --git a/src/test/test_connection.h b/src/test/test_connection.h index 392783b53b..27c296504a 100644 --- a/src/test/test_connection.h +++ b/src/test/test_connection.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** Some constants used by test_connection and helpers */ diff --git a/src/test/test_conscache.c b/src/test/test_conscache.c index ffec3149b0..b5cbd72515 100644 --- a/src/test/test_conscache.c +++ b/src/test/test_conscache.c @@ -1,10 +1,11 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "config.h" -#include "conscache.h" -#include "test.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/dircache/conscache.h" +#include "lib/encoding/confline.h" +#include "test/test.h" #ifdef HAVE_UTIME_H #include <utime.h> @@ -337,4 +338,3 @@ struct testcase_t conscache_tests[] = { ENT(filter), END_OF_TESTCASES }; - diff --git a/src/test/test_consdiff.c b/src/test/test_consdiff.c index fda3a7f186..b836befd22 100644 --- a/src/test/test_consdiff.c +++ b/src/test/test_consdiff.c @@ -1,15 +1,15 @@ /* Copyright (c) 2014, Daniel Martà - * Copyright (c) 2014, The Tor Project, Inc. */ + * Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFF_PRIVATE -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" -#include "consdiff.h" -#include "memarea.h" -#include "log_test_helpers.h" +#include "feature/dircommon/consdiff.h" +#include "lib/memarea/memarea.h" +#include "test/log_test_helpers.h" #define tt_str_eq_line(a,b) \ tt_assert(line_str_eq((b),(a))) diff --git a/src/test/test_consdiffmgr.c b/src/test/test_consdiffmgr.c index 3b91baca39..6c0601b504 100644 --- a/src/test/test_consdiffmgr.c +++ b/src/test/test_consdiffmgr.c @@ -1,21 +1,25 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONSDIFFMGR_PRIVATE -#include "or.h" -#include "config.h" -#include "conscache.h" -#include "consdiff.h" -#include "consdiffmgr.h" -#include "cpuworker.h" -#include "crypto_rand.h" -#include "networkstatus.h" -#include "routerparse.h" -#include "workqueue.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/dircache/conscache.h" +#include "feature/dircommon/consdiff.h" +#include "feature/dircache/consdiffmgr.h" +#include "core/mainloop/cpuworker.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/routerparse.h" +#include "lib/evloop/workqueue.h" +#include "lib/compress/compress.h" +#include "lib/encoding/confline.h" -#include "test.h" -#include "log_test_helpers.h" +#include "feature/nodelist/networkstatus_st.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" // ============================== Setup/teardown the consdiffmgr // These functions get run before/after each test in this module @@ -894,4 +898,3 @@ struct testcase_t consdiffmgr_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_containers.c b/src/test/test_containers.c index 3fc3523af4..717eb0892a 100644 --- a/src/test/test_containers.c +++ b/src/test/test_containers.c @@ -1,13 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" -#include "crypto_rand.h" -#include "fp_pair.h" -#include "test.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircommon/fp_pair.h" +#include "test/test.h" + +#include "lib/container/bitarray.h" +#include "lib/container/order.h" +#include "lib/crypt_ops/digestset.h" /** Helper: return a tristate based on comparing the strings in *<b>a</b> and * *<b>b</b>. */ @@ -640,18 +644,18 @@ test_container_digestset(void *arg) } set = digestset_new(1000); SMARTLIST_FOREACH(included, const char *, cp, - if (digestset_contains(set, cp)) + if (digestset_probably_contains(set, cp)) ok = 0); tt_assert(ok); SMARTLIST_FOREACH(included, const char *, cp, digestset_add(set, cp)); SMARTLIST_FOREACH(included, const char *, cp, - if (!digestset_contains(set, cp)) + if (!digestset_probably_contains(set, cp)) ok = 0); tt_assert(ok); for (i = 0; i < 1000; ++i) { crypto_rand(d, DIGEST_LEN); - if (digestset_contains(set, d)) + if (digestset_probably_contains(set, d)) ++false_positives; } tt_int_op(50, OP_GT, false_positives); /* Should be far lower. */ @@ -1295,4 +1299,3 @@ struct testcase_t container_tests[] = { CONTAINER(smartlist_strings_eq, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_controller.c b/src/test/test_controller.c index 1a350f66c0..2ded04619c 100644 --- a/src/test/test_controller.c +++ b/src/test/test_controller.c @@ -1,17 +1,24 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONTROL_PRIVATE -#include "or.h" -#include "bridges.h" -#include "control.h" -#include "entrynodes.h" -#include "hs_common.h" -#include "networkstatus.h" -#include "rendservice.h" -#include "routerlist.h" -#include "test.h" -#include "test_helpers.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/client/bridges.h" +#include "feature/control/control.h" +#include "feature/client/entrynodes.h" +#include "feature/hs/hs_common.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/rend/rendservice.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/nodelist.h" +#include "test/test.h" +#include "test/test_helpers.h" + +#include "feature/control/control_connection_st.h" +#include "feature/dirclient/download_status_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/node_st.h" static void test_add_onion_helper_keyarg_v3(void *arg) @@ -1525,6 +1532,80 @@ test_current_time(void *arg) return; } +static size_t n_nodelist_get_list = 0; +static smartlist_t *nodes = NULL; + +static smartlist_t * +mock_nodelist_get_list(void) +{ + n_nodelist_get_list++; + tor_assert(nodes); + + return nodes; +} + +static void +test_getinfo_md_all(void *arg) +{ + char *answer = NULL; + const char *errmsg = NULL; + int retval = 0; + + (void)arg; + + node_t *node1 = tor_malloc(sizeof(node_t)); + memset(node1, 0, sizeof(node_t)); + node1->md = tor_malloc(sizeof(microdesc_t)); + memset(node1->md, 0, sizeof(microdesc_t)); + node1->md->body = tor_strdup("md1\n"); + node1->md->bodylen = 4; + + node_t *node2 = tor_malloc(sizeof(node_t)); + memset(node2, 0, sizeof(node_t)); + node2->md = tor_malloc(sizeof(microdesc_t)); + memset(node2->md, 0, sizeof(microdesc_t)); + node2->md->body = tor_strdup("md2\n"); + node2->md->bodylen = 4; + + MOCK(nodelist_get_list, mock_nodelist_get_list); + + nodes = smartlist_new(); + + retval = getinfo_helper_dir(NULL, "md/all", &answer, &errmsg); + + tt_int_op(n_nodelist_get_list, OP_EQ, 1); + tt_int_op(retval, OP_EQ, 0); + tt_assert(answer != NULL); + tt_assert(errmsg == NULL); + tt_str_op(answer, OP_EQ, ""); + + tor_free(answer); + + smartlist_add(nodes, node1); + smartlist_add(nodes, node2); + + retval = getinfo_helper_dir(NULL, "md/all", &answer, &errmsg); + + tt_int_op(n_nodelist_get_list, OP_EQ, 2); + tt_int_op(retval, OP_EQ, 0); + tt_assert(answer != NULL); + tt_assert(errmsg == NULL); + + tt_str_op(answer, OP_EQ, "md1\nmd2\n"); + + done: + UNMOCK(nodelist_get_list); + tor_free(node1->md->body); + tor_free(node1->md); + tor_free(node1); + tor_free(node2->md->body); + tor_free(node2->md); + tor_free(node2); + tor_free(answer); + smartlist_free(nodes); + return; +} + struct testcase_t controller_tests[] = { { "add_onion_helper_keyarg_v2", test_add_onion_helper_keyarg_v2, 0, NULL, NULL }, @@ -1542,6 +1623,6 @@ struct testcase_t controller_tests[] = { { "download_status_desc", test_download_status_desc, 0, NULL, NULL }, { "download_status_bridge", test_download_status_bridge, 0, NULL, NULL }, { "current_time", test_current_time, 0, NULL, NULL }, + { "getinfo_md_all", test_getinfo_md_all, 0, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_controller_events.c b/src/test/test_controller_events.c index e81aea8d66..e935b70428 100644 --- a/src/test/test_controller_events.c +++ b/src/test/test_controller_events.c @@ -1,15 +1,19 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONNECTION_PRIVATE #define TOR_CHANNEL_INTERNAL_ #define CONTROL_PRIVATE -#include "or.h" -#include "channel.h" -#include "channeltls.h" -#include "connection.h" -#include "control.h" -#include "test.h" +#include "core/or/or.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/or/circuitlist.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "test/test.h" + +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" static void add_testing_cell_stats_entry(circuit_t *circ, uint8_t command, @@ -328,4 +332,3 @@ struct testcase_t controller_event_tests[] = { TEST(event_mask, TT_FORK), END_OF_TESTCASES }; - diff --git a/src/test/test_crypto.c b/src/test/test_crypto.c index bb2e340dd2..2124e22196 100644 --- a/src/test/test_crypto.c +++ b/src/test/test_crypto.c @@ -1,21 +1,30 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CRYPTO_CURVE25519_PRIVATE #define CRYPTO_RAND_PRIVATE -#include "or.h" -#include "test.h" -#include "aes.h" -#include "util.h" +#include "core/or/or.h" +#include "test/test.h" +#include "lib/crypt_ops/aes.h" #include "siphash.h" -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_hkdf.h" +#include "lib/crypt_ops/crypto_rand.h" #include "ed25519_vectors.inc" +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + /** Run unit tests for Diffie-Hellman functionality. */ static void test_crypto_dh(void *arg) @@ -23,38 +32,39 @@ test_crypto_dh(void *arg) crypto_dh_t *dh1 = crypto_dh_new(DH_TYPE_CIRCUIT); crypto_dh_t *dh1_dup = NULL; crypto_dh_t *dh2 = crypto_dh_new(DH_TYPE_CIRCUIT); - char p1[DH_BYTES]; - char p2[DH_BYTES]; - char s1[DH_BYTES]; - char s2[DH_BYTES]; + char p1[DH1024_KEY_LEN]; + char p2[DH1024_KEY_LEN]; + char s1[DH1024_KEY_LEN]; + char s2[DH1024_KEY_LEN]; ssize_t s1len, s2len; (void)arg; - tt_int_op(crypto_dh_get_bytes(dh1),OP_EQ, DH_BYTES); - tt_int_op(crypto_dh_get_bytes(dh2),OP_EQ, DH_BYTES); + tt_int_op(crypto_dh_get_bytes(dh1),OP_EQ, DH1024_KEY_LEN); + tt_int_op(crypto_dh_get_bytes(dh2),OP_EQ, DH1024_KEY_LEN); - memset(p1, 0, DH_BYTES); - memset(p2, 0, DH_BYTES); - tt_mem_op(p1,OP_EQ, p2, DH_BYTES); + memset(p1, 0, DH1024_KEY_LEN); + memset(p2, 0, DH1024_KEY_LEN); + tt_mem_op(p1,OP_EQ, p2, DH1024_KEY_LEN); tt_int_op(-1, OP_EQ, crypto_dh_get_public(dh1, p1, 6)); /* too short */ - tt_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES)); - tt_mem_op(p1,OP_NE, p2, DH_BYTES); - tt_assert(! crypto_dh_get_public(dh2, p2, DH_BYTES)); - tt_mem_op(p1,OP_NE, p2, DH_BYTES); + tt_assert(! crypto_dh_get_public(dh1, p1, DH1024_KEY_LEN)); + tt_mem_op(p1,OP_NE, p2, DH1024_KEY_LEN); + tt_assert(! crypto_dh_get_public(dh2, p2, DH1024_KEY_LEN)); + tt_mem_op(p1,OP_NE, p2, DH1024_KEY_LEN); - memset(s1, 0, DH_BYTES); - memset(s2, 0xFF, DH_BYTES); - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p2, DH_BYTES, s1, 50); - s2len = crypto_dh_compute_secret(LOG_WARN, dh2, p1, DH_BYTES, s2, 50); + memset(s1, 0, DH1024_KEY_LEN); + memset(s2, 0xFF, DH1024_KEY_LEN); + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p2, DH1024_KEY_LEN, s1, 50); + s2len = crypto_dh_compute_secret(LOG_WARN, dh2, p1, DH1024_KEY_LEN, s2, 50); tt_assert(s1len > 0); tt_int_op(s1len,OP_EQ, s2len); tt_mem_op(s1,OP_EQ, s2, s1len); /* test dh_dup; make sure it works the same. */ dh1_dup = crypto_dh_dup(dh1); - s1len = crypto_dh_compute_secret(LOG_WARN, dh1_dup, p2, DH_BYTES, s1, 50); + s1len = crypto_dh_compute_secret(LOG_WARN, dh1_dup, p2, DH1024_KEY_LEN, + s1, 50); tt_mem_op(s1,OP_EQ, s2, s1len); { @@ -67,12 +77,14 @@ test_crypto_dh(void *arg) s1len = crypto_dh_compute_secret(LOG_WARN, dh1, "\x00", 1, s1, 50); tt_int_op(-1, OP_EQ, s1len); - memset(p1, 0, DH_BYTES); /* 0 with padding. */ - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + memset(p1, 0, DH1024_KEY_LEN); /* 0 with padding. */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); - p1[DH_BYTES-1] = 1; /* 1 with padding*/ - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + p1[DH1024_KEY_LEN-1] = 1; /* 1 with padding*/ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); /* 2 is okay, though weird. */ @@ -89,15 +101,18 @@ test_crypto_dh(void *arg) /* p-1, p, and so on are not okay. */ base16_decode(p1, sizeof(p1), P, strlen(P)); - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); - p1[DH_BYTES-1] = 0xFE; /* p-1 */ - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + p1[DH1024_KEY_LEN-1] = 0xFE; /* p-1 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); - p1[DH_BYTES-1] = 0xFD; /* p-2 works fine */ - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + p1[DH1024_KEY_LEN-1] = 0xFD; /* p-2 works fine */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(50, OP_EQ, s1len); const char P_plus_one[] = @@ -109,31 +124,35 @@ test_crypto_dh(void *arg) base16_decode(p1, sizeof(p1), P_plus_one, strlen(P_plus_one)); - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); - p1[DH_BYTES-1] = 0x01; /* p+2 */ - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + p1[DH1024_KEY_LEN-1] = 0x01; /* p+2 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); - p1[DH_BYTES-1] = 0xff; /* p+256 */ - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + p1[DH1024_KEY_LEN-1] = 0xff; /* p+256 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); - memset(p1, 0xff, DH_BYTES), /* 2^1024-1 */ - s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH_BYTES, s1, 50); + memset(p1, 0xff, DH1024_KEY_LEN), /* 2^1024-1 */ + s1len = crypto_dh_compute_secret(LOG_WARN, dh1, p1, DH1024_KEY_LEN, + s1, 50); tt_int_op(-1, OP_EQ, s1len); } { /* provoke an error in the openssl DH_compute_key function; make sure we * survive. */ - tt_assert(! crypto_dh_get_public(dh1, p1, DH_BYTES)); + tt_assert(! crypto_dh_get_public(dh1, p1, DH1024_KEY_LEN)); crypto_dh_free(dh2); dh2= crypto_dh_new(DH_TYPE_CIRCUIT); /* no private key set */ s1len = crypto_dh_compute_secret(LOG_WARN, dh2, - p1, DH_BYTES, + p1, DH1024_KEY_LEN, s1, 50); tt_int_op(s1len, OP_EQ, -1); } @@ -152,8 +171,13 @@ test_crypto_openssl_version(void *arg) const char *h_version = crypto_openssl_get_header_version_str(); tt_assert(version); tt_assert(h_version); - tt_assert(!strcmpstart(version, h_version)); /* "-fips" suffix, etc */ - tt_assert(!strstr(version, "OpenSSL")); + if (strcmpstart(version, h_version)) { /* "-fips" suffix, etc */ + TT_DIE(("OpenSSL library version %s did not begin with header version %s.", + version, h_version)); + } + if (strstr(version, "OpenSSL")) { + TT_DIE(("assertion failed: !strstr(\"%s\", \"OpenSSL\")", version)); + } int a=-1,b=-1,c=-1; if (!strcmpstart(version, "LibreSSL") || !strcmpstart(version, "BoringSSL")) return; @@ -190,10 +214,10 @@ test_crypto_rng(void *arg) j = crypto_rand_int(100); if (j < 0 || j >= 100) allok = 0; - big = crypto_rand_uint64(U64_LITERAL(1)<<40); - if (big >= (U64_LITERAL(1)<<40)) + big = crypto_rand_uint64(UINT64_C(1)<<40); + if (big >= (UINT64_C(1)<<40)) allok = 0; - big = crypto_rand_uint64(U64_LITERAL(5)); + big = crypto_rand_uint64(UINT64_C(5)); if (big >= 5) allok = 0; d = crypto_rand_double(); @@ -1817,15 +1841,6 @@ test_crypto_hkdf_sha256(void *arg) key_material, 100) /* Test vectors generated with ntor_ref.py */ - memset(key_material, 0, sizeof(key_material)); - EXPAND(""); - tt_int_op(r, OP_EQ, 0); - test_memeq_hex(key_material, - "d3490ed48b12a48f9547861583573fe3f19aafe3f81dc7fc75" - "eeed96d741b3290f941576c1f9f0b2d463d1ec7ab2c6bf71cd" - "d7f826c6298c00dbfe6711635d7005f0269493edf6046cc7e7" - "dcf6abe0d20c77cf363e8ffe358927817a3d3e73712cee28d8"); - EXPAND("Tor"); tt_int_op(r, OP_EQ, 0); test_memeq_hex(key_material, @@ -2810,8 +2825,8 @@ test_crypto_siphash(void *arg) { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, } }; - const struct sipkey K = { U64_LITERAL(0x0706050403020100), - U64_LITERAL(0x0f0e0d0c0b0a0908) }; + const struct sipkey K = { UINT64_C(0x0706050403020100), + UINT64_C(0x0f0e0d0c0b0a0908) }; uint8_t input[64]; int i, j; @@ -2866,12 +2881,12 @@ crypto_rand_check_failure_mode_identical(void) { /* just in case the buffer size isn't a multiple of sizeof(int64_t) */ #define FAILURE_MODE_BUFFER_SIZE_I64 \ - (FAILURE_MODE_BUFFER_SIZE/SIZEOF_INT64_T) + (FAILURE_MODE_BUFFER_SIZE/8) #define FAILURE_MODE_BUFFER_SIZE_I64_BYTES \ - (FAILURE_MODE_BUFFER_SIZE_I64*SIZEOF_INT64_T) + (FAILURE_MODE_BUFFER_SIZE_I64*8) #if FAILURE_MODE_BUFFER_SIZE_I64 < 2 -#error FAILURE_MODE_BUFFER_SIZE needs to be at least 2*SIZEOF_INT64_T +#error FAILURE_MODE_BUFFER_SIZE needs to be at least 2*8 #endif int64_t buf[FAILURE_MODE_BUFFER_SIZE_I64]; @@ -3067,4 +3082,3 @@ struct testcase_t crypto_tests[] = { { "failure_modes", test_crypto_failure_modes, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_crypto_openssl.c b/src/test/test_crypto_openssl.c index a016277508..b1a5613eaf 100644 --- a/src/test/test_crypto_openssl.c +++ b/src/test/test_crypto_openssl.c @@ -1,21 +1,21 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CRYPTO_RAND_PRIVATE -#include "crypto_rand.h" -#include "util.h" -#include "util_format.h" -#include "compat.h" -#include "test.h" +#include "lib/crypt_ops/compat_openssl.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/encoding/binascii.h" +#include "lib/malloc/util_malloc.h" +#include "test/test.h" #include <openssl/evp.h> #include <openssl/rand.h> -#include "compat_openssl.h" +#include <string.h> /* Test for rectifying openssl RAND engine. */ static void @@ -104,4 +104,3 @@ struct testcase_t crypto_openssl_tests[] = { TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_crypto_slow.c b/src/test/test_crypto_slow.c index 0e1f5bd227..88b31ad9af 100644 --- a/src/test/test_crypto_slow.c +++ b/src/test/test_crypto_slow.c @@ -1,15 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define CRYPTO_S2K_PRIVATE -#include "or.h" -#include "test.h" -#include "crypto_s2k.h" -#include "crypto_pwbox.h" -#include "crypto_rand.h" +#include "core/or/or.h" +#include "test/test.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_s2k.h" +#include "lib/crypt_ops/crypto_pwbox.h" +#include "lib/crypt_ops/crypto_rand.h" #if defined(HAVE_LIBSCRYPT_H) && defined(HAVE_LIBSCRYPT_SCRYPT) #define HAVE_LIBSCRYPT @@ -615,4 +617,3 @@ struct testcase_t slow_crypto_tests[] = { ED25519_TEST(fuzz_donna, TT_FORK), END_OF_TESTCASES }; - diff --git a/src/test/test_data.c b/src/test/test_data.c index ce6c3394f6..be8153258b 100644 --- a/src/test/test_data.c +++ b/src/test/test_data.c @@ -1,9 +1,9 @@ /* Copyright 2001-2004 Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "test.h" +#include "test/test.h" /* Our unit test expect that the AUTHORITY_CERT_* public keys will sort * in this order. */ diff --git a/src/test/test_dir.c b/src/test/test_dir.c index b42755e351..bda56b3a8e 100644 --- a/src/test/test_dir.c +++ b/src/test/test_dir.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -17,32 +17,55 @@ #define NETWORKSTATUS_PRIVATE #define RELAY_PRIVATE -#include "or.h" -#include "bridges.h" -#include "confparse.h" -#include "config.h" -#include "control.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirserv.h" -#include "dirauth/dirvote.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "memarea.h" -#include "networkstatus.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "dirauth/shared_random_state.h" -#include "test.h" -#include "test_dir_common.h" -#include "torcert.h" -#include "relay.h" -#include "log_test_helpers.h" -#include "voting_schedule.h" +#include "core/or/or.h" +#include "feature/client/bridges.h" +#include "core/mainloop/connection.h" +#include "app/config/confparse.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircache/directory.h" +#include "feature/dircache/dirserv.h" +#include "feature/dirauth/dirvote.h" +#include "feature/client/entrynodes.h" +#include "feature/dircommon/fp_pair.h" +#include "feature/hibernate/hibernate.h" +#include "lib/memarea/memarea.h" +#include "lib/osinfo/uname.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "feature/dirauth/shared_random_state.h" +#include "test/test.h" +#include "test/test_dir_common.h" +#include "feature/nodelist/torcert.h" +#include "core/or/relay.h" +#include "test/log_test_helpers.h" +#include "feature/dircommon/voting_schedule.h" +#include "lib/compress/compress.h" + +#include "core/or/addr_policy_st.h" +#include "feature/nodelist/authority_cert_st.h" +#include "feature/nodelist/document_signature_st.h" +#include "feature/nodelist/extrainfo_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/networkstatus_voter_info_st.h" +#include "feature/dirauth/ns_detached_signatures_st.h" +#include "core/or/port_cfg_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" +#include "core/or/tor_version_st.h" +#include "feature/dirauth/vote_microdesc_hash_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif #define NS_MODULE dir @@ -2087,7 +2110,7 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now) tt_int_op(rs->or_port,OP_EQ, 443); tt_int_op(rs->dir_port,OP_EQ, 8000); /* no flags except "running" (16) and "v2dir" (64) and "valid" (128) */ - tt_u64_op(vrs->flags, OP_EQ, U64_LITERAL(0xd0)); + tt_u64_op(vrs->flags, OP_EQ, UINT64_C(0xd0)); } else if (tor_memeq(rs->identity_digest, "\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5\x5" "\x5\x5\x5\x5", @@ -2113,10 +2136,10 @@ test_vrs_for_v3ns(vote_routerstatus_t *vrs, int voter, time_t now) tt_int_op(rs->ipv6_orport,OP_EQ, 4711); if (voter == 1) { /* all except "authority" (1) */ - tt_u64_op(vrs->flags, OP_EQ, U64_LITERAL(254)); + tt_u64_op(vrs->flags, OP_EQ, UINT64_C(254)); } else { /* 1023 - authority(1) - madeofcheese(16) - madeoftin(32) */ - tt_u64_op(vrs->flags, OP_EQ, U64_LITERAL(974)); + tt_u64_op(vrs->flags, OP_EQ, UINT64_C(974)); } } else if (tor_memeq(rs->identity_digest, "\x33\x33\x33\x33\x33\x33\x33\x33\x33\x33" @@ -2926,8 +2949,8 @@ test_dir_scale_bw(void *testdata) for (i=0; i<8; ++i) { total += vals_u64[i]; } - tt_assert(total >= (U64_LITERAL(1)<<60)); - tt_assert(total <= (U64_LITERAL(1)<<62)); + tt_assert(total >= (UINT64_C(1)<<60)); + tt_assert(total <= (UINT64_C(1)<<62)); for (i=0; i<8; ++i) { /* vals[2].u64 is the scaled value of 1.0 */ @@ -6028,4 +6051,3 @@ struct testcase_t dir_tests[] = { DIR(networkstatus_consensus_has_ipv6, TT_FORK), END_OF_TESTCASES }; - diff --git a/src/test/test_dir_common.c b/src/test/test_dir_common.c index 230410f7fa..e65e2b0111 100644 --- a/src/test/test_dir_common.c +++ b/src/test/test_dir_common.c @@ -1,18 +1,24 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define DIRVOTE_PRIVATE -#include "test.h" -#include "container.h" -#include "or.h" -#include "dirauth/dirvote.h" -#include "nodelist.h" -#include "routerlist.h" -#include "test_dir_common.h" -#include "voting_schedule.h" +#include "test/test.h" +#include "core/or/or.h" +#include "feature/dirauth/dirvote.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerlist.h" +#include "test/test_dir_common.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/networkstatus_voter_info_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/dirauth/vote_microdesc_hash_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" void dir_common_setup_vote(networkstatus_t **vote, time_t now); networkstatus_t * dir_common_add_rs_and_parse(networkstatus_t *vote, diff --git a/src/test/test_dir_common.h b/src/test/test_dir_common.h index 65b9cf6436..1e90228edb 100644 --- a/src/test/test_dir_common.h +++ b/src/test/test_dir_common.h @@ -1,11 +1,11 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "networkstatus.h" -#include "routerparse.h" +#include "core/or/or.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/routerparse.h" #define TEST_DIR_ROUTER_ID_1 3 #define TEST_DIR_ROUTER_ID_2 5 diff --git a/src/test/test_dir_handle_get.c b/src/test/test_dir_handle_get.c index 688d26bdc1..571b0386e2 100644 --- a/src/test/test_dir_handle_get.c +++ b/src/test/test_dir_handle_get.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define RENDCOMMON_PRIVATE @@ -9,30 +9,37 @@ #define CONFIG_PRIVATE #define RENDCACHE_PRIVATE -#include "or.h" -#include "config.h" -#include "connection.h" -#include "consdiffmgr.h" -#include "directory.h" -#include "test.h" -#include "compress.h" -#include "rendcommon.h" -#include "rendcache.h" -#include "router.h" -#include "routerlist.h" -#include "rend_test_helpers.h" -#include "microdesc.h" -#include "test_helpers.h" -#include "nodelist.h" -#include "entrynodes.h" -#include "routerparse.h" -#include "networkstatus.h" -#include "proto_http.h" -#include "geoip.h" -#include "dirserv.h" -#include "dirauth/dirvote.h" -#include "log_test_helpers.h" -#include "voting_schedule.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/dircache/consdiffmgr.h" +#include "feature/dircache/directory.h" +#include "test/test.h" +#include "lib/compress/compress.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendcache.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "test/rend_test_helpers.h" +#include "feature/nodelist/microdesc.h" +#include "test/test_helpers.h" +#include "feature/nodelist/nodelist.h" +#include "feature/client/entrynodes.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/networkstatus.h" +#include "core/proto/proto_http.h" +#include "feature/stats/geoip.h" +#include "feature/dircache/dirserv.h" +#include "feature/dirauth/dirvote.h" +#include "test/log_test_helpers.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/dircommon/dir_connection_st.h" +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerlist_st.h" #ifdef _WIN32 /* For mkdir() */ diff --git a/src/test/test_dns.c b/src/test/test_dns.c index 1fee01d2c0..8369f844f6 100644 --- a/src/test/test_dns.c +++ b/src/test/test_dns.c @@ -1,14 +1,18 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" #define DNS_PRIVATE -#include "dns.h" -#include "connection.h" -#include "router.h" +#include "feature/relay/dns.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/relay/router.h" + +#include "core/or/edge_connection_st.h" +#include "core/or/or_circuit_st.h" #define NS_MODULE dns @@ -745,4 +749,3 @@ struct testcase_t dns_tests[] = { }; #undef NS_MODULE - diff --git a/src/test/test_dos.c b/src/test/test_dos.c index 8ae967f3ae..b411e7b38a 100644 --- a/src/test/test_dos.c +++ b/src/test/test_dos.c @@ -5,18 +5,23 @@ #define TOR_CHANNEL_INTERNAL_ #define CIRCUITLIST_PRIVATE -#include "or.h" -#include "dos.h" -#include "circuitlist.h" -#include "crypto_rand.h" -#include "geoip.h" -#include "channel.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "routerlist.h" -#include "test.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "core/or/dos.h" +#include "core/or/circuitlist.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/stats/geoip.h" +#include "core/or/channel.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerlist.h" + +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/or_connection_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" static networkstatus_t *dummy_ns = NULL; static networkstatus_t * diff --git a/src/test/test_entryconn.c b/src/test/test_entryconn.c index 9d8a072c77..bec70090e6 100644 --- a/src/test/test_entryconn.c +++ b/src/test/test_entryconn.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,18 +6,23 @@ #define CONNECTION_PRIVATE #define CONNECTION_EDGE_PRIVATE -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" -#include "addressmap.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "connection_edge.h" -#include "nodelist.h" +#include "feature/client/addressmap.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/nodelist/nodelist.h" -#include "hs_cache.h" -#include "rendcache.h" +#include "feature/hs/hs_cache.h" +#include "feature/rend/rendcache.h" + +#include "core/or/entry_connection_st.h" +#include "core/or/socks_request_st.h" + +#include "lib/encoding/confline.h" static void * entryconn_rewrite_setup(const struct testcase_t *tc) @@ -830,4 +835,3 @@ struct testcase_t entryconn_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_entrynodes.c b/src/test/test_entrynodes.c index cfcb88a66e..cafdeb6863 100644 --- a/src/test/test_entrynodes.c +++ b/src/test/test_entrynodes.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -10,28 +10,41 @@ #define ROUTERLIST_PRIVATE #define DIRECTORY_PRIVATE -#include "or.h" -#include "test.h" - -#include "bridges.h" -#include "circuitlist.h" -#include "circuitbuild.h" -#include "config.h" -#include "confparse.h" -#include "crypto_rand.h" -#include "directory.h" -#include "entrynodes.h" -#include "nodelist.h" -#include "networkstatus.h" -#include "policies.h" -#include "routerlist.h" -#include "routerparse.h" -#include "routerset.h" -#include "statefile.h" -#include "util.h" - -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "test/test.h" + +#include "feature/client/bridges.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitbuild.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircache/directory.h" +#include "feature/client/entrynodes.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/networkstatus.h" +#include "core/or/policies.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/routerset.h" +#include "app/config/statefile.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" + +#include "lib/container/bloomfilt.h" +#include "lib/encoding/confline.h" /* TODO: * choose_random_entry() test with state set. @@ -3064,4 +3077,3 @@ struct testcase_t entrynodes_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_extorport.c b/src/test/test_extorport.c index e05342cb8a..ff987563c6 100644 --- a/src/test/test_extorport.c +++ b/src/test/test_extorport.c @@ -1,19 +1,26 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONNECTION_PRIVATE #define EXT_ORPORT_PRIVATE #define MAIN_PRIVATE -#include "or.h" -#include "buffers.h" -#include "connection.h" -#include "connection_or.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "ext_orport.h" -#include "main.h" -#include "test.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/relay/ext_orport.h" +#include "core/mainloop/main.h" + +#include "core/or/or_connection_st.h" + +#include "test/test.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif /* Test connection_or_remove_from_ext_or_id_map and * connection_or_set_ext_or_identifier */ @@ -607,4 +614,3 @@ struct testcase_t extorport_tests[] = { { "handshake", test_ext_or_handshake, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_geoip.c b/src/test/test_geoip.c index 6f849f436b..9df8ea7988 100644 --- a/src/test/test_geoip.c +++ b/src/test/test_geoip.c @@ -8,10 +8,10 @@ /* These macros pull in declarations for some functions and structures that * are typically file-private. */ #define GEOIP_PRIVATE -#include "or.h" -#include "config.h" -#include "geoip.h" -#include "test.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/stats/geoip.h" +#include "test/test.h" /* Record odd numbered fake-IPs using ipv6, even numbered fake-IPs * using ipv4. Since our fake geoip database is the same between @@ -575,4 +575,3 @@ struct testcase_t geoip_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_guardfraction.c b/src/test/test_guardfraction.c index 51ca8f08ec..f45a723295 100644 --- a/src/test/test_guardfraction.c +++ b/src/test/test_guardfraction.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define DIRSERV_PRIVATE @@ -6,18 +6,20 @@ #define NETWORKSTATUS_PRIVATE #include "orconfig.h" -#include "or.h" -#include "config.h" -#include "dirserv.h" -#include "container.h" -#include "entrynodes.h" -#include "util.h" -#include "routerparse.h" -#include "networkstatus.h" - -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/dircache/dirserv.h" +#include "feature/client/entrynodes.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/networkstatus.h" + +#include "feature/nodelist/networkstatus_st.h" +#include "feature/dirauth/vote_microdesc_hash_st.h" +#include "feature/nodelist/vote_routerstatus_st.h" + +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" /** Generate a vote_routerstatus_t for a router with identity digest * <b>digest_in_hex</b>. */ diff --git a/src/test/test_handles.c b/src/test/test_handles.c index eb1e1f1bbe..2910d7e18f 100644 --- a/src/test/test_handles.c +++ b/src/test/test_handles.c @@ -1,11 +1,13 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "test.h" +#include "test/test.h" -#include "util.h" -#include "handles.h" +#include "lib/container/handles.h" +#include "lib/log/util_bug.h" + +#include <stdio.h> typedef struct demo_t { HANDLE_ENTRY(demo, demo_t); @@ -94,4 +96,3 @@ struct testcase_t handle_tests[] = { HANDLE_TEST(basic, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_helpers.c b/src/test/test_helpers.c index 1db5e9064f..c666bca59a 100644 --- a/src/test/test_helpers.c +++ b/src/test/test_helpers.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,21 +12,28 @@ #define MAIN_PRIVATE #include "orconfig.h" -#include "or.h" - -#include "buffers.h" -#include "config.h" -#include "confparse.h" -#include "connection.h" -#include "crypto_rand.h" -#include "main.h" -#include "nodelist.h" -#include "relay.h" -#include "routerlist.h" - -#include "test.h" -#include "test_helpers.h" -#include "test_connection.h" +#include "core/or/or.h" + +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "core/mainloop/connection.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/relay.h" +#include "feature/nodelist/routerlist.h" +#include "lib/encoding/confline.h" + +#include "core/or/cell_st.h" +#include "core/or/connection_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" +#include "feature/nodelist/routerlist_st.h" + +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/test_connection.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS DISABLE_GCC_WARNING(overlength-strings) @@ -34,7 +41,7 @@ DISABLE_GCC_WARNING(overlength-strings) * at large. */ #endif #include "test_descriptors.inc" -#include "circuitlist.h" +#include "core/or/circuitlist.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS ENABLE_GCC_WARNING(overlength-strings) #endif @@ -276,4 +283,3 @@ helper_parse_options(const char *conf) } return opt; } - diff --git a/src/test/test_helpers.h b/src/test/test_helpers.h index 9bc8553257..3196c93e6b 100644 --- a/src/test/test_helpers.h +++ b/src/test/test_helpers.h @@ -1,10 +1,10 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #ifndef TOR_TEST_HELPERS_H #define TOR_TEST_HELPERS_H -#include "or.h" +#include "core/or/or.h" const char *get_yesterday_date_str(void); diff --git a/src/test/test_hs.c b/src/test/test_hs.c index 07daebc164..135df8e9f3 100644 --- a/src/test/test_hs.c +++ b/src/test/test_hs.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -12,16 +12,27 @@ #define RENDSERVICE_PRIVATE #define HS_SERVICE_PRIVATE -#include "or.h" -#include "test.h" -#include "control.h" -#include "config.h" -#include "hs_common.h" -#include "rendcommon.h" -#include "rendservice.h" -#include "routerset.h" -#include "circuitbuild.h" -#include "test_helpers.h" +#include "core/or/or.h" +#include "test/test.h" +#include "feature/control/control.h" +#include "app/config/config.h" +#include "feature/hs/hs_common.h" +#include "feature/rend/rendcommon.h" +#include "feature/rend/rendservice.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "core/or/circuitbuild.h" + +#include "feature/nodelist/node_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/nodelist/routerinfo_st.h" + +#include "test/test_helpers.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif /* mock ID digest and longname for node that's in nodelist */ #define HSDIR_EXIST_ID "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" \ @@ -1055,4 +1066,3 @@ struct testcase_t hs_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_hs_cache.c b/src/test/test_hs_cache.c index 458ce1a92e..c1a69af829 100644 --- a/src/test/test_hs_cache.c +++ b/src/test/test_hs_cache.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,17 +10,21 @@ #define DIRECTORY_PRIVATE #define HS_CACHE_PRIVATE -#include "ed25519_cert.h" -#include "hs_cache.h" -#include "rendcache.h" -#include "directory.h" -#include "networkstatus.h" -#include "connection.h" -#include "proto_http.h" +#include "trunnel/ed25519_cert.h" +#include "feature/hs/hs_cache.h" +#include "feature/rend/rendcache.h" +#include "feature/dircache/directory.h" +#include "feature/nodelist/networkstatus.h" +#include "core/mainloop/connection.h" +#include "core/proto/proto_http.h" +#include "lib/crypt_ops/crypto_format.h" -#include "hs_test_helpers.h" -#include "test_helpers.h" -#include "test.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/nodelist/networkstatus_st.h" + +#include "test/hs_test_helpers.h" +#include "test/test_helpers.h" +#include "test/test.h" /* Static variable used to encoded the HSDir query. */ static char query_b64[256]; @@ -558,4 +562,3 @@ struct testcase_t hs_cache[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_hs_cell.c b/src/test/test_hs_cell.c index 5c5236b391..b47929e8eb 100644 --- a/src/test/test_hs_cell.c +++ b/src/test/test_hs_cell.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,18 +9,18 @@ #define HS_INTROPOINT_PRIVATE #define HS_SERVICE_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" -#include "crypto_ed25519.h" -#include "crypto_rand.h" -#include "hs_cell.h" -#include "hs_intropoint.h" -#include "hs_service.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/hs/hs_cell.h" +#include "feature/hs/hs_intropoint.h" +#include "feature/hs/hs_service.h" /* Trunnel. */ -#include "hs/cell_establish_intro.h" +#include "trunnel/hs/cell_establish_intro.h" /** We simulate the creation of an outgoing ESTABLISH_INTRO cell, and then we * parse it from the receiver side. */ diff --git a/src/test/test_hs_client.c b/src/test/test_hs_client.c index 50dca588ed..57da03ca28 100644 --- a/src/test/test_hs_client.c +++ b/src/test/test_hs_client.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -14,28 +14,40 @@ #define CIRCUITLIST_PRIVATE #define CONNECTION_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "rend_test_helpers.h" -#include "hs_test_helpers.h" - -#include "config.h" -#include "crypto.h" -#include "channeltls.h" -#include "main.h" -#include "nodelist.h" -#include "routerset.h" - -#include "hs_circuit.h" -#include "hs_client.h" -#include "hs_ident.h" -#include "hs_cache.h" -#include "circuitlist.h" -#include "circuitbuild.h" -#include "connection.h" -#include "connection_edge.h" -#include "networkstatus.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/rend_test_helpers.h" +#include "test/hs_test_helpers.h" + +#include "app/config/config.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "core/or/channeltls.h" +#include "feature/dircache/directory.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerset.h" + +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_ident.h" +#include "feature/hs/hs_cache.h" +#include "core/or/circuitlist.h" +#include "core/or/circuitbuild.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_edge.h" +#include "feature/nodelist/networkstatus.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" static int mock_connection_ap_handshake_send_begin(entry_connection_t *ap_conn) @@ -188,17 +200,17 @@ test_e2e_rend_circuit_setup_legacy(void *arg) /* Make a good RENDEZVOUS1 cell body because it needs to pass key exchange * digest verification... */ - uint8_t rend_cell_body[DH_KEY_LEN+DIGEST_LEN] = {2}; + uint8_t rend_cell_body[DH1024_KEY_LEN+DIGEST_LEN] = {2}; { char keys[DIGEST_LEN+CPATH_KEY_MATERIAL_LEN]; crypto_dh_t *dh_state = or_circ->build_state->pending_final_cpath->rend_dh_handshake_state; /* compute and overwrite digest of cell body with the right value */ retval = crypto_dh_compute_secret(LOG_PROTOCOL_WARN, dh_state, - (char*)rend_cell_body, DH_KEY_LEN, + (char*)rend_cell_body, DH1024_KEY_LEN, keys, DIGEST_LEN+CPATH_KEY_MATERIAL_LEN); tt_int_op(retval, OP_GT, 0); - memcpy(rend_cell_body+DH_KEY_LEN, keys, DIGEST_LEN); + memcpy(rend_cell_body+DH1024_KEY_LEN, keys, DIGEST_LEN); } /* Setup the circuit */ @@ -600,4 +612,3 @@ struct testcase_t hs_client_tests[] = { TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_hs_common.c b/src/test/test_hs_common.c index 7348eb746c..f17cc8aeb3 100644 --- a/src/test/test_hs_common.c +++ b/src/test/test_hs_common.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,27 +11,34 @@ #define HS_SERVICE_PRIVATE #define NODELIST_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "hs_test_helpers.h" - -#include "connection_edge.h" -#include "crypto_rand.h" -#include "hs_common.h" -#include "hs_client.h" -#include "hs_service.h" -#include "config.h" -#include "networkstatus.h" -#include "directory.h" -#include "dirauth/dirvote.h" -#include "nodelist.h" -#include "routerlist.h" -#include "statefile.h" -#include "circuitlist.h" -#include "dirauth/shared_random.h" -#include "util.h" -#include "voting_schedule.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/hs_test_helpers.h" + +#include "core/or/connection_edge.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_client.h" +#include "feature/hs/hs_service.h" +#include "app/config/config.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/dircache/directory.h" +#include "feature/dirauth/dirvote.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/routerlist.h" +#include "app/config/statefile.h" +#include "core/or/circuitlist.h" +#include "feature/dirauth/shared_random.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" /** Test the validation of HS v3 addresses */ static void @@ -1826,4 +1833,3 @@ struct testcase_t hs_common_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_hs_config.c b/src/test/test_hs_config.c index a76be301d3..498d2df197 100644 --- a/src/test/test_hs_config.c +++ b/src/test/test_hs_config.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -9,15 +9,15 @@ #define CONFIG_PRIVATE #define HS_SERVICE_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" -#include "config.h" -#include "hs_common.h" -#include "hs_config.h" -#include "hs_service.h" -#include "rendservice.h" +#include "app/config/config.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_config.h" +#include "feature/hs/hs_service.h" +#include "feature/rend/rendservice.h" static int helper_config_service(const char *conf, int validate_only) diff --git a/src/test/test_hs_control.c b/src/test/test_hs_control.c index 308843e9b8..48402030bf 100644 --- a/src/test/test_hs_control.c +++ b/src/test/test_hs_control.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -7,23 +7,20 @@ **/ #define CONTROL_PRIVATE -#define CIRCUITBUILD_PRIVATE -#define RENDCOMMON_PRIVATE -#define RENDSERVICE_PRIVATE -#define HS_SERVICE_PRIVATE - -#include "or.h" -#include "test.h" -#include "control.h" -#include "config.h" -#include "hs_common.h" -#include "hs_control.h" -#include "nodelist.h" -//#include "rendcommon.h" -//#include "rendservice.h" -//#include "routerset.h" -//#include "circuitbuild.h" -#include "test_helpers.h" + +#include "core/or/or.h" +#include "test/test.h" +#include "feature/control/control.h" +#include "app/config/config.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_control.h" +#include "feature/nodelist/nodelist.h" + +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerstatus_st.h" +#include "lib/crypt_ops/crypto_format.h" + +#include "test/test_helpers.h" /* mock ID digest and longname for node that's in nodelist */ #define HSDIR_EXIST_ID \ @@ -195,4 +192,3 @@ struct testcase_t hs_control_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_hs_descriptor.c b/src/test/test_hs_descriptor.c index 14f1a664e7..9a7e66eaea 100644 --- a/src/test/test_hs_descriptor.c +++ b/src/test/test_hs_descriptor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -8,18 +8,19 @@ #define HS_DESCRIPTOR_PRIVATE -#include "crypto_ed25519.h" -#include "crypto_digest.h" -#include "crypto_rand.h" -#include "ed25519_cert.h" -#include "or.h" -#include "hs_descriptor.h" -#include "test.h" -#include "torcert.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "trunnel/ed25519_cert.h" +#include "core/or/or.h" +#include "feature/hs/hs_descriptor.h" +#include "test/test.h" +#include "feature/nodelist/torcert.h" -#include "hs_test_helpers.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "test/hs_test_helpers.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" #ifdef HAVE_CFLAG_WOVERLENGTH_STRINGS DISABLE_GCC_WARNING(overlength-strings) @@ -896,4 +897,3 @@ struct testcase_t hs_descriptor[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_hs_intropoint.c b/src/test/test_hs_intropoint.c index 1671fa9e7a..7da376471b 100644 --- a/src/test/test_hs_intropoint.c +++ b/src/test/test_hs_intropoint.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -11,27 +11,29 @@ #define RENDSERVICE_PRIVATE #define CIRCUITLIST_PRIVATE -#include "test.h" -#include "log_test_helpers.h" -#include "crypto_rand.h" +#include "test/test.h" +#include "test/log_test_helpers.h" +#include "lib/crypt_ops/crypto_rand.h" -#include "or.h" -#include "circuitlist.h" -#include "circuituse.h" +#include "core/or/or.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" #include "ht.h" -#include "relay.h" -#include "rendservice.h" +#include "core/or/relay.h" +#include "feature/rend/rendservice.h" -#include "hs_cell.h" -#include "hs_circuitmap.h" -#include "hs_common.h" -#include "hs_intropoint.h" -#include "hs_service.h" +#include "feature/hs/hs_cell.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_intropoint.h" +#include "feature/hs/hs_service.h" + +#include "core/or/or_circuit_st.h" /* Trunnel. */ -#include "hs/cell_establish_intro.h" -#include "hs/cell_introduce1.h" -#include "hs/cell_common.h" +#include "trunnel/hs/cell_establish_intro.h" +#include "trunnel/hs/cell_introduce1.h" +#include "trunnel/hs/cell_common.h" static size_t new_establish_intro_cell(const char *circ_nonce, diff --git a/src/test/test_hs_ntor.c b/src/test/test_hs_ntor.c index 8eee54d4b4..eeb0491657 100644 --- a/src/test/test_hs_ntor.c +++ b/src/test/test_hs_ntor.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,11 +6,13 @@ * \brief Test hidden service ntor functionality. */ -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" -#include "hs_ntor.h" +#include "core/crypto/hs_ntor.h" /* Test the HS ntor handshake. Simulate the sending of an encrypted INTRODUCE1 * cell, and verify the proper derivation of decryption keys on the other end. @@ -111,4 +113,3 @@ struct testcase_t hs_ntor_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_hs_ntor_cl.c b/src/test/test_hs_ntor_cl.c index ed1eda58ea..03e34968be 100644 --- a/src/test/test_hs_ntor_cl.c +++ b/src/test/test_hs_ntor_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** This is a wrapper over the little-t-tor HS ntor functions. The wrapper is @@ -13,13 +13,13 @@ #include <stdlib.h> #define ONION_NTOR_PRIVATE -#include "or.h" -#include "util.h" -#include "compat.h" -#include "crypto.h" -#include "crypto_curve25519.h" -#include "hs_ntor.h" -#include "onion_ntor.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_format.h" +#include "core/crypto/hs_ntor.h" +#include "core/crypto/onion_ntor.h" #define N_ARGS(n) STMT_BEGIN { \ if (argc < (n)) { \ @@ -252,4 +252,3 @@ main(int argc, char **argv) return 1; } } - diff --git a/src/test/test_hs_service.c b/src/test/test_hs_service.c index 33b5e96070..8074d260a4 100644 --- a/src/test/test_hs_service.c +++ b/src/test/test_hs_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -22,39 +22,48 @@ #define HS_CLIENT_PRIVATE #define ROUTERPARSE_PRIVATE -#include "test.h" -#include "test_helpers.h" -#include "log_test_helpers.h" -#include "rend_test_helpers.h" -#include "hs_test_helpers.h" - -#include "or.h" -#include "config.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "circuituse.h" -#include "crypto_rand.h" -#include "dirauth/dirvote.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "relay.h" -#include "routerparse.h" -#include "hs_common.h" -#include "hs_config.h" -#include "hs_ident.h" -#include "hs_intropoint.h" -#include "hs_ntor.h" -#include "hs_circuit.h" -#include "hs_service.h" -#include "hs_client.h" -#include "main.h" -#include "rendservice.h" -#include "statefile.h" -#include "dirauth/shared_random_state.h" -#include "voting_schedule.h" +#include "test/test.h" +#include "test/test_helpers.h" +#include "test/log_test_helpers.h" +#include "test/rend_test_helpers.h" +#include "test/hs_test_helpers.h" + +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/circuituse.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dirauth/dirvote.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/relay.h" +#include "feature/nodelist/routerparse.h" +#include "feature/hs/hs_common.h" +#include "feature/hs/hs_config.h" +#include "feature/hs/hs_ident.h" +#include "feature/hs/hs_intropoint.h" +#include "core/crypto/hs_ntor.h" +#include "feature/hs/hs_circuit.h" +#include "feature/hs/hs_circuitmap.h" +#include "feature/hs/hs_service.h" +#include "feature/hs/hs_client.h" +#include "core/mainloop/main.h" +#include "feature/rend/rendservice.h" +#include "app/config/statefile.h" +#include "feature/dirauth/shared_random_state.h" +#include "feature/dircommon/voting_schedule.h" + +#include "core/or/cpath_build_state_st.h" +#include "core/or/crypt_path_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/origin_circuit_st.h" +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerinfo_st.h" /* Trunnel */ -#include "hs/cell_establish_intro.h" +#include "trunnel/hs/cell_establish_intro.h" static networkstatus_t mock_ns; @@ -1627,4 +1636,3 @@ struct testcase_t hs_service_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_introduce.c b/src/test/test_introduce.c index d502bdddb1..cdfb70bdff 100644 --- a/src/test/test_introduce.c +++ b/src/test/test_introduce.c @@ -1,13 +1,13 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "crypto.h" -#include "or.h" -#include "test.h" +#include "lib/crypt_ops/crypto.h" +#include "core/or/or.h" +#include "test/test.h" #define RENDSERVICE_PRIVATE -#include "rendservice.h" +#include "feature/rend/rendservice.h" static uint8_t v0_test_plaintext[] = /* 20 bytes of rendezvous point nickname */ diff --git a/src/test/test_keypin.c b/src/test/test_keypin.c index 79d7bac902..9af12ff548 100644 --- a/src/test/test_keypin.c +++ b/src/test/test_keypin.c @@ -1,13 +1,12 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define KEYPIN_PRIVATE -#include "or.h" -#include "keypin.h" -#include "util.h" +#include "core/or/or.h" +#include "feature/dirauth/keypin.h" -#include "test.h" +#include "test/test.h" static void test_keypin_parse_line(void *arg) diff --git a/src/test/test_link_handshake.c b/src/test/test_link_handshake.c index 6840072d76..e0d12fb472 100644 --- a/src/test/test_link_handshake.c +++ b/src/test/test_link_handshake.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,21 +8,26 @@ #define TOR_CHANNEL_INTERNAL_ #define TORTLS_PRIVATE -#include "compat.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "core/or/channeltls.h" +#include "trunnel/link_handshake.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "core/or/scheduler.h" +#include "feature/nodelist/torcert.h" -#include "or.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "channeltls.h" -#include "link_handshake.h" -#include "router.h" -#include "routerkeys.h" -#include "scheduler.h" -#include "torcert.h" +#include "core/or/or_connection_st.h" +#include "core/or/or_handshake_certs_st.h" +#include "core/or/or_handshake_state_st.h" +#include "core/or/var_cell_st.h" -#include "test.h" -#include "log_test_helpers.h" +#include "lib/tls/tortls.h" + +#include "test/test.h" +#include "test/log_test_helpers.h" static var_cell_t *mock_got_var_cell = NULL; @@ -1576,4 +1581,3 @@ struct testcase_t link_handshake_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_logging.c b/src/test/test_logging.c index e373158e34..2e3b8800ac 100644 --- a/src/test/test_logging.c +++ b/src/test/test_logging.c @@ -1,10 +1,19 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ +#define CONFIG_PRIVATE + #include "orconfig.h" -#include "or.h" -#include "torlog.h" -#include "test.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "lib/err/torerr.h" +#include "lib/log/torlog.h" +#include "test/test.h" +#include "lib/process/subprocess.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif static void dummy_cb_fn(int severity, uint32_t domain, const char *msg) @@ -89,7 +98,7 @@ test_sigsafe_err(void *arg) init_logging(1); mark_logs_temp(); - add_file_log(&include_bug, fn, 0); + open_and_add_file_log(&include_bug, fn, 0); tor_log_update_sigsafe_err_fds(); close_temp_logs(); @@ -170,4 +179,3 @@ struct testcase_t logging_tests[] = { { "ratelim", test_ratelim, 0, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_mainloop.c b/src/test/test_mainloop.c index 9da8a039dd..f85c224ae9 100644 --- a/src/test/test_mainloop.c +++ b/src/test/test_mainloop.c @@ -6,11 +6,11 @@ * \brief Tests for functions closely related to the Tor main loop */ -#include "test.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/log_test_helpers.h" -#include "or.h" -#include "main.h" +#include "core/or/or.h" +#include "core/mainloop/main.h" static const uint64_t BILLION = 1000000000; @@ -21,7 +21,7 @@ test_mainloop_update_time_normal(void *arg) monotime_enable_test_mocking(); /* This is arbitrary */ - uint64_t mt_now = U64_LITERAL(7493289274986); + uint64_t mt_now = UINT64_C(7493289274986); /* This time is in the past as of when this test was written. */ time_t now = 1525272090; monotime_coarse_set_mock_time_nsec(mt_now); @@ -63,7 +63,7 @@ test_mainloop_update_time_jumps(void *arg) monotime_enable_test_mocking(); /* This is arbitrary */ - uint64_t mt_now = U64_LITERAL(7493289274986); + uint64_t mt_now = UINT64_C(7493289274986); /* This time is in the past as of when this test was written. */ time_t now = 220897152; monotime_coarse_set_mock_time_nsec(mt_now); diff --git a/src/test/test_microdesc.c b/src/test/test_microdesc.c index 4b168f49ed..ec4779ead1 100644 --- a/src/test/test_microdesc.c +++ b/src/test/test_microdesc.c @@ -1,19 +1,28 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "core/or/or.h" -#include "config.h" +#include "app/config/config.h" #define DIRVOTE_PRIVATE -#include "dirauth/dirvote.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "routerlist.h" -#include "routerparse.h" -#include "torcert.h" - -#include "test.h" +#include "feature/dirauth/dirvote.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/nodelist/torcert.h" + +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "test/test.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif #ifdef _WIN32 /* For mkdir() */ @@ -810,4 +819,3 @@ struct testcase_t microdesc_tests[] = { { "corrupt_desc", test_md_corrupt_desc, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_nodelist.c b/src/test/test_nodelist.c index 9499fd0380..cdd5e95cf0 100644 --- a/src/test/test_nodelist.c +++ b/src/test/test_nodelist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,12 +6,19 @@ * \brief Unit tests for nodelist related functions. **/ -#include "or.h" -#include "crypto_rand.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "torcert.h" -#include "test.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "feature/nodelist/torcert.h" + +#include "feature/nodelist/microdesc_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "test/test.h" /** Test the case when node_get_by_id() returns NULL, * node_get_verbose_nickname_by_id should return the base 16 encoding diff --git a/src/test/test_ntor_cl.c b/src/test/test_ntor_cl.c index d0eea85d6f..744b42c9d9 100644 --- a/src/test/test_ntor_cl.c +++ b/src/test/test_ntor_cl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -6,12 +6,10 @@ #include <stdlib.h> #define ONION_NTOR_PRIVATE -#include "or.h" -#include "util.h" -#include "compat.h" -#include "crypto.h" -#include "crypto_curve25519.h" -#include "onion_ntor.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "core/crypto/onion_ntor.h" #define N_ARGS(n) STMT_BEGIN { \ if (argc < (n)) { \ diff --git a/src/test/test_oom.c b/src/test/test_oom.c index abf8896452..313a6b3114 100644 --- a/src/test/test_oom.c +++ b/src/test/test_oom.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for OOM handling logic */ @@ -7,16 +7,21 @@ #define BUFFERS_PRIVATE #define CIRCUITLIST_PRIVATE #define CONNECTION_PRIVATE -#include "or.h" -#include "buffers.h" -#include "circuitlist.h" -#include "compat_libevent.h" -#include "connection.h" -#include "config.h" -#include "crypto_rand.h" -#include "relay.h" -#include "test.h" -#include "test_helpers.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "core/or/circuitlist.h" +#include "lib/evloop/compat_libevent.h" +#include "core/mainloop/connection.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/or/relay.h" +#include "test/test.h" +#include "test/test_helpers.h" + +#include "core/or/cell_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" /* small replacement mock for circuit_mark_for_close_ to avoid doing all * the other bookkeeping that comes with marking circuits. */ diff --git a/src/test/test_oos.c b/src/test/test_oos.c index e72fcf5de9..5f9942d8ae 100644 --- a/src/test/test_oos.c +++ b/src/test/test_oos.c @@ -1,16 +1,20 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for OOS handler */ #define CONNECTION_PRIVATE -#include "or.h" -#include "config.h" -#include "connection.h" -#include "connection_or.h" -#include "main.h" -#include "test.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/or/connection_or.h" +#include "feature/dircache/directory.h" +#include "core/mainloop/main.h" +#include "test/test.h" + +#include "feature/dircommon/dir_connection_st.h" +#include "core/or/or_connection_st.h" static or_options_t mock_options; @@ -453,4 +457,3 @@ struct testcase_t oos_tests[] = { { "pick_oos_victims", test_oos_pick_oos_victims, TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_options.c b/src/test/test_options.c index 65564f324c..396965401e 100644 --- a/src/test/test_options.c +++ b/src/test/test_options.c @@ -1,24 +1,26 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define CONFIG_PRIVATE -#include "or.h" -#include "confparse.h" -#include "config.h" -#include "test.h" -#include "geoip.h" +#include "core/or/or.h" +#include "app/config/confparse.h" +#include "app/config/config.h" +#include "test/test.h" +#include "feature/stats/geoip.h" #define ROUTERSET_PRIVATE -#include "routerset.h" -#include "main.h" -#include "log_test_helpers.h" +#include "feature/nodelist/routerset.h" +#include "core/mainloop/main.h" +#include "test/log_test_helpers.h" -#include "sandbox.h" -#include "memarea.h" -#include "policies.h" -#include "test_helpers.h" +#include "lib/sandbox/sandbox.h" +#include "lib/memarea/memarea.h" +#include "lib/osinfo/uname.h" +#include "lib/encoding/confline.h" +#include "core/or/policies.h" +#include "test/test_helpers.h" #define NS_MODULE test_options @@ -274,7 +276,7 @@ test_options_validate(void *arg) return; } -#define MEGABYTEIFY(mb) (U64_LITERAL(mb) << 20) +#define MEGABYTEIFY(mb) (UINT64_C(mb) << 20) static void test_have_enough_mem_for_dircache(void *arg) { @@ -4237,4 +4239,3 @@ struct testcase_t options_tests[] = { LOCAL_VALIDATE_TEST(accel), END_OF_TESTCASES /* */ }; - diff --git a/src/test/test_periodic_event.c b/src/test/test_periodic_event.c index 34689b64f4..03ba3df793 100644 --- a/src/test/test_periodic_event.c +++ b/src/test/test_periodic_event.c @@ -11,15 +11,15 @@ #define HS_SERVICE_PRIVATE #define MAIN_PRIVATE -#include "test.h" -#include "test_helpers.h" - -#include "or.h" -#include "config.h" -#include "hibernate.h" -#include "hs_service.h" -#include "main.h" -#include "periodic.h" +#include "test/test.h" +#include "test/test_helpers.h" + +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/hibernate/hibernate.h" +#include "feature/hs/hs_service.h" +#include "core/mainloop/main.h" +#include "core/mainloop/periodic.h" /** Helper function: This is replaced in some tests for the event callbacks so * we don't actually go into the code path of those callbacks. */ diff --git a/src/test/test_policy.c b/src/test/test_policy.c index e89d49aaf5..4b1adc91f0 100644 --- a/src/test/test_policy.c +++ b/src/test/test_policy.c @@ -1,14 +1,21 @@ -/* Copyright (c) 2013-2017, The Tor Project, Inc. */ +/* Copyright (c) 2013-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "core/or/or.h" #define CONFIG_PRIVATE -#include "config.h" -#include "router.h" -#include "routerparse.h" +#include "app/config/config.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerparse.h" #define POLICIES_PRIVATE -#include "policies.h" -#include "test.h" +#include "core/or/policies.h" +#include "lib/encoding/confline.h" +#include "test/test.h" + +#include "core/or/addr_policy_st.h" +#include "feature/nodelist/node_st.h" +#include "core/or/port_cfg_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" /* Helper: assert that short_policy parses and writes back out as itself, or as <b>expected</b> if that's provided. */ @@ -2445,4 +2452,3 @@ struct testcase_t policy_tests[] = { test_policies_fascist_firewall_choose_address, 0, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_procmon.c b/src/test/test_procmon.c index 5c52af8693..2c7918f580 100644 --- a/src/test/test_procmon.c +++ b/src/test/test_procmon.c @@ -1,14 +1,14 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROCMON_PRIVATE #include "orconfig.h" -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" -#include "procmon.h" +#include "lib/evloop/procmon.h" -#include "log_test_helpers.h" +#include "test/log_test_helpers.h" #define NS_MODULE procmon diff --git a/src/test/test_proto_http.c b/src/test/test_proto_http.c index 2f36fbccd7..1cfa0a752c 100644 --- a/src/test/test_proto_http.c +++ b/src/test/test_proto_http.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,11 +6,11 @@ * \brief Tests for our HTTP protocol parser code */ -#include "or.h" -#include "test.h" -#include "buffers.h" -#include "proto_http.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "test/test.h" +#include "lib/container/buffers.h" +#include "core/proto/proto_http.h" +#include "test/log_test_helpers.h" #define S(str) str, sizeof(str)-1 diff --git a/src/test/test_proto_misc.c b/src/test/test_proto_misc.c index 263ca47447..1fcb763421 100644 --- a/src/test/test_proto_misc.c +++ b/src/test/test_proto_misc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -6,14 +6,16 @@ * \brief Test our smaller buffer-based protocol functions */ -#include "or.h" -#include "test.h" -#include "buffers.h" -#include "connection_or.h" -#include "ext_orport.h" -#include "proto_cell.h" -#include "proto_control0.h" -#include "proto_ext_or.h" +#include "core/or/or.h" +#include "test/test.h" +#include "lib/container/buffers.h" +#include "core/or/connection_or.h" +#include "feature/relay/ext_orport.h" +#include "core/proto/proto_cell.h" +#include "core/proto/proto_control0.h" +#include "core/proto/proto_ext_or.h" + +#include "core/or/var_cell_st.h" static void test_proto_var_cell(void *arg) diff --git a/src/test/test_protover.c b/src/test/test_protover.c index 70b7c9a85f..5bbf997fde 100644 --- a/src/test/test_protover.c +++ b/src/test/test_protover.c @@ -1,15 +1,15 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define PROTOVER_PRIVATE #include "orconfig.h" -#include "test.h" +#include "test/test.h" -#include "protover.h" +#include "core/or/protover.h" -#include "or.h" -#include "connection_or.h" +#include "core/or/or.h" +#include "core/or/connection_or.h" static void test_protover_parse(void *arg) diff --git a/src/test/test_pt.c b/src/test/test_pt.c index 07b6712ff9..dea3791da2 100644 --- a/src/test/test_pt.c +++ b/src/test/test_pt.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,15 +8,19 @@ #define UTIL_PRIVATE #define STATEFILE_PRIVATE #define CONTROL_PRIVATE -#include "or.h" -#include "config.h" -#include "confparse.h" -#include "control.h" -#include "transports.h" -#include "circuitbuild.h" -#include "util.h" -#include "statefile.h" -#include "test.h" +#define SUBPROCESS_PRIVATE +#include "core/or/or.h" +#include "app/config/config.h" +#include "app/config/confparse.h" +#include "feature/control/control.h" +#include "feature/client/transports.h" +#include "core/or/circuitbuild.h" +#include "app/config/statefile.h" +#include "test/test.h" +#include "lib/process/subprocess.h" +#include "lib/encoding/confline.h" + +#include "app/config/or_state_st.h" static void reset_mp(managed_proxy_t *mp) @@ -544,4 +548,3 @@ struct testcase_t pt_tests[] = { NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_pubsub.c b/src/test/test_pubsub.c deleted file mode 100644 index 2f047d9f2c..0000000000 --- a/src/test/test_pubsub.c +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ -/* See LICENSE for licensing information */ - -/** - * \file test_pubsub.c - * \brief Unit tests for publish-subscribe abstraction. - **/ - -#include "or.h" -#include "test.h" -#include "pubsub.h" - -DECLARE_PUBSUB_STRUCT_TYPES(foobar) -DECLARE_PUBSUB_TOPIC(foobar) -DECLARE_NOTIFY_PUBSUB_TOPIC(static, foobar) -IMPLEMENT_PUBSUB_TOPIC(static, foobar) - -struct foobar_event_data_t { - unsigned u; - const char *s; -}; - -struct foobar_subscriber_data_t { - const char *name; - long l; -}; - -static int -foobar_sub1(foobar_event_data_t *ev, foobar_subscriber_data_t *mine) -{ - ev->u += 10; - mine->l += 100; - return 0; -} - -static int -foobar_sub2(foobar_event_data_t *ev, foobar_subscriber_data_t *mine) -{ - ev->u += 5; - mine->l += 50; - return 0; -} - -static void -test_pubsub_basic(void *arg) -{ - (void)arg; - foobar_subscriber_data_t subdata1 = { "hi", 0 }; - foobar_subscriber_data_t subdata2 = { "wow", 0 }; - const foobar_subscriber_t *sub1; - const foobar_subscriber_t *sub2; - foobar_event_data_t ed = { 0, "x" }; - foobar_event_data_t ed2 = { 0, "y" }; - sub1 = foobar_subscribe(foobar_sub1, &subdata1, SUBSCRIBE_ATSTART, 100); - tt_assert(sub1); - - foobar_notify(&ed, 0); - tt_int_op(subdata1.l, OP_EQ, 100); - tt_int_op(subdata2.l, OP_EQ, 0); - tt_int_op(ed.u, OP_EQ, 10); - - sub2 = foobar_subscribe(foobar_sub2, &subdata2, 0, 5); - tt_assert(sub2); - - foobar_notify(&ed2, 0); - tt_int_op(subdata1.l, OP_EQ, 200); - tt_int_op(subdata2.l, OP_EQ, 50); - tt_int_op(ed2.u, OP_EQ, 15); - - foobar_unsubscribe(sub1); - - foobar_notify(&ed, 0); - tt_int_op(subdata1.l, OP_EQ, 200); - tt_int_op(subdata2.l, OP_EQ, 100); - tt_int_op(ed.u, OP_EQ, 15); - - done: - foobar_clear(); -} - -struct testcase_t pubsub_tests[] = { - { "pubsub_basic", test_pubsub_basic, TT_FORK, NULL, NULL }, - END_OF_TESTCASES -}; - diff --git a/src/test/test_relay.c b/src/test/test_relay.c index 73c0ed5586..25084fab37 100644 --- a/src/test/test_relay.c +++ b/src/test/test_relay.c @@ -1,17 +1,21 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "core/or/or.h" #define CIRCUITBUILD_PRIVATE -#include "circuitbuild.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" #define RELAY_PRIVATE -#include "relay.h" +#include "core/or/relay.h" /* For init/free stuff */ -#include "scheduler.h" +#include "core/or/scheduler.h" + +#include "core/or/cell_st.h" +#include "core/or/or_circuit_st.h" /* Test suite stuff */ -#include "test.h" -#include "fakechans.h" +#include "test/test.h" +#include "test/fakechans.h" static or_circuit_t * new_fake_orcirc(channel_t *nchan, channel_t *pchan); @@ -127,4 +131,3 @@ struct testcase_t relay_tests[] = { TT_FORK, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_relaycell.c b/src/test/test_relaycell.c index 1bd17b73bf..eb30cab0ec 100644 --- a/src/test/test_relaycell.c +++ b/src/test/test_relaycell.c @@ -1,20 +1,26 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /* Unit tests for handling different kinds of relay cell */ #define RELAY_PRIVATE #define CIRCUITLIST_PRIVATE -#include "or.h" -#include "main.h" -#include "config.h" -#include "connection.h" -#include "crypto.h" -#include "circuitbuild.h" -#include "circuitlist.h" -#include "connection_edge.h" -#include "relay.h" -#include "test.h" +#include "core/or/or.h" +#include "core/mainloop/main.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "lib/crypt_ops/crypto.h" +#include "core/or/circuitbuild.h" +#include "core/or/circuitlist.h" +#include "core/or/connection_edge.h" +#include "core/or/relay.h" +#include "test/test.h" + +#include "core/or/cell_st.h" +#include "core/or/crypt_path_st.h" +#include "core/or/entry_connection_st.h" +#include "core/or/origin_circuit_st.h" +#include "core/or/socks_request_st.h" static int srm_ncalls; static entry_connection_t *srm_conn; diff --git a/src/test/test_relaycrypt.c b/src/test/test_relaycrypt.c index 60bd479719..c3cfb7d10b 100644 --- a/src/test/test_relaycrypt.c +++ b/src/test/test_relaycrypt.c @@ -3,14 +3,19 @@ * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "circuitbuild.h" +#include "core/or/or.h" +#include "core/or/circuitbuild.h" #define CIRCUITLIST_PRIVATE -#include "circuitlist.h" -#include "crypto_rand.h" -#include "relay.h" -#include "relay_crypto.h" -#include "test.h" +#include "core/or/circuitlist.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "core/or/relay.h" +#include "core/crypto/relay_crypto.h" + +#include "core/or/cell_st.h" +#include "core/or/or_circuit_st.h" +#include "core/or/origin_circuit_st.h" + +#include "test/test.h" static const char KEY_MATERIAL[3][CPATH_KEY_MATERIAL_LEN] = { " 'My public key is in this signed x509 object', said Tom assertively.", diff --git a/src/test/test_rendcache.c b/src/test/test_rendcache.c index 9f6cfc4a22..394e28d785 100644 --- a/src/test/test_rendcache.c +++ b/src/test/test_rendcache.c @@ -1,18 +1,25 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "core/or/or.h" -#include "test.h" +#include "test/test.h" #define RENDCACHE_PRIVATE -#include "rendcache.h" -#include "router.h" -#include "routerlist.h" -#include "config.h" -#include "hs_common.h" -#include "rend_test_helpers.h" -#include "log_test_helpers.h" +#include "feature/rend/rendcache.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "app/config/config.h" +#include "feature/hs/hs_common.h" + +#include "core/or/extend_info_st.h" +#include "feature/rend/rend_encoded_v2_service_descriptor_st.h" +#include "feature/rend/rend_intro_point_st.h" +#include "feature/rend/rend_service_descriptor_st.h" +#include "feature/nodelist/routerinfo_st.h" + +#include "test/rend_test_helpers.h" +#include "test/log_test_helpers.h" #define NS_MODULE rend_cache diff --git a/src/test/test_replay.c b/src/test/test_replay.c index d8dcc7370c..bca3a6660a 100644 --- a/src/test/test_replay.c +++ b/src/test/test_replay.c @@ -1,12 +1,12 @@ -/* Copyright (c) 2012-2017, The Tor Project, Inc. */ +/* Copyright (c) 2012-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define REPLAYCACHE_PRIVATE #include "orconfig.h" -#include "or.h" -#include "replaycache.h" -#include "test.h" +#include "core/or/or.h" +#include "feature/hs_common/replaycache.h" +#include "test/test.h" static const char *test_buffer = "Lorem ipsum dolor sit amet, consectetur adipisici elit, sed do eiusmod" diff --git a/src/test/test_router.c b/src/test/test_router.c index 4e96e24534..c6a2452c8c 100644 --- a/src/test/test_router.c +++ b/src/test/test_router.c @@ -1,21 +1,23 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* Copyright (c) 2017, isis agora lovecruft */ /* See LICENSE for licensing information */ /** * \file test_router.c - * \brief Unittests for code in src/or/router.c + * \brief Unittests for code in router.c **/ -#include "or.h" -#include "config.h" -#include "crypto_curve25519.h" -#include "crypto_ed25519.h" -#include "router.h" -#include "routerlist.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" + +#include "feature/nodelist/routerinfo_st.h" /* Test suite stuff */ -#include "test.h" +#include "test/test.h" NS_DECL(const routerinfo_t *, router_get_my_routerinfo, (void)); @@ -109,4 +111,3 @@ struct testcase_t router_tests[] = { ROUTER_TEST(dump_router_to_string_no_bridge_distribution_method, TT_FORK), END_OF_TESTCASES }; - diff --git a/src/test/test_routerkeys.c b/src/test/test_routerkeys.c index e4abcdb92d..1a1bf63ba0 100644 --- a/src/test/test_routerkeys.c +++ b/src/test/test_routerkeys.c @@ -1,24 +1,31 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define ROUTER_PRIVATE -#include "or.h" -#include "config.h" -#include "router.h" -#include "routerkeys.h" -#include "util.h" -#include "crypto.h" -#include "torcert.h" -#include "test.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_format.h" +#include "feature/nodelist/torcert.h" +#include "test/test.h" #ifdef _WIN32 /* For mkdir() */ #include <direct.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif + static void test_routerkeys_write_fingerprint(void *arg) { @@ -695,4 +702,3 @@ struct testcase_t routerkeys_tests[] = { TEST(rsa_ed_crosscert, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_routerlist.c b/src/test/test_routerlist.c index 701227c1c7..89d1f4f90f 100644 --- a/src/test/test_routerlist.c +++ b/src/test/test_routerlist.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -13,29 +13,39 @@ #define NETWORKSTATUS_PRIVATE #define ROUTERLIST_PRIVATE #define TOR_UNIT_TESTING -#include "or.h" -#include "config.h" -#include "connection.h" -#include "container.h" -#include "control.h" -#include "crypto_rand.h" -#include "directory.h" -#include "dirauth/dirvote.h" -#include "entrynodes.h" -#include "hibernate.h" -#include "microdesc.h" -#include "networkstatus.h" -#include "nodelist.h" -#include "policies.h" -#include "router.h" -#include "routerlist.h" -#include "routerset.h" -#include "routerparse.h" -#include "dirauth/shared_random.h" -#include "statefile.h" -#include "test.h" -#include "test_dir_common.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "feature/control/control.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dircache/directory.h" +#include "feature/dirauth/dirvote.h" +#include "feature/client/entrynodes.h" +#include "feature/hibernate/hibernate.h" +#include "feature/nodelist/microdesc.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/nodelist/nodelist.h" +#include "core/or/policies.h" +#include "feature/relay/router.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerset.h" +#include "feature/nodelist/routerparse.h" +#include "feature/dirauth/shared_random.h" +#include "app/config/statefile.h" + +#include "feature/nodelist/authority_cert_st.h" +#include "feature/dircommon/dir_connection_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "feature/nodelist/node_st.h" +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "lib/encoding/confline.h" +#include "lib/container/buffers.h" + +#include "test/test.h" +#include "test/test_dir_common.h" +#include "test/log_test_helpers.h" void construct_consensus(char **consensus_text_md, time_t now); @@ -776,4 +786,3 @@ struct testcase_t routerlist_tests[] = { { "warn_early_consensus", test_warn_early_consensus, 0, NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_routerset.c b/src/test/test_routerset.c index c541324674..2017ef0050 100644 --- a/src/test/test_routerset.c +++ b/src/test/test_routerset.c @@ -1,15 +1,22 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define ROUTERSET_PRIVATE -#include "or.h" -#include "geoip.h" -#include "routerset.h" -#include "routerparse.h" -#include "policies.h" -#include "nodelist.h" -#include "test.h" +#include "core/or/or.h" +#include "feature/stats/geoip.h" +#include "feature/nodelist/routerset.h" +#include "feature/nodelist/routerparse.h" +#include "core/or/policies.h" +#include "feature/nodelist/nodelist.h" + +#include "core/or/addr_policy_st.h" +#include "core/or/extend_info_st.h" +#include "feature/nodelist/node_st.h" +#include "feature/nodelist/routerinfo_st.h" +#include "feature/nodelist/routerstatus_st.h" + +#include "test/test.h" #define NS_MODULE routerset @@ -2221,4 +2228,3 @@ struct testcase_t routerset_tests[] = { TEST_CASE(routerset_free), END_OF_TESTCASES }; - diff --git a/src/test/test_scheduler.c b/src/test/test_scheduler.c index 841fc69456..2d562299ab 100644 --- a/src/test/test_scheduler.c +++ b/src/test/test_scheduler.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,19 +8,19 @@ #define SCHEDULER_KIST_PRIVATE #define TOR_CHANNEL_INTERNAL_ #define CHANNEL_PRIVATE_ -#include "or.h" -#include "config.h" -#include "compat_libevent.h" -#include "channel.h" -#include "channeltls.h" -#include "connection.h" -#include "networkstatus.h" +#include "core/or/or.h" +#include "app/config/config.h" +#include "lib/evloop/compat_libevent.h" +#include "core/or/channel.h" +#include "core/or/channeltls.h" +#include "core/mainloop/connection.h" +#include "feature/nodelist/networkstatus.h" #define SCHEDULER_PRIVATE_ -#include "scheduler.h" +#include "core/or/scheduler.h" /* Test suite stuff */ -#include "test.h" -#include "fakechans.h" +#include "test/test.h" +#include "test/fakechans.h" /* Shamelessly stolen from compat_libevent.c */ #define V(major, minor, patch) \ diff --git a/src/test/test_shared_random.c b/src/test/test_shared_random.c index 2b3c8c93be..ccf051606f 100644 --- a/src/test/test_shared_random.c +++ b/src/test/test_shared_random.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Tor Project, Inc. */ +/* Copyright (c) 2016-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define SHARED_RANDOM_PRIVATE @@ -6,21 +6,29 @@ #define CONFIG_PRIVATE #define DIRVOTE_PRIVATE -#include "or.h" -#include "test.h" -#include "config.h" -#include "crypto_rand.h" -#include "dirauth/dirvote.h" -#include "dirauth/shared_random.h" -#include "dirauth/shared_random_state.h" -#include "log_test_helpers.h" -#include "networkstatus.h" -#include "router.h" -#include "routerkeys.h" -#include "routerlist.h" -#include "routerparse.h" -#include "shared_random_client.h" -#include "voting_schedule.h" +#include "core/or/or.h" +#include "test/test.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/dirauth/dirvote.h" +#include "feature/dirauth/shared_random.h" +#include "feature/dirauth/shared_random_state.h" +#include "test/log_test_helpers.h" +#include "feature/nodelist/networkstatus.h" +#include "feature/relay/router.h" +#include "feature/relay/routerkeys.h" +#include "feature/nodelist/routerlist.h" +#include "feature/nodelist/routerparse.h" +#include "feature/hs_common/shared_random_client.h" +#include "feature/dircommon/voting_schedule.h" + +#include "feature/dirclient/dir_server_st.h" +#include "feature/nodelist/networkstatus_st.h" +#include "app/config/or_state_st.h" + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif static authority_cert_t *mock_cert; @@ -1390,4 +1398,3 @@ struct testcase_t sr_tests[] = { NULL, NULL }, END_OF_TESTCASES }; - diff --git a/src/test/test_slow.c b/src/test/test_slow.c index e640702499..0b665363ab 100644 --- a/src/test/test_slow.c +++ b/src/test/test_slow.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -15,8 +15,8 @@ #include <fcntl.h> #endif -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" struct testgroup_t testgroups[] = { { "slow/crypto/", slow_crypto_tests }, diff --git a/src/test/test_socks.c b/src/test/test_socks.c index 8da7191e82..e064cc8db1 100644 --- a/src/test/test_socks.c +++ b/src/test/test_socks.c @@ -1,14 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "proto_socks.h" -#include "test.h" -#include "log_test_helpers.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "core/mainloop/connection.h" +#include "core/proto/proto_socks.h" +#include "test/test.h" +#include "test/log_test_helpers.h" +#include "core/or/socks_request_st.h" +#include "lib/net/socks5_status.h" typedef struct socks_test_data_t { socks_request_t *req; @@ -1046,4 +1049,3 @@ struct testcase_t socks_tests[] = { END_OF_TESTCASES }; - diff --git a/src/test/test_status.c b/src/test/test_status.c index b4ca17891b..3cc23955ad 100644 --- a/src/test/test_status.c +++ b/src/test/test_status.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Tor Project, Inc. */ +/* Copyright (c) 2014-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define STATUS_PRIVATE @@ -11,20 +11,26 @@ #include <float.h> #include <math.h> -#include "or.h" -#include "torlog.h" +#include "core/or/or.h" +#include "lib/log/torlog.h" #include "tor_queue.h" -#include "status.h" -#include "circuitlist.h" -#include "config.h" -#include "hibernate.h" -#include "rephist.h" -#include "relay.h" -#include "router.h" -#include "main.h" -#include "nodelist.h" -#include "statefile.h" -#include "test.h" +#include "core/or/status.h" +#include "core/or/circuitlist.h" +#include "app/config/config.h" +#include "feature/hibernate/hibernate.h" +#include "feature/stats/rephist.h" +#include "core/or/relay.h" +#include "feature/relay/router.h" +#include "core/mainloop/main.h" +#include "feature/nodelist/nodelist.h" +#include "app/config/statefile.h" +#include "lib/tls/tortls.h" + +#include "core/or/origin_circuit_st.h" +#include "app/config/or_state_st.h" +#include "feature/nodelist/routerinfo_st.h" + +#include "test/test.h" #define NS_MODULE status @@ -226,7 +232,7 @@ NS(test_main)(void *arg) tor_free(actual); expected = "10.00 GB"; - actual = bytes_to_usage((U64_LITERAL(1) << 30) * 10L); + actual = bytes_to_usage((UINT64_C(1) << 30) * 10L); tt_str_op(actual, OP_EQ, expected); tor_free(actual); @@ -1093,4 +1099,3 @@ struct testcase_t status_tests[] = { TEST_CASE_ASPECT(log_heartbeat, tls_write_overhead), END_OF_TESTCASES }; - diff --git a/src/test/test_storagedir.c b/src/test/test_storagedir.c index 26606f9b6e..68cee418ad 100644 --- a/src/test/test_storagedir.c +++ b/src/test/test_storagedir.c @@ -1,10 +1,11 @@ -/* Copyright (c) 2017, The Tor Project, Inc. */ +/* Copyright (c) 2017-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "crypto_rand.h" -#include "storagedir.h" -#include "test.h" +#include "core/or/or.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/fs/storagedir.h" +#include "lib/encoding/confline.h" +#include "test/test.h" #ifdef HAVE_UTIME_H #include <utime.h> @@ -373,4 +374,3 @@ struct testcase_t storagedir_tests[] = { ENT(read_labeled), END_OF_TESTCASES }; - diff --git a/src/test/test_switch_id.c b/src/test/test_switch_id.c index fe36d8c6e6..d8a1d15e4e 100644 --- a/src/test/test_switch_id.c +++ b/src/test/test_switch_id.c @@ -1,11 +1,15 @@ -/* Copyright (c) 2015-2017, The Tor Project, Inc. */ +/* Copyright (c) 2015-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" +#include "core/or/or.h" +#include "lib/process/setuid.h" #ifdef HAVE_SYS_CAPABILITY_H #include <sys/capability.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif #define TEST_BUILT_WITH_CAPS 0 #define TEST_HAVE_CAPS 1 @@ -189,4 +193,3 @@ main(int argc, char **argv) return (okay ? 0 : 1); #endif /* defined(_WIN32) */ } - diff --git a/src/test/test_threads.c b/src/test/test_threads.c index ed6d8f04aa..f0a4dd2057 100644 --- a/src/test/test_threads.c +++ b/src/test/test_threads.c @@ -1,12 +1,12 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" -#include "compat_threads.h" -#include "test.h" +#include "core/or/or.h" +#include "lib/thread/threads.h" +#include "test/test.h" /** mutex for thread test to stop the threads hitting data at the same time. */ static tor_mutex_t *thread_test_mutex_ = NULL; diff --git a/src/test/test_tortls.c b/src/test/test_tortls.c index 388f6df325..2b40ed72d9 100644 --- a/src/test/test_tortls.c +++ b/src/test/test_tortls.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define TORTLS_PRIVATE @@ -11,7 +11,7 @@ #endif #include <math.h> -#include "compat.h" +#include "lib/cc/compat_compiler.h" /* Some versions of OpenSSL declare SSL_get_selected_srtp_profile twice in * srtp.h. Suppress the GCC warning so we can build with -Wredundant-decl. */ @@ -30,13 +30,14 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) -#include "or.h" -#include "torlog.h" -#include "config.h" -#include "tortls.h" +#include "core/or/or.h" +#include "lib/log/torlog.h" +#include "app/config/config.h" +#include "lib/tls/tortls.h" +#include "app/config/or_state_st.h" -#include "test.h" -#include "log_test_helpers.h" +#include "test/test.h" +#include "test/log_test_helpers.h" #define NS_MODULE tortls #ifndef HAVE_SSL_STATE @@ -2839,4 +2840,3 @@ struct testcase_t tortls_tests[] = { LOCAL_TEST_CASE(context_init_one, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_util.c b/src/test/test_util.c index ec11bfd5f5..99fee4c5a5 100644 --- a/src/test/test_util.c +++ b/src/test/test_util.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -8,16 +8,36 @@ #define COMPAT_TIME_PRIVATE #define CONTROL_PRIVATE #define UTIL_PRIVATE -#include "or.h" -#include "buffers.h" -#include "config.h" -#include "control.h" -#include "crypto_rand.h" -#include "test.h" -#include "memarea.h" -#include "util_process.h" -#include "log_test_helpers.h" -#include "compress_zstd.h" +#define UTIL_MALLOC_PRIVATE +#define SOCKET_PRIVATE +#define SUBPROCESS_PRIVATE +#include "lib/testsupport/testsupport.h" +#include "core/or/or.h" +#include "lib/container/buffers.h" +#include "app/config/config.h" +#include "feature/control/control.h" +#include "feature/client/transports.h" +#include "lib/crypt_ops/crypto_format.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "test/test.h" +#include "lib/memarea/memarea.h" +#include "lib/process/waitpid.h" +#include "test/log_test_helpers.h" +#include "lib/compress/compress.h" +#include "lib/compress/compress_zstd.h" +#include "lib/encoding/keyval.h" +#include "lib/fdio/fdio.h" +#include "lib/fs/winlib.h" +#include "lib/process/env.h" +#include "lib/process/pidfile.h" +#include "lib/process/subprocess.h" +#include "lib/intmath/weakrng.h" +#include "lib/thread/numcpus.h" +#include "lib/math/fp.h" +#include "lib/math/laplace.h" +#include "lib/meminfo/meminfo.h" +#include "lib/time/tvdiff.h" +#include "lib/encoding/confline.h" #ifdef HAVE_PWD_H #include <pwd.h> @@ -28,6 +48,16 @@ #ifdef HAVE_UTIME_H #include <utime.h> #endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + #ifdef _WIN32 #include <tchar.h> #endif @@ -1901,8 +1931,8 @@ test_util_strmisc(void *arg) tor_snprintf(buf, 10, "abcdef"); tt_int_op(0,OP_EQ, buf[6]); /* uint64 */ - tor_snprintf(buf, sizeof(buf), "x!"U64_FORMAT"!x", - U64_PRINTF_ARG(U64_LITERAL(12345678901))); + tor_snprintf(buf, sizeof(buf), "x!%"PRIu64"!x", + (UINT64_C(12345678901))); tt_str_op("x!12345678901!x",OP_EQ, buf); /* Test str{,case}cmpstart */ @@ -2115,20 +2145,10 @@ test_util_parse_integer(void *arg) tt_int_op(1,OP_EQ, i); tt_str_op(cp,OP_EQ, " plus garbage"); /* Illogical min max */ - tor_capture_bugs_(1); tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,4,&i,NULL)); tt_int_op(0,OP_EQ, i); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tt_str_op("!(max < min)", OP_EQ, - smartlist_get(tor_get_captured_bug_log_(), 0)); - tor_end_capture_bugs_(); - tor_capture_bugs_(1); tt_int_op(0L,OP_EQ, tor_parse_long("-50",10,100,-100,&i,NULL)); tt_int_op(0,OP_EQ, i); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tt_str_op("!(max < min)", OP_EQ, - smartlist_get(tor_get_captured_bug_log_(), 0)); - tor_end_capture_bugs_(); /* Out of bounds */ tt_int_op(0L,OP_EQ, tor_parse_long("10",10,50,100,&i,NULL)); tt_int_op(0,OP_EQ, i); @@ -2139,11 +2159,8 @@ test_util_parse_integer(void *arg) tt_int_op(0L,OP_EQ, tor_parse_long("2",2,0,100,NULL,NULL)); tt_int_op(68284L,OP_EQ, tor_parse_long("10abc",16,0,70000,NULL,NULL)); tt_int_op(68284L,OP_EQ, tor_parse_long("10ABC",16,0,70000,NULL,NULL)); - tor_capture_bugs_(2); tt_int_op(0L,OP_EQ, tor_parse_long("10",-2,0,100,NULL,NULL)); tt_int_op(0,OP_EQ, tor_parse_long("10ABC",-1,0,70000,&i,NULL)); - tt_int_op(2, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tor_end_capture_bugs_(); tt_int_op(i,OP_EQ, 0); /* Test parse_ulong */ @@ -2156,40 +2173,34 @@ test_util_parse_integer(void *arg) tt_int_op(0UL,OP_EQ, tor_parse_ulong("8",8,0,100,NULL,NULL)); tt_int_op(50UL,OP_EQ, tor_parse_ulong("50",10,50,100,NULL,NULL)); tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,NULL,NULL)); - tor_capture_bugs_(1); tt_int_op(0UL,OP_EQ, tor_parse_ulong("50",-1,50,100,&i,NULL)); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tor_end_capture_bugs_(); tt_int_op(0,OP_EQ, i); tt_int_op(0UL,OP_EQ, tor_parse_ulong("-50",10,0,100,&i,NULL)); tt_int_op(0,OP_EQ, i); /* Test parse_uint64 */ - tt_assert(U64_LITERAL(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); + tt_assert(UINT64_C(10) == tor_parse_uint64("10 x",10,0,100, &i, &cp)); tt_int_op(1,OP_EQ, i); tt_str_op(cp,OP_EQ, " x"); - tt_assert(U64_LITERAL(12345678901) == + tt_assert(UINT64_C(12345678901) == tor_parse_uint64("12345678901",10,0,UINT64_MAX, &i, &cp)); tt_int_op(1,OP_EQ, i); tt_str_op(cp,OP_EQ, ""); - tt_assert(U64_LITERAL(0) == + tt_assert(UINT64_C(0) == tor_parse_uint64("12345678901",10,500,INT32_MAX, &i, &cp)); tt_int_op(0,OP_EQ, i); - tor_capture_bugs_(1); - tt_assert(U64_LITERAL(0) == + tt_assert(UINT64_C(0) == tor_parse_uint64("123",-1,0,INT32_MAX, &i, &cp)); - tt_int_op(1, OP_EQ, smartlist_len(tor_get_captured_bug_log_())); - tor_end_capture_bugs_(); tt_int_op(0,OP_EQ, i); { /* Test parse_double */ double d = tor_parse_double("10", 0, (double)UINT64_MAX,&i,NULL); tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 10); + tt_assert(((uint64_t)d) == 10); d = tor_parse_double("0", 0, (double)UINT64_MAX,&i,NULL); tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 0); + tt_assert(((uint64_t)d) == 0); d = tor_parse_double(" ", 0, (double)UINT64_MAX,&i,NULL); tt_double_op(fabs(d), OP_LT, 1e-10); tt_int_op(0,OP_EQ, i); @@ -2201,7 +2212,7 @@ test_util_parse_integer(void *arg) tt_int_op(1,OP_EQ, i); d = tor_parse_double("-.0", 0, (double)UINT64_MAX,&i,NULL); tt_int_op(1,OP_EQ, i); - tt_assert(DBL_TO_U64(d) == 0); + tt_assert(((uint64_t)d) == 0); d = tor_parse_double("-10", -100.0, 100.0,&i,NULL); tt_int_op(1,OP_EQ, i); tt_double_op(fabs(d - -10.0),OP_LT, 1E-12); @@ -2219,12 +2230,12 @@ test_util_parse_integer(void *arg) tt_int_op(i,OP_EQ, 0); tt_int_op(0UL,OP_EQ, tor_parse_ulong(TOOBIG, 10, 0, ULONG_MAX, &i, NULL)); tt_int_op(i,OP_EQ, 0); - tt_u64_op(U64_LITERAL(0), OP_EQ, tor_parse_uint64(TOOBIG, 10, + tt_u64_op(UINT64_C(0), OP_EQ, tor_parse_uint64(TOOBIG, 10, 0, UINT64_MAX, &i, NULL)); tt_int_op(i,OP_EQ, 0); } done: - tor_end_capture_bugs_(); + ; } static void @@ -2242,17 +2253,17 @@ test_util_pow2(void *arg) tt_int_op(tor_log2(3),OP_EQ, 1); tt_int_op(tor_log2(4),OP_EQ, 2); tt_int_op(tor_log2(5),OP_EQ, 2); - tt_int_op(tor_log2(U64_LITERAL(40000000000000000)),OP_EQ, 55); + tt_int_op(tor_log2(UINT64_C(40000000000000000)),OP_EQ, 55); tt_int_op(tor_log2(UINT64_MAX),OP_EQ, 63); /* Test round_to_power_of_2 */ tt_u64_op(round_to_power_of_2(120), OP_EQ, 128); tt_u64_op(round_to_power_of_2(128), OP_EQ, 128); tt_u64_op(round_to_power_of_2(130), OP_EQ, 128); - tt_u64_op(round_to_power_of_2(U64_LITERAL(40000000000000000)), OP_EQ, - U64_LITERAL(1)<<55); - tt_u64_op(round_to_power_of_2(U64_LITERAL(0xffffffffffffffff)), OP_EQ, - U64_LITERAL(1)<<63); + tt_u64_op(round_to_power_of_2(UINT64_C(40000000000000000)), OP_EQ, + UINT64_C(1)<<55); + tt_u64_op(round_to_power_of_2(UINT64_C(0xffffffffffffffff)), OP_EQ, + UINT64_C(1)<<63); tt_u64_op(round_to_power_of_2(0), OP_EQ, 1); tt_u64_op(round_to_power_of_2(1), OP_EQ, 1); tt_u64_op(round_to_power_of_2(2), OP_EQ, 2); @@ -4102,7 +4113,8 @@ test_util_ftruncate(void *ptr) tt_int_op(fd, OP_GE, 0); /* Make the file be there. */ - tt_int_op(strlen(message), OP_EQ, write_all(fd, message, strlen(message),0)); + tt_int_op(strlen(message), OP_EQ, + write_all_to_fd(fd, message, strlen(message))); tt_int_op((int)tor_fd_getpos(fd), OP_EQ, strlen(message)); tt_int_op(0, OP_EQ, fstat(fd, &st)); tt_int_op((int)st.st_size, OP_EQ, strlen(message)); @@ -4115,7 +4127,7 @@ test_util_ftruncate(void *ptr) /* Replace, and see if it got replaced */ tt_int_op(strlen(message2), OP_EQ, - write_all(fd, message2, strlen(message2), 0)); + write_all_to_fd(fd, message2, strlen(message2))); tt_int_op((int)tor_fd_getpos(fd), OP_EQ, strlen(message2)); tt_int_op(0, OP_EQ, fstat(fd, &st)); tt_int_op((int)st.st_size, OP_EQ, strlen(message2)); @@ -5558,15 +5570,15 @@ test_util_max_mem(void *arg) tt_int_op(r, OP_EQ, r2); tt_uint_op(memory2, OP_EQ, memory1); - TT_BLATHER(("System memory: "U64_FORMAT, U64_PRINTF_ARG(memory1))); + TT_BLATHER(("System memory: %"TOR_PRIuSZ, (memory1))); if (r==0) { /* You have at least a megabyte. */ tt_uint_op(memory1, OP_GT, (1<<20)); } else { /* You do not have a petabyte. */ -#if SIZEOF_SIZE_T == SIZEOF_UINT64_T - tt_u64_op(memory1, OP_LT, (U64_LITERAL(1)<<50)); +#if SIZEOF_SIZE_T >= 8 + tt_u64_op(memory1, OP_LT, (UINT64_C(1)<<50)); #endif } @@ -6316,4 +6328,3 @@ struct testcase_t util_tests[] = { UTIL_TEST(get_unquoted_path, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_util_format.c b/src/test/test_util_format.c index 10645fe117..85d8a8e62e 100644 --- a/src/test/test_util_format.c +++ b/src/test/test_util_format.c @@ -1,14 +1,14 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "or.h" +#include "core/or/or.h" -#include "test.h" +#include "test/test.h" -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #define UTIL_FORMAT_PRIVATE -#include "util_format.h" +#include "lib/encoding/binascii.h" #define NS_MODULE util_format @@ -19,7 +19,7 @@ test_util_format_unaligned_accessors(void *ignored) char buf[9] = "onionsoup"; // 6f6e696f6e736f7570 tt_u64_op(get_uint64(buf+1), OP_EQ, - tor_htonll(U64_LITERAL(0x6e696f6e736f7570))); + tor_htonll(UINT64_C(0x6e696f6e736f7570))); tt_uint_op(get_uint32(buf+1), OP_EQ, htonl(0x6e696f6e)); tt_uint_op(get_uint16(buf+1), OP_EQ, htons(0x6e69)); tt_uint_op(get_uint8(buf+1), OP_EQ, 0x6e); @@ -33,7 +33,7 @@ test_util_format_unaligned_accessors(void *ignored) set_uint32(buf+1, htonl(0x78696465)); tt_mem_op(buf, OP_EQ, "oxidestop", 9); - set_uint64(buf+1, tor_htonll(U64_LITERAL(0x6266757363617465))); + set_uint64(buf+1, tor_htonll(UINT64_C(0x6266757363617465))); tt_mem_op(buf, OP_EQ, "obfuscate", 9); done: ; diff --git a/src/test/test_util_process.c b/src/test/test_util_process.c index 68ce6cfd40..44c4da9169 100644 --- a/src/test/test_util_process.c +++ b/src/test/test_util_process.c @@ -1,15 +1,15 @@ -/* Copyright (c) 2010-2017, The Tor Project, Inc. */ +/* Copyright (c) 2010-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #define UTIL_PROCESS_PRIVATE #include "orconfig.h" -#include "or.h" +#include "core/or/or.h" -#include "test.h" +#include "test/test.h" -#include "util_process.h" +#include "lib/process/waitpid.h" -#include "log_test_helpers.h" +#include "test/log_test_helpers.h" #ifndef _WIN32 #define NS_MODULE util_process diff --git a/src/test/test_util_slow.c b/src/test/test_util_slow.c index 2cd68cf118..5021e89dff 100644 --- a/src/test/test_util_slow.c +++ b/src/test/test_util_slow.c @@ -1,15 +1,21 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" #define UTIL_PRIVATE -#include "util.h" -#include "util_process.h" -#include "crypto.h" -#include "torlog.h" -#include "test.h" +#define SUBPROCESS_PRIVATE +#include "lib/crypt_ops/crypto.h" +#include "lib/log/torlog.h" +#include "lib/process/subprocess.h" +#include "lib/process/waitpid.h" +#include "lib/string/printf.h" +#include "lib/time/compat_time.h" +#include "test/test.h" + +#include <errno.h> +#include <string.h> #ifndef BUILDDIR #define BUILDDIR "." @@ -388,4 +394,3 @@ struct testcase_t slow_util_tests[] = { UTIL_TEST(spawn_background_waitpid_notify, 0), END_OF_TESTCASES }; - diff --git a/src/test/test_voting_schedule.c b/src/test/test_voting_schedule.c index df6058b74f..c3a581cf21 100644 --- a/src/test/test_voting_schedule.c +++ b/src/test/test_voting_schedule.c @@ -3,10 +3,10 @@ #include "orconfig.h" -#include "or.h" -#include "voting_schedule.h" +#include "core/or/or.h" +#include "feature/dircommon/voting_schedule.h" -#include "test.h" +#include "test/test.h" static void test_voting_schedule_interval_start(void *arg) diff --git a/src/test/test_workqueue.c b/src/test/test_workqueue.c index cc7073850c..4550bad1f0 100644 --- a/src/test/test_workqueue.c +++ b/src/test/test_workqueue.c @@ -1,15 +1,17 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "or.h" -#include "compat_threads.h" -#include "onion.h" -#include "workqueue.h" -#include "crypto_curve25519.h" -#include "crypto_rand.h" -#include "compat_libevent.h" +#include "core/or/or.h" +#include "lib/thread/threads.h" +#include "core/crypto/onion.h" +#include "lib/evloop/workqueue.h" +#include "lib/crypt_ops/crypto_curve25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/net/alertsock.h" +#include "lib/evloop/compat_libevent.h" +#include "lib/intmath/weakrng.h" #include <stdio.h> @@ -450,4 +452,3 @@ main(int argc, char **argv) return 0; } } - diff --git a/src/test/test_zero_length_keys.sh b/src/test/test_zero_length_keys.sh index f85edb68db..84ca513b0a 100755 --- a/src/test/test_zero_length_keys.sh +++ b/src/test/test_zero_length_keys.sh @@ -3,8 +3,8 @@ exitcode=0 -"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/or/tor" -z || exitcode=1 -"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/or/tor" -d || exitcode=1 -"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/or/tor" -e || exitcode=1 +"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -z || exitcode=1 +"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -d || exitcode=1 +"${SHELL:-sh}" "${abs_top_srcdir:-.}/src/test/zero_length_keys.sh" "${builddir:-.}/src/app/tor" -e || exitcode=1 exit ${exitcode} diff --git a/src/test/testing_common.c b/src/test/testing_common.c index 4c3fe15960..3880bca9c5 100644 --- a/src/test/testing_common.c +++ b/src/test/testing_common.c @@ -1,6 +1,6 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -10,20 +10,30 @@ #define MAIN_PRIVATE #include "orconfig.h" -#include "or.h" -#include "control.h" -#include "config.h" -#include "crypto_rand.h" -#include "rephist.h" -#include "backtrace.h" -#include "test.h" -#include "channelpadding.h" -#include "main.h" +#include "core/or/or.h" +#include "feature/control/control.h" +#include "app/config/config.h" +#include "lib/crypt_ops/crypto_dh.h" +#include "lib/crypt_ops/crypto_ed25519.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "feature/stats/rephist.h" +#include "lib/err/backtrace.h" +#include "test/test.h" +#include "core/or/channelpadding.h" +#include "core/mainloop/main.h" +#include "lib/compress/compress.h" +#include "lib/evloop/compat_libevent.h" #include <stdio.h> #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif #ifdef _WIN32 /* For mkdir() */ @@ -32,11 +42,6 @@ #include <dirent.h> #endif /* defined(_WIN32) */ -#ifdef USE_DMALLOC -#include <dmalloc.h> -#include "main.h" -#endif - /** Temporary directory (set up by setup_directory) under which we store all * our files during testing. */ static char temp_dir[256]; @@ -231,13 +236,6 @@ main(int c, const char **v) /* We must initialise logs before we call tor_assert() */ init_logging(1); -#ifdef USE_DMALLOC - { - int r = crypto_use_tor_alloc_functions(); - tor_assert(r == 0); - } -#endif /* defined(USE_DMALLOC) */ - update_approx_time(time(NULL)); options = options_new(); tor_threads_init(); @@ -319,10 +317,7 @@ main(int c, const char **v) int have_failed = (tinytest_main(c, v, testgroups) != 0); free_pregenerated_keys(); -#ifdef USE_DMALLOC - tor_free_all(0); - dmalloc_log_unfreed(); -#endif + crypto_global_cleanup(); if (have_failed) @@ -330,4 +325,3 @@ main(int c, const char **v) else return 0; } - diff --git a/src/test/testing_rsakeys.c b/src/test/testing_rsakeys.c index 94d3db328a..a8c9ce4ce8 100644 --- a/src/test/testing_rsakeys.c +++ b/src/test/testing_rsakeys.c @@ -1,12 +1,12 @@ /* Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ -#include "crypto_rand.h" +#include "lib/crypt_ops/crypto_rand.h" #include "orconfig.h" -#include "or.h" -#include "test.h" +#include "core/or/or.h" +#include "test/test.h" /** Define this if unit tests spend too much time generating public keys. * This module is meant to save time by using a bunch of pregenerated RSA diff --git a/src/tools/include.am b/src/tools/include.am index 016cf3b124..8a2ecb23c9 100644 --- a/src/tools/include.am +++ b/src/tools/include.am @@ -6,45 +6,44 @@ endif src_tools_tor_resolve_SOURCES = src/tools/tor-resolve.c src_tools_tor_resolve_LDFLAGS = -src_tools_tor_resolve_LDADD = src/common/libor.a \ - src/common/libor-ctime.a \ +src_tools_tor_resolve_LDADD = \ + $(TOR_UTIL_LIBS) \ $(rust_ldadd) \ - @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_USERENV@ + @TOR_LIB_MATH@ @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_USERENV@ if COVERAGE_ENABLED src_tools_tor_cov_resolve_SOURCES = src/tools/tor-resolve.c src_tools_tor_cov_resolve_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_tools_tor_cov_resolve_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) -src_tools_tor_cov_resolve_LDADD = src/common/libor-testing.a \ - src/common/libor-ctime-testing.a \ +src_tools_tor_cov_resolve_LDADD = \ + $(TOR_UTIL_TESTING_LIBS) \ @TOR_LIB_MATH@ @TOR_LIB_WS32@ endif src_tools_tor_gencert_SOURCES = src/tools/tor-gencert.c src_tools_tor_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_tools_tor_gencert_LDADD = src/common/libor.a src/common/libor-crypto.a \ - src/common/libor-ctime.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ +src_tools_tor_gencert_LDADD = \ + $(TOR_CRYPTO_LIBS) \ + $(TOR_UTIL_LIBS) \ $(rust_ldadd) \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @TOR_LIB_USERENV@ @CURVE25519_LIBS@ if COVERAGE_ENABLED src_tools_tor_cov_gencert_SOURCES = src/tools/tor-gencert.c src_tools_tor_cov_gencert_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_CPPFLAGS) src_tools_tor_cov_gencert_CFLAGS = $(AM_CFLAGS) $(TEST_CFLAGS) src_tools_tor_cov_gencert_LDFLAGS = @TOR_LDFLAGS_zlib@ @TOR_LDFLAGS_openssl@ -src_tools_tor_cov_gencert_LDADD = src/common/libor-testing.a \ - src/common/libor-crypto-testing.a \ - src/common/libor-ctime-testing.a \ - $(LIBKECCAK_TINY) \ - $(LIBDONNA) \ +src_tools_tor_cov_gencert_LDADD = \ + $(TOR_CRYPTO_TESTING_LIBS) \ + $(TOR_UTIL_TESTING_LIBS) \ @TOR_LIB_MATH@ @TOR_ZLIB_LIBS@ @TOR_OPENSSL_LIBS@ \ - @TOR_LIB_WS32@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ + @TOR_LIB_WS32@ @TOR_LIB_IPHLPAPI@ @TOR_LIB_GDI@ @CURVE25519_LIBS@ endif if BUILD_LIBTORRUNNER noinst_LIBRARIES += src/tools/libtorrunner.a -src_tools_libtorrunner_a_SOURCES = src/tools/tor_runner.c src/or/tor_api.c +src_tools_libtorrunner_a_SOURCES = \ + src/tools/tor_runner.c \ + src/feature/api/tor_api.c endif diff --git a/src/tools/tor-gencert.c b/src/tools/tor-gencert.c index aafefdad74..ce032ed643 100644 --- a/src/tools/tor-gencert.c +++ b/src/tools/tor-gencert.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2007-2017, The Tor Project, Inc. */ +/* Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" @@ -13,7 +13,7 @@ #include <unistd.h> #endif -#include "compat.h" +#include "lib/cc/compat_compiler.h" /* Some versions of OpenSSL declare X509_STORE_CTX_set_verify_cb twice in * x509.h and x509_vfy.h. Suppress the GCC warning so we can build with @@ -30,20 +30,20 @@ DISABLE_GCC_WARNING(redundant-decls) ENABLE_GCC_WARNING(redundant-decls) #include <errno.h> -#if 0 -#include <stdlib.h> -#include <stdarg.h> -#include <assert.h> -#endif -#include "util.h" -#include "torlog.h" -#include "crypto.h" -#include "crypto_digest.h" -#include "crypto_rand.h" -#include "crypto_util.h" -#include "address.h" -#include "util_format.h" +#include "lib/crypt_ops/crypto.h" +#include "lib/crypt_ops/crypto_digest.h" +#include "lib/crypt_ops/crypto_rand.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/encoding/binascii.h" +#include "lib/encoding/time_fmt.h" +#include "lib/fs/files.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/address.h" +#include "lib/net/ipv4.h" +#include "lib/string/compat_string.h" +#include "lib/string/printf.h" #define IDENTITY_KEY_BITS 3072 #define SIGNING_KEY_BITS 2048 @@ -78,29 +78,6 @@ show_help(void) "[--passphrase-fd <fd>]\n"); } -/* XXXX copied from crypto.c */ -static void -crypto_log_errors(int severity, const char *doing) -{ - unsigned long err; - const char *msg, *lib, *func; - while ((err = ERR_get_error()) != 0) { - msg = (const char*)ERR_reason_error_string(err); - lib = (const char*)ERR_lib_error_string(err); - func = (const char*)ERR_func_error_string(err); - if (!msg) msg = "(null)"; - if (!lib) lib = "(null)"; - if (!func) func = "(null)"; - if (doing) { - tor_log(severity, LD_CRYPTO, "crypto error while %s: %s (in %s:%s)", - doing, msg, lib, func); - } else { - tor_log(severity, LD_CRYPTO, "crypto error: %s (in %s:%s)", - msg, lib, func); - } - } -} - /** Read the passphrase from the passphrase fd. */ static int load_passphrase(void) @@ -108,7 +85,7 @@ load_passphrase(void) char *cp; char buf[1024]; /* "Ought to be enough for anybody." */ memset(buf, 0, sizeof(buf)); /* should be needless */ - ssize_t n = read_all(passphrase_fd, buf, sizeof(buf), 0); + ssize_t n = read_all_from_fd(passphrase_fd, buf, sizeof(buf)); if (n < 0) { log_err(LD_GENERAL, "Couldn't read from passphrase fd: %s", strerror(errno)); @@ -599,4 +576,3 @@ main(int argc, char **argv) crypto_global_cleanup(); return r; } - diff --git a/src/tools/tor-resolve.c b/src/tools/tor-resolve.c index 966b88b3e8..1532d5f201 100644 --- a/src/tools/tor-resolve.c +++ b/src/tools/tor-resolve.c @@ -1,20 +1,25 @@ /* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson - * Copyright (c) 2007-2017, The Tor Project, Inc. + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ #include "orconfig.h" -#include "compat.h" -#include "util.h" -#include "address.h" -#include "torlog.h" -#include "sandbox.h" + +#include "lib/arch/bytes.h" +#include "lib/log/torlog.h" +#include "lib/malloc/util_malloc.h" +#include "lib/net/address.h" +#include "lib/net/resolve.h" +#include "lib/net/socket.h" +#include "lib/sandbox/sandbox.h" +#include "lib/string/util_string.h" + +#include "lib/net/socks5_status.h" #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> -#include <assert.h> #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> @@ -225,11 +230,11 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, if (version == 5) { char method_buf[2]; - if (write_all(s, "\x05\x01\x00", 3, 1) != 3) { + if (write_all_to_socket(s, "\x05\x01\x00", 3) != 3) { log_err(LD_NET, "Error sending SOCKS5 method list."); goto err; } - if (read_all(s, method_buf, 2, 1) != 2) { + if (read_all_from_socket(s, method_buf, 2) != 2) { log_err(LD_NET, "Error reading SOCKS5 methods."); goto err; } @@ -251,7 +256,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, tor_assert(!req); goto err; } - if (write_all(s, req, len, 1) != len) { + if (write_all_to_socket(s, req, len) != len) { log_sock_error("sending SOCKS request", s); tor_free(req); goto err; @@ -260,7 +265,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, if (version == 4) { char reply_buf[RESPONSE_LEN_4]; - if (read_all(s, reply_buf, RESPONSE_LEN_4, 1) != RESPONSE_LEN_4) { + if (read_all_from_socket(s, reply_buf, RESPONSE_LEN_4) != RESPONSE_LEN_4) { log_err(LD_NET, "Error reading SOCKS4 response."); goto err; } @@ -271,7 +276,7 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, } } else { char reply_buf[16]; - if (read_all(s, reply_buf, 4, 1) != 4) { + if (read_all_from_socket(s, reply_buf, 4) != 4) { log_err(LD_NET, "Error reading SOCKS5 response."); goto err; } @@ -291,14 +296,14 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, } if (reply_buf[3] == 1) { /* IPv4 address */ - if (read_all(s, reply_buf, 4, 1) != 4) { + if (read_all_from_socket(s, reply_buf, 4) != 4) { log_err(LD_NET, "Error reading address in socks5 response."); goto err; } tor_addr_from_ipv4n(result_addr, get_uint32(reply_buf)); } else if (reply_buf[3] == 4) { /* IPv6 address */ - if (read_all(s, reply_buf, 16, 1) != 16) { + if (read_all_from_socket(s, reply_buf, 16) != 16) { log_err(LD_NET, "Error reading address in socks5 response."); goto err; } @@ -306,13 +311,14 @@ do_resolve(const char *hostname, uint32_t sockshost, uint16_t socksport, } else if (reply_buf[3] == 3) { /* Domain name */ size_t result_len; - if (read_all(s, reply_buf, 1, 1) != 1) { + if (read_all_from_socket(s, reply_buf, 1) != 1) { log_err(LD_NET, "Error reading address_length in socks5 response."); goto err; } result_len = *(uint8_t*)(reply_buf); *result_hostname = tor_malloc(result_len+1); - if (read_all(s, *result_hostname, result_len, 1) != (int) result_len) { + if (read_all_from_socket(s, *result_hostname, result_len) + != (int) result_len) { log_err(LD_NET, "Error reading hostname in socks5 response."); goto err; } @@ -451,4 +457,3 @@ main(int argc, char **argv) } return 0; } - diff --git a/src/tools/tor_runner.c b/src/tools/tor_runner.c index 9ed2ee5775..dd90af3df5 100644 --- a/src/tools/tor_runner.c +++ b/src/tools/tor_runner.c @@ -1,7 +1,7 @@ /* Copyright (c) 2001 Matej Pfajfar. * Copyright (c) 2001-2004, Roger Dingledine. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2017, The Tor Project, Inc. */ + * Copyright (c) 2007-2018, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -23,8 +23,8 @@ * functions. Don't add more dependencies! */ -#include "tor_api.h" -#include "tor_api_internal.h" +#include "feature/api/tor_api.h" +#include "feature/api/tor_api_internal.h" #include "orconfig.h" #ifdef HAVE_UNISTD_H diff --git a/src/trace/include.am b/src/trace/include.am deleted file mode 100644 index 3285b04de6..0000000000 --- a/src/trace/include.am +++ /dev/null @@ -1,22 +0,0 @@ -# Include the src/ so we can use the trace/events.h statement when including -# any file in that directory. -AM_CPPFLAGS += -I$(srcdir)/src - -noinst_LIBRARIES += \ - src/trace/libor-trace.a -LIBOR_TRACE_A_SOURCES = \ - src/trace/trace.c - -TRACEHEADERS = \ - src/trace/trace.h \ - src/trace/events.h - -if USE_EVENT_TRACING_DEBUG -TRACEHEADERS += \ - src/trace/debug.h -endif - -# Library source files. -src_trace_libor_trace_a_SOURCES = $(LIBOR_TRACE_A_SOURCES) - -noinst_HEADERS+= $(TRACEHEADERS) diff --git a/src/trunnel/include.am b/src/trunnel/include.am index b249fb302c..5a0a79c3a0 100644 --- a/src/trunnel/include.am +++ b/src/trunnel/include.am @@ -6,8 +6,6 @@ noinst_LIBRARIES += \ src/trunnel/libor-trunnel-testing.a endif -AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel - TRUNNELINPUTS = \ src/trunnel/ed25519_cert.trunnel \ src/trunnel/link_handshake.trunnel \ @@ -39,7 +37,8 @@ TRUNNELHEADERS = \ src/trunnel/channelpadding_negotiation.h src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES) -src_trunnel_libor_trunnel_a_CPPFLAGS = -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS) +src_trunnel_libor_trunnel_a_CPPFLAGS = \ + -DTRUNNEL_LOCAL_H $(AM_CPPFLAGS) -I$(top_srcdir)/src/trunnel if UNITTESTS_ENABLED src_trunnel_libor_trunnel_testing_a_SOURCES = $(TRUNNELSOURCES) @@ -54,4 +53,3 @@ noinst_HEADERS+= $(TRUNNELHEADERS) EXTRA_DIST += \ src/trunnel/README - diff --git a/src/trunnel/trunnel-local.h b/src/trunnel/trunnel-local.h index 8aa6d0ddaa..e81396aeea 100644 --- a/src/trunnel/trunnel-local.h +++ b/src/trunnel/trunnel-local.h @@ -2,9 +2,9 @@ #ifndef TRUNNEL_LOCAL_H_INCLUDED #define TRUNNEL_LOCAL_H_INCLUDED -#include "util.h" -#include "compat.h" -#include "crypto_util.h" +#include "lib/crypt_ops/crypto_util.h" +#include "lib/malloc/util_malloc.h" +#include "lib/log/util_bug.h" #define trunnel_malloc tor_malloc #define trunnel_calloc tor_calloc diff --git a/src/win32/orconfig.h b/src/win32/orconfig.h index 45578f9bb8..65a905debe 100644 --- a/src/win32/orconfig.h +++ b/src/win32/orconfig.h @@ -218,7 +218,7 @@ #define USING_TWOS_COMPLEMENT /* Version number of package */ -#define VERSION "0.3.4.4-rc" +#define VERSION "0.3.5.0-alpha-dev" |