]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mdns_objects/mdns_powerlog.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mdns_objects / mdns_powerlog.c
1 /*
2 * Copyright (c) 2020 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "mdns_powerlog.h"
18 #include "mdns_helpers.h"
19
20 #include "DNSMessage.h"
21
22 #include <CoreUtils/CoreUtils.h>
23 #include <libproc.h>
24 #include <os/log.h>
25 #include <PowerLog/PowerLog.h>
26 #include <SoftLinking/WeakLinking.h>
27 #include <sys/proc_info.h>
28
29 //======================================================================================================================
30 // MARK: - Weak Linking
31
32 WEAK_LINK_FORCE_IMPORT(PLLogRegisteredEvent); // The PowerLog framework isn't present in the BaseSystem
33
34 //======================================================================================================================
35 // MARK: - PowerLog Event Names
36
37 #define MDNS_POWERLOG_EVENT_AWDL_BROWSE_START CFSTR("startAWDLBrowse")
38 #define MDNS_POWERLOG_EVENT_AWDL_BROWSE_STOP CFSTR("stopAWDLBrowse")
39 #define MDNS_POWERLOG_EVENT_AWDL_ADVERTISE_START CFSTR("startAWDLAdvertise")
40 #define MDNS_POWERLOG_EVENT_AWDL_ADVERTISE_STOP CFSTR("stopAWDLAdvertise")
41 #define MDNS_POWERLOG_EVENT_AWDL_RESOLVE_START CFSTR("startAWDLResolve")
42 #define MDNS_POWERLOG_EVENT_AWDL_RESOLVE_STOP CFSTR("stopAWDLResolve")
43
44 //======================================================================================================================
45 // MARK: - PowerLog Event Dictionary Keys
46
47 #define MDNS_POWERLOG_EVENT_KEY_SERVICE_TYPE CFSTR("service") // String: Service name w/protocol, e.g., _ssh._tcp.
48 #define MDNS_POWERLOG_EVENT_KEY_RECORD_TYPE CFSTR("recordType") // String: Record type, e.g., PTR, SRV, A.
49 #define MDNS_POWERLOG_EVENT_KEY_CLIENT_PID CFSTR("clientPID") // Number: Client's PID.
50 #define MDNS_POWERLOG_EVENT_KEY_CLIENT_NAME CFSTR("clientName") // String: Client's process name.
51
52 //======================================================================================================================
53 // MARK: - Helper Prototypes
54
55 static void
56 _mdns_powerlog_bonjour_event(CFStringRef event_name, const uint8_t *record_name, int record_type, pid_t client_pid);
57
58 //======================================================================================================================
59 // MARK: - Debug Logging
60
61 // The purpose of this os_log category is to log debug messages about logging to PowerLog.
62 // It has nothing to do with actually logging to PowerLog.
63 MDNS_LOG_CATEGORY_DEFINE(powerlog, "powerlog");
64
65 //======================================================================================================================
66 // MARK: - External Functions
67
68 void
69 mdns_powerlog_awdl_browse_start(const uint8_t * const record_name, const int record_type, const pid_t client_pid)
70 {
71 _mdns_powerlog_bonjour_event(MDNS_POWERLOG_EVENT_AWDL_BROWSE_START, record_name, record_type, client_pid);
72 }
73
74 //======================================================================================================================
75
76 void
77 mdns_powerlog_awdl_browse_stop(const uint8_t * const record_name, const int record_type, const pid_t client_pid)
78 {
79 _mdns_powerlog_bonjour_event(MDNS_POWERLOG_EVENT_AWDL_BROWSE_STOP, record_name, record_type, client_pid);
80 }
81
82 //======================================================================================================================
83
84 void
85 mdns_powerlog_awdl_advertise_start(const uint8_t * const record_name, const int record_type, const pid_t client_pid)
86 {
87 _mdns_powerlog_bonjour_event(MDNS_POWERLOG_EVENT_AWDL_ADVERTISE_START, record_name, record_type, client_pid);
88 }
89
90 //======================================================================================================================
91
92 void
93 mdns_powerlog_awdl_advertise_stop(const uint8_t * const record_name, const int record_type, const pid_t client_pid)
94 {
95 _mdns_powerlog_bonjour_event(MDNS_POWERLOG_EVENT_AWDL_ADVERTISE_STOP, record_name, record_type, client_pid);
96 }
97
98 //======================================================================================================================
99
100 void
101 mdns_powerlog_awdl_resolve_start(const uint8_t * const record_name, const int record_type, const pid_t client_pid)
102 {
103 _mdns_powerlog_bonjour_event(MDNS_POWERLOG_EVENT_AWDL_RESOLVE_START, record_name, record_type, client_pid);
104 }
105
106 //======================================================================================================================
107
108 void
109 mdns_powerlog_awdl_resolve_stop(const uint8_t * const record_name, const int record_type, const pid_t client_pid)
110 {
111 _mdns_powerlog_bonjour_event(MDNS_POWERLOG_EVENT_AWDL_RESOLVE_STOP, record_name, record_type, client_pid);
112 }
113
114 //======================================================================================================================
115 // MARK: - Helpers
116
117 static CFDictionaryRef
118 _mdns_powerlog_create_event_dictionary(const uint8_t *record_name, int record_type, pid_t client_pid);
119
120 static void
121 _mdns_powerlog_bonjour_event(const CFStringRef event_name, const uint8_t * const record_name, const int record_type,
122 const pid_t client_pid)
123 {
124 require_quiet(PLLogRegisteredEvent, exit);
125
126 const PLClientID plc_id = PLClientIDMDNSResponder;
127 const CFDictionaryRef event_dict = _mdns_powerlog_create_event_dictionary(record_name, record_type, client_pid);
128 os_log_debug(_mdns_powerlog_log(),
129 "Logging to powerlog -- id: %ld, event: %@, dictionary: %@", (long)plc_id, event_name, event_dict);
130 PLLogRegisteredEvent(plc_id, event_name, event_dict, NULL);
131 CFReleaseNullSafe(event_dict);
132
133 exit:
134 return;
135 }
136
137 //======================================================================================================================
138
139 static void
140 _mdns_powerlog_event_dictionary_add_service_type(CFMutableDictionaryRef event_dict, const uint8_t *record_name);
141
142 static void
143 _mdns_powerlog_event_dictionary_add_record_type(CFMutableDictionaryRef event_dict, int record_type);
144
145 static void
146 _mdns_powerlog_event_dictionary_add_client_info(CFMutableDictionaryRef event_dict, pid_t client_pid);
147
148 static CFDictionaryRef
149 _mdns_powerlog_create_event_dictionary(const uint8_t * const record_name, const int record_type,
150 const pid_t client_pid)
151 {
152 CFMutableDictionaryRef event_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
153 &kCFTypeDictionaryValueCallBacks);
154 require_quiet(event_dict, exit);
155
156 _mdns_powerlog_event_dictionary_add_service_type(event_dict, record_name);
157 _mdns_powerlog_event_dictionary_add_record_type(event_dict, record_type);
158 _mdns_powerlog_event_dictionary_add_client_info(event_dict, client_pid);
159
160 exit:
161 return event_dict;
162 }
163
164 //======================================================================================================================
165
166 static char *
167 _mdns_get_service_name_string_from_domain_name(const uint8_t *name,
168 char service_name_str[static kDNSServiceMaxDomainName]);
169
170 static void
171 _mdns_powerlog_event_dictionary_add_service_type(const CFMutableDictionaryRef event_dict,
172 const uint8_t * const record_name)
173 {
174 char service_type[kDNSServiceMaxDomainName];
175 if (_mdns_get_service_name_string_from_domain_name(record_name, service_type)) {
176 CFStringRef service_type_value = CFStringCreateWithCString(NULL, service_type, kCFStringEncodingUTF8);
177 if (service_type_value) {
178 CFDictionaryAddValue(event_dict, MDNS_POWERLOG_EVENT_KEY_SERVICE_TYPE, service_type_value);
179 ForgetCF(&service_type_value);
180 }
181 }
182 }
183
184 #define MDNS_TCP_PROTOCOL_LABEL ((const uint8_t *)"\x4" "_tcp")
185 #define MDNS_UDP_PROTOCOL_LABEL ((const uint8_t *)"\x4" "_udp")
186 #define MDNS_LOCAL_DOMAIN_NAME ((const uint8_t *)"\x5" "local")
187
188 static char *
189 _mdns_get_service_name_string_from_domain_name(const uint8_t * const record_name,
190 char service_name_str[static kDNSServiceMaxDomainName])
191 {
192 size_t len;
193 const uint8_t *l1 = NULL;
194 const uint8_t *l2 = NULL;
195 const uint8_t *l3 = NULL;
196 // Get the three labels leading up to the root label.
197 for (const uint8_t *ptr = record_name; (len = *ptr) != 0; ptr = &ptr[1 + len]) {
198 l1 = l2;
199 l2 = l3;
200 l3 = ptr;
201 }
202 // Make sure the first label begins with '_', the second label is '_tcp' or '_udp', and the third label is 'local'.
203 // See <https://tools.ietf.org/html/rfc6763#section-4.1.2>.
204 char *result = NULL;
205 if (l1 && (l1[1] == '_') &&
206 l2 && (DomainLabelEqual(l2, MDNS_TCP_PROTOCOL_LABEL) || DomainLabelEqual(l2, MDNS_UDP_PROTOCOL_LABEL)) &&
207 l3 && DomainNameEqual(l3, MDNS_LOCAL_DOMAIN_NAME)) {
208 uint8_t service_name[kDomainNameLengthMax];
209 uint8_t *ptr = service_name;
210 const uint8_t * const limit = &service_name[countof(service_name)];
211
212 // Append service name label.
213 len = 1 + l1[0];
214 require_quiet(((size_t)(limit - ptr)) >= len, exit);
215 memcpy(ptr, l1, len);
216 ptr += len;
217
218 // Append protocol label, i.e., '_tcp' or '_udp'.
219 len = 1 + l2[0];
220 require_quiet(((size_t)(limit - ptr)) >= len, exit);
221 memcpy(ptr, l2, len);
222 ptr += len;
223
224 // Append root label.
225 require_quiet((limit - ptr) >= 1, exit);
226 *ptr = 0;
227
228 // Convert to string.
229 const OSStatus err = DomainNameToString(service_name, limit, service_name_str, NULL);
230 if (!err) {
231 // Remove trailing root dot.
232 len = strlen(service_name_str);
233 if (len > 0) {
234 char * const cptr = &service_name_str[len - 1];
235 if (*cptr == '.') {
236 *cptr = '\0';
237 }
238 }
239 result = service_name_str;
240 }
241 }
242
243 exit:
244 return result;
245 }
246
247 //======================================================================================================================
248
249 static void
250 _mdns_powerlog_event_dictionary_add_record_type(const CFMutableDictionaryRef event_dict, const int record_type)
251 {
252 char qtype_str_buf[32];
253 const char *qtype_str = DNSRecordTypeValueToString(record_type);
254 if (!qtype_str) {
255 snprintf(qtype_str_buf, sizeof(qtype_str_buf), "TYPE%d", record_type);
256 qtype_str = qtype_str_buf;
257 }
258 CFStringRef qtype_str_value = CFStringCreateWithCString(NULL, qtype_str, kCFStringEncodingUTF8);
259 if (qtype_str_value) {
260 CFDictionaryAddValue(event_dict, MDNS_POWERLOG_EVENT_KEY_RECORD_TYPE, qtype_str_value);
261 ForgetCF(&qtype_str_value);
262 }
263 }
264
265 //======================================================================================================================
266
267 static char *
268 _mdns_pid_to_name(pid_t pid, char name[STATIC_PARAM MAXCOMLEN]);
269
270 static void
271 _mdns_powerlog_event_dictionary_add_client_info(const CFMutableDictionaryRef event_dict, const pid_t client_pid)
272 {
273 const long long client_pid_ll = client_pid;
274 CFNumberRef client_pid_value = CFNumberCreate(NULL, kCFNumberLongLongType, &client_pid_ll);
275 if (client_pid_value != NULL) {
276 CFDictionaryAddValue(event_dict, MDNS_POWERLOG_EVENT_KEY_CLIENT_PID, client_pid_value);
277 ForgetCF(&client_pid_value);
278 }
279 char client_name[MAXCOMLEN];
280 if (_mdns_pid_to_name(client_pid, client_name)) {
281 CFStringRef client_name_value = CFStringCreateWithCString(NULL, client_name, kCFStringEncodingUTF8);
282 if (client_name_value) {
283 CFDictionaryAddValue(event_dict, MDNS_POWERLOG_EVENT_KEY_CLIENT_NAME, client_name_value);
284 ForgetCF(&client_name_value);
285 }
286 }
287 }
288
289 static char *
290 _mdns_pid_to_name(const pid_t pid, char name[STATIC_PARAM MAXCOMLEN])
291 {
292 if (pid != 0) {
293 struct proc_bsdshortinfo info;
294 const int n = proc_pidinfo(pid, PROC_PIDT_SHORTBSDINFO, 1, &info, PROC_PIDT_SHORTBSDINFO_SIZE);
295 if (n == (int)sizeof(info)) {
296 strlcpy(name, info.pbsi_comm, MAXCOMLEN);
297 return name;
298 }
299 }
300 return NULL;
301 }