From 78a582ed880166a73be284ae799397e84fac36a3 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Mon, 11 Dec 2017 13:00:48 +0000 Subject: Restructure log initilization function to allow multiple backends without arguments. This patch ensures that we more easily can extend our log backends that does not take any additional argument other than a single keyword. This patch is mostly reindentation of some code which is why it is split out into its own patch. See: https://bugs.torproject.org/24362 --- src/or/config.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/or/config.c b/src/or/config.c index bcfac1dae2..676e7f605b 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -5732,16 +5732,17 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, } goto cleanup; } - if (smartlist_len(elts) == 1 && - !strcasecmp(smartlist_get(elts,0), "syslog")) { + if (smartlist_len(elts) == 1) { + if (!strcasecmp(smartlist_get(elts,0), "syslog")) { #ifdef HAVE_SYSLOG_H - if (!validate_only) { - add_syslog_log(severity, options->SyslogIdentityTag); - } + if (!validate_only) { + add_syslog_log(severity, options->SyslogIdentityTag); + } #else - log_warn(LD_CONFIG, "Syslog is not supported on this system. Sorry."); + log_warn(LD_CONFIG, "Syslog is not supported on this system. Sorry."); #endif /* defined(HAVE_SYSLOG_H) */ - goto cleanup; + goto cleanup; + } } if (smartlist_len(elts) == 2 && -- cgit v1.2.3-54-g00ecf From b0b8f7c30c8296344c77d06a24821f35b667e3dd Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Mon, 11 Dec 2017 13:12:25 +0000 Subject: Add support for Android's logging subsystem. This patch adds support for Android's logging subsystem in Tor. When debugging Android applications it is useful to be able to collect information about the application running on the platform via the various system services that is available on the platform. This patch allows you to add "Log notice android" to your torrc and have Tor send everything above and including the notice severity to Android's ring buffer which can be inspected using the 'adb logcat' program. See: https://bugs.torproject.org/24362 --- changes/bug24362 | 2 ++ configure.ac | 14 ++++++++++ doc/tor.1.txt | 5 ++++ src/common/log.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/common/torlog.h | 6 +++- src/or/config.c | 19 +++++++++++++ src/or/or.h | 1 + 7 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 changes/bug24362 diff --git a/changes/bug24362 b/changes/bug24362 new file mode 100644 index 0000000000..15e393cf3f --- /dev/null +++ b/changes/bug24362 @@ -0,0 +1,2 @@ + o Minor features (logging, android): + - Added support for the Android logging subsystem. Closes ticket 24362. diff --git a/configure.ac b/configure.ac index 82e656d3c5..4316f4e09c 100644 --- a/configure.ac +++ b/configure.ac @@ -204,6 +204,20 @@ if test x$enable_event_tracing_debug = xyes; then AC_DEFINE([TOR_EVENT_TRACING_ENABLED], [1], [Compile the event tracing instrumentation]) fi +dnl Enable Android only features. +AC_ARG_ENABLE(android, + AS_HELP_STRING(--enable-android, [build with Android features enabled])) +AM_CONDITIONAL([USE_ANDROID], [test "x$enable_android" = "xyes"]) + +if test "x$enable_android" = "xyes"; then + AC_DEFINE([USE_ANDROID], [1], [Compile with Android specific features enabled]) + + dnl Check if the Android log library is available. + AC_CHECK_HEADERS([android/log.h]) + AC_SEARCH_LIBS(__android_log_write, [log]) + +fi + dnl check for the correct "ar" when cross-compiling. dnl (AM_PROG_AR was new in automake 1.11.2, which we do not yet require, dnl so kludge up a replacement for the case where it isn't there yet.) diff --git a/doc/tor.1.txt b/doc/tor.1.txt index 1814b8292a..b2218e33cc 100644 --- a/doc/tor.1.txt +++ b/doc/tor.1.txt @@ -727,6 +727,11 @@ GENERAL OPTIONS log entries are marked with "Tor-__tag__". Can not be changed while tor is running. (Default: none) +[[AndroidIdentityTag]] **AndroidIdentityTag** __tag__:: + When logging to Android's logging subsystem, adds a tag to the log identity + such that log entries are marked with "Tor-__tag__". Can not be changed while + tor is running. (Default: none) + [[SafeLogging]] **SafeLogging** **0**|**1**|**relay**:: Tor can scrub potentially sensitive strings from log messages (e.g. addresses) by replacing them with the string [scrubbed]. This way logs can diff --git a/src/common/log.c b/src/common/log.c index 80055fda04..ad3d1affd5 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -35,6 +35,9 @@ #define LOG_PRIVATE #include "torlog.h" #include "container.h" +#ifdef HAVE_ANDROID_LOG_H +#include +#endif // HAVE_ANDROID_LOG_H. /** Given a severity, yields an index into log_severity_list_t.masks to use * for that severity. */ @@ -58,6 +61,8 @@ typedef struct logfile_t { int needs_close; /**< Boolean: true if the stream gets closed on shutdown. */ int is_temporary; /**< Boolean: close after initializing logging subsystem.*/ int is_syslog; /**< Boolean: send messages to syslog. */ + int is_android; /**< Boolean: send messages to Android's log subsystem. */ + char *android_tag; /**< Identity Tag used in Android's log subsystem. */ log_callback callback; /**< If not NULL, send messages to this function. */ log_severity_list_t *severities; /**< Which severity of messages should we * log for each log domain? */ @@ -103,6 +108,33 @@ should_log_function_name(log_domain_mask_t domain, int severity) } } +#ifdef HAVE_ANDROID_LOG_H +/** Helper function to convert Tor's log severity into the matching + * Android log priority. + */ +static int +severity_to_android_log_priority(int severity) +{ + switch (severity) { + case LOG_DEBUG: + return ANDROID_LOG_VERBOSE; + case LOG_INFO: + return ANDROID_LOG_DEBUG; + case LOG_NOTICE: + return ANDROID_LOG_INFO; + case LOG_WARN: + return ANDROID_LOG_WARN; + case LOG_ERR: + return ANDROID_LOG_ERROR; + default: + // LCOV_EXCL_START + raw_assert(0); + return 0; + // LCOV_EXCL_STOP + } +} +#endif // HAVE_ANDROID_LOG_H. + /** A mutex to guard changes to logfiles and logging. */ static tor_mutex_t log_mutex; /** True iff we have initialized log_mutex */ @@ -411,7 +443,7 @@ logfile_wants_message(const logfile_t *lf, int severity, if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { return 0; } - if (! (lf->fd >= 0 || lf->is_syslog || lf->callback)) { + if (! (lf->fd >= 0 || lf->is_syslog || lf->is_android || lf->callback)) { return 0; } if (lf->seems_dead) { @@ -454,6 +486,11 @@ logfile_deliver(logfile_t *lf, const char *buf, size_t msg_len, syslog(severity, "%s", msg_after_prefix); #endif /* defined(MAXLINE) */ #endif /* defined(HAVE_SYSLOG_H) */ + } else if (lf->is_android) { +#ifdef HAVE_ANDROID_LOG_H + int priority = severity_to_android_log_priority(severity); + __android_log_write(priority, lf->android_tag, msg_after_prefix); +#endif // HAVE_ANDROID_LOG_H. } else if (lf->callback) { if (domain & LD_NOCB) { if (!*callbacks_deferred && pending_cb_messages) { @@ -646,7 +683,7 @@ tor_log_update_sigsafe_err_fds(void) /* Don't try callback to the control port, or syslogs: We can't * do them from a signal handler. Don't try stdout: we always do stderr. */ - if (lf->is_temporary || lf->is_syslog || + if (lf->is_temporary || lf->is_syslog || lf->is_android || lf->callback || lf->seems_dead || lf->fd < 0) continue; if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] & @@ -683,7 +720,7 @@ tor_log_get_logfile_names(smartlist_t *out) LOCK_LOGS(); for (lf = logfiles; lf; lf = lf->next) { - if (lf->is_temporary || lf->is_syslog || lf->callback) + if (lf->is_temporary || lf->is_syslog || lf->is_android || lf->callback) continue; if (lf->filename == NULL) continue; @@ -732,6 +769,7 @@ log_free_(logfile_t *victim) return; tor_free(victim->severities); tor_free(victim->filename); + tor_free(victim->android_tag); tor_free(victim); } @@ -1151,6 +1189,39 @@ add_syslog_log(const log_severity_list_t *severity, } #endif /* defined(HAVE_SYSLOG_H) */ +#ifdef HAVE_ANDROID_LOG_H +/** + * Add a log handler to send messages to the Android platform log facility. + */ +int +add_android_log(const log_severity_list_t *severity, + const char *android_tag) +{ + logfile_t *lf = NULL; + + lf = tor_malloc_zero(sizeof(logfile_t)); + lf->fd = -1; + lf->severities = tor_memdup(severity, sizeof(log_severity_list_t)); + lf->filename = tor_strdup(""); + lf->is_android = 1; + + if (android_tag == NULL) + lf->android_tag = tor_strdup("Tor"); + else { + char buf[256]; + tor_snprintf(buf, sizeof(buf), "Tor-%s", android_tag); + lf->android_tag = tor_strdup(buf); + } + + LOCK_LOGS(); + lf->next = logfiles; + logfiles = lf; + log_global_min_severity_ = get_min_log_level(); + UNLOCK_LOGS(); + return 0; +} +#endif // HAVE_ANDROID_LOG_H. + /** If level is a valid log severity, return the corresponding * numeric value. Otherwise, return -1. */ int @@ -1318,7 +1389,8 @@ parse_log_severity_config(const char **cfg_ptr, if (!strcasecmpstart(cfg, "file") || !strcasecmpstart(cfg, "stderr") || !strcasecmpstart(cfg, "stdout") || - !strcasecmpstart(cfg, "syslog")) { + !strcasecmpstart(cfg, "syslog") || + !strcasecmpstart(cfg, "android")) { goto done; } if (got_an_unqualified_range > 1) diff --git a/src/common/torlog.h b/src/common/torlog.h index 65bf41702a..b7d033adb9 100644 --- a/src/common/torlog.h +++ b/src/common/torlog.h @@ -146,7 +146,11 @@ int add_file_log(const log_severity_list_t *severity, const char *filename, #ifdef HAVE_SYSLOG_H int add_syslog_log(const log_severity_list_t *severity, const char* syslog_identity_tag); -#endif +#endif // HAVE_SYSLOG_H. +#ifdef HAVE_ANDROID_LOG_H +int add_android_log(const log_severity_list_t *severity, + const char *android_identity_tag); +#endif // HAVE_ANDROID_LOG_H. int add_callback_log(const log_severity_list_t *severity, log_callback cb); void logs_set_domain_logging(int enabled); int get_min_log_level(void); diff --git a/src/or/config.c b/src/or/config.c index 676e7f605b..0f662a617d 100644 --- a/src/or/config.c +++ b/src/or/config.c @@ -403,6 +403,7 @@ static config_var_t option_vars_[] = { V(LogTimeGranularity, MSEC_INTERVAL, "1 second"), V(TruncateLogFile, BOOL, "0"), V(SyslogIdentityTag, STRING, NULL), + V(AndroidIdentityTag, STRING, NULL), V(LongLivedPorts, CSV, "21,22,706,1863,5050,5190,5222,5223,6523,6667,6697,8300"), VAR("MapAddress", LINELIST, AddressMap, NULL), @@ -4692,6 +4693,12 @@ options_transition_allowed(const or_options_t *old, return -1; } + if (!opt_streq(old->AndroidIdentityTag, new_val->AndroidIdentityTag)) { + *msg = tor_strdup("While Tor is running, changing " + "AndroidIdentityTag is not allowed."); + return -1; + } + if ((old->HardwareAccel != new_val->HardwareAccel) || !opt_streq(old->AccelName, new_val->AccelName) || !opt_streq(old->AccelDir, new_val->AccelDir)) { @@ -5743,6 +5750,18 @@ options_init_logs(const or_options_t *old_options, or_options_t *options, #endif /* defined(HAVE_SYSLOG_H) */ goto cleanup; } + + if (!strcasecmp(smartlist_get(elts, 0), "android")) { +#ifdef HAVE_ANDROID_LOG_H + if (!validate_only) { + add_android_log(severity, options->AndroidIdentityTag); + } +#else + log_warn(LD_CONFIG, "Android logging is not supported" + " on this system. Sorry."); +#endif // HAVE_ANDROID_LOG_H. + goto cleanup; + } } if (smartlist_len(elts) == 2 && diff --git a/src/or/or.h b/src/or/or.h index b078022326..aff43f195b 100644 --- a/src/or/or.h +++ b/src/or/or.h @@ -3639,6 +3639,7 @@ typedef struct { 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 -- cgit v1.2.3-54-g00ecf From cbc465a3d1496d43c9bf28cfaf20d7409a2070b7 Mon Sep 17 00:00:00 2001 From: Alexander Færøy Date: Tue, 12 Dec 2017 01:17:57 +0000 Subject: Simplify explicit conditional checks into an inlined function. This patch lifts the check for whether a given log file (`logfile_t`) is an "external logfile" (handled by an external logging system such as syslog, android's logging subsystem, or as an external C callback function) into a function on its own. See: https://bugs.torproject.org/24362 --- src/common/log.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/common/log.c b/src/common/log.c index ad3d1affd5..996840a080 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -433,6 +433,16 @@ pending_log_message_free_(pending_log_message_t *msg) tor_free(msg); } +/** Helper function: returns true iff the log file, given in lf, is + * handled externally via the system log API, the Android logging API, or is an + * external callback function. */ +static inline int +logfile_is_external(logfile_t *lf) +{ + raw_assert(lf); + return lf->is_syslog || lf->is_android || lf->callback; +} + /** Return true iff lf would like to receive a message with the * specified severity in the specified domain. */ @@ -443,7 +453,7 @@ logfile_wants_message(const logfile_t *lf, int severity, if (! (lf->severities->masks[SEVERITY_MASK_IDX(severity)] & domain)) { return 0; } - if (! (lf->fd >= 0 || lf->is_syslog || lf->is_android || lf->callback)) { + if (! (lf->fd >= 0 || logfile_is_external(lf))) { return 0; } if (lf->seems_dead) { @@ -683,8 +693,8 @@ tor_log_update_sigsafe_err_fds(void) /* Don't try callback to the control port, or syslogs: We can't * do them from a signal handler. Don't try stdout: we always do stderr. */ - if (lf->is_temporary || lf->is_syslog || lf->is_android || - lf->callback || lf->seems_dead || lf->fd < 0) + if (lf->is_temporary || logfile_is_external(lf) + || lf->seems_dead || lf->fd < 0) continue; if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] & (LD_BUG|LD_GENERAL)) { @@ -720,7 +730,7 @@ tor_log_get_logfile_names(smartlist_t *out) LOCK_LOGS(); for (lf = logfiles; lf; lf = lf->next) { - if (lf->is_temporary || lf->is_syslog || lf->is_android || lf->callback) + if (lf->is_temporary || logfile_is_external(lf)) continue; if (lf->filename == NULL) continue; -- cgit v1.2.3-54-g00ecf