1//
2// TORLogging.m
3// Tor
4//
5// Created by Benjamin Erhart on 9/9/17.
6//
7
8#import "TORLogging.h"
9
10#if __has_include(<event2/event.h>)
11
12#import <event2/event.h>
13#import <asl.h>
14// XXXX This is not an exposed or supported Tor API.
15// XXXX If Tor changes this header, then this code might break.
16#import <lib/log/log.h>
17
18tor_log_cb tor_log_callback;
19tor_log_cb event_log_callback;
20
21NS_ASSUME_NONNULL_BEGIN
22
23static char *subsystem = "org.torproject.Tor";
24
25static inline const char *TORLegacyLevelFromOSLogType(os_log_type_t type) {
26 switch (type) {
27 case OS_LOG_TYPE_ERROR: return "3";
28 case OS_LOG_TYPE_INFO: return "4";
29 case OS_LOG_TYPE_DEBUG:
30 default: return "5";
31 }
32}
33
34#pragma clang diagnostic push
35#pragma clang diagnostic ignored "-Wdeprecated-declarations"
36
37static void TORLegacyLog(os_log_type_t type, const char *msg) {
38 static dispatch_once_t onceToken;
39 static aslclient log = NULL;
40 dispatch_once(&onceToken, ^{ log = asl_open(NULL, "com.apple.console", 0); });
41 char read_uid[16];
42 snprintf(read_uid, sizeof(read_uid), "%d", geteuid());
43 aslmsg message = asl_new(ASL_TYPE_MSG);
44 if (message != NULL) {
45 if (asl_set(message, ASL_KEY_LEVEL, TORLegacyLevelFromOSLogType(type)) == 0 &&
46 asl_set(message, ASL_KEY_MSG, msg) == 0 &&
47 asl_set(message, ASL_KEY_READ_UID, read_uid) == 0) {
48 asl_send(log, message);
49 }
50 asl_free(message);
51 }
52}
53
54#pragma clang diagnostic pop
55
56static inline os_log_type_t TORLogTypeFromEventSeverity(int severity) {
57 switch (severity) {
58 case EVENT_LOG_ERR:
59 case EVENT_LOG_WARN: return OS_LOG_TYPE_ERROR;
60 case EVENT_LOG_MSG: return OS_LOG_TYPE_INFO;
61 case EVENT_LOG_DEBUG: return OS_LOG_TYPE_DEBUG;
62 default: return OS_LOG_TYPE_DEFAULT;
63 }
64}
65
66static void TOREventLogCallback(int severity, const char *msg) {
67 os_log_type_t type = TORLogTypeFromEventSeverity(severity);
68 if (event_log_callback) {
69 event_log_callback(type, msg);
70 } else if (@available(iOS 10.0, macOS 10.12, *)) {
71 static dispatch_once_t onceToken;
72 static os_log_t log = NULL;
73 dispatch_once(&onceToken, ^{ log = os_log_create(subsystem, "libevent"); });
74 os_log_with_type(log, type, "%{public}s", msg);
75 } else {
76 TORLegacyLog(type, msg);
77 }
78}
79
80static const char * __nullable TORCategoryForDomain(uint32_t domain) {
81 switch (domain) {
82 case LD_GENERAL: return "general";
83 case LD_CRYPTO: return "crypto";
84 case LD_NET: return "net";
85 case LD_CONFIG: return "config";
86 case LD_FS: return "fs";
87 case LD_PROTOCOL: return "protocol";
88 case LD_MM: return "mm";
89 case LD_HTTP: return "http";
90 case LD_APP: return "app";
91 case LD_CONTROL: return "control";
92 case LD_CIRC: return "circ";
93 case LD_REND: return "rend";
94 case LD_BUG: return "bug";
95 case LD_DIR: return "dir";
96 case LD_DIRSERV: return "dirserv";
97 case LD_OR: return "or";
98 case LD_EDGE: return "edge";
99 case LD_ACCT: return "acct";
100 case LD_HIST: return "hist";
101 case LD_HANDSHAKE: return "handshake";
102 case LD_HEARTBEAT: return "heartbeat";
103 case LD_CHANNEL: return "channel";
104 case LD_SCHED: return "sched";
105 case LD_GUARD: return "guard";
106 default: return NULL;
107 }
108}
109
110static inline os_log_type_t TORLogTypeFromSeverity(int severity) {
111 switch (severity) {
112 case LOG_ERR: return OS_LOG_TYPE_FAULT;
113 case LOG_WARN: return OS_LOG_TYPE_ERROR;
114 case LOG_NOTICE:
115 case LOG_INFO: return OS_LOG_TYPE_INFO;
116 case LOG_DEBUG: return OS_LOG_TYPE_DEBUG;
117 default: return OS_LOG_TYPE_DEFAULT;
118 }
119}
120
121static void TORLogCallback(int severity, uint64_t domain, const char *msg) {
122 if (domain & LD_NOCB) return;
123 os_log_type_t type = TORLogTypeFromSeverity(severity);
124 if (tor_log_callback) {
125 tor_log_callback(type, msg);
126 } else if (@available(iOS 10.0, macOS 10.12, *)) {
127 int index = 0;
128 while (domain >>= 1) ++index;
129 if (index >= N_LOGGING_DOMAINS) return;
130 static os_log_t logs[N_LOGGING_DOMAINS] = { NULL };
131 os_log_t log = logs[index];
132 if (log == NULL) {
133 log = os_log_create(subsystem, TORCategoryForDomain(1u << index));
134 logs[index] = log;
135 }
136 os_log_with_type(log, type, "%{public}s", msg);
137 } else {
138 TORLegacyLog(type, msg);
139 }
140}
141
142void TORInstallEventLogging(void) {
143 event_log_callback = NULL;
144 event_set_log_callback(TOREventLogCallback);
145 event_enable_debug_logging(EVENT_DBG_ALL);
146}
147
148void TORInstallEventLoggingCallback(tor_log_cb cb) {
149 event_log_callback = cb;
150 event_set_log_callback(TOREventLogCallback);
151 event_enable_debug_logging(EVENT_DBG_ALL);
152}
153
154void TORInstallTorLogging(void) {
155 tor_log_callback = NULL;
156 log_severity_list_t list;
157 set_log_severity_config(LOG_DEBUG, LOG_ERR, &list);
158 add_callback_log(&list, TORLogCallback);
159}
160
161extern void TORInstallTorLoggingCallback(tor_log_cb cb) {
162 tor_log_callback = cb;
163 log_severity_list_t list;
164 set_log_severity_config(LOG_DEBUG, LOG_ERR, &list);
165 add_callback_log(&list, TORLogCallback);
166}
167
168NS_ASSUME_NONNULL_END
169
170#else // Stub for builds without tor.xcframework binary
171
172tor_log_cb tor_log_callback;
173tor_log_cb event_log_callback;
174
175void TORInstallEventLogging(void) {}
176void TORInstallEventLoggingCallback(tor_log_cb cb) { event_log_callback = cb; }
177void TORInstallTorLogging(void) {}
178void TORInstallTorLoggingCallback(tor_log_cb cb) { tor_log_callback = cb; }
179
180#endif // __has_include(<event2/event.h>)