2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
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
8 * https://www.apache.org/licenses/LICENSE-2.0
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.
17 #import "DNSMessage.h"
19 #import <CoreUtils/CoreUtils.h>
20 #import <Foundation/Foundation.h>
21 #import <os/log_private.h>
24 #error "This file must be compiled with ARC."
27 //======================================================================================================================
30 // Data Type Specifier Arguments Notes
31 // DNS message %{mdns:dnsmsg}.*P length (int), pointer (void *) -
32 // DNS message header %{mdns:dnshdr}.*P length (int), pointer (void *) -
33 // Error code integer %{mdns:err}d, %{mdns:err}ld, etc. error code (int, OSStatus, etc.) 1
34 // DNS record data %{mdns:rd.<record type>}.*P length (int), pointer (void *) 2,3,4
35 // DNS record type %{mdns:rrtype}d record type (int)
38 // 1. Formatting is handled by NSPrintTypedObject() from the CoreUtils framework, which handles a large variety of
39 // error codes, including errno and kDNSServiceErr_* error codes.
40 // 2. The DNS record data must be fully expanded, i.e., it must not contain any compressed DNS domain names.
41 // 3. The <record type> portion of the specifier is a case-insensitive DNS record type mnemonic, e.g., A, AAAA,
43 // 4. Formatting is handled by DNSRecordDataToString(), which currently only handles a subset of record types.
44 // This subset consists of the record types most commonly encountered by mDNSResponder. This subset may grow
47 // The specifiers for DNSSEC record data, %{mdns:dnskey}, %{mdns:ds}, %{mdns:nsec}, %{mdns:nsec3}, and
48 // %{mdns:rrsig}, have been deprecated in favor of the %{mdns:rd.<record type>} style of record data specifiers.
50 #define LOG_MDNS_SPECIFIER_DNS_MESSAGE "dnsmsg"
51 #define LOG_MDNS_SPECIFIER_DNS_MESSAGE_HEADER "dnshdr"
52 #define LOG_MDNS_SPECIFIER_ERROR "err"
53 #define LOG_MDNS_SPECIFIER_RDATA_PREFIX "rd."
54 #define LOG_MDNS_SPECIFIER_DNS_RECORD_TYPE "rrtype"
56 //======================================================================================================================
57 // MARK: - Data Structures
59 typedef NSAttributedString *
60 (*log_mdns_data_formatter_f)(NSData *data);
63 const char * specifier;
64 log_mdns_data_formatter_f formatter;
65 } log_mdns_data_formatter_item_t;
67 typedef NSAttributedString *
68 (*log_mdns_number_formatter_f)(NSNumber *number);
71 const char * specifier;
72 log_mdns_number_formatter_f formatter;
73 } log_mdns_number_formatter_item_t;
75 //======================================================================================================================
76 // MARK: - Local Prototypes
78 static NSAttributedString *
79 _log_mdns_format_dns_message(NSData *data);
81 static NSAttributedString *
82 _log_mdns_format_dns_message_header(NSData *data);
84 static NSAttributedString *
85 _log_mdns_format_record_data(NSData *data, int record_type);
87 static NSAttributedString *
88 _log_mdns_format_err(NSNumber *number);
90 static NSAttributedString *
91 _log_mdns_format_dns_record_type(NSNumber *number);
93 static NSAttributedString *
94 _log_mdns_format_dns_message_ex(NSData *data, DNSMessageToStringFlags extra_flags);
96 //======================================================================================================================
97 // MARK: - DNS Record Data Formatters
99 #define LOG_MDNS_DEFINE_RDATA_FORMATTER(RECORD_TYPE) \
100 static NSAttributedString * \
101 _log_mdns_format_record_data_ ## RECORD_TYPE (NSData * const rdata) \
103 return _log_mdns_format_record_data(rdata, kDNSRecordType_ ## RECORD_TYPE); \
105 extern int _log_mdns_dummy_variable
107 LOG_MDNS_DEFINE_RDATA_FORMATTER(DNSKEY);
108 LOG_MDNS_DEFINE_RDATA_FORMATTER(DS);
109 LOG_MDNS_DEFINE_RDATA_FORMATTER(NSEC);
110 LOG_MDNS_DEFINE_RDATA_FORMATTER(NSEC3);
111 LOG_MDNS_DEFINE_RDATA_FORMATTER(RRSIG);
113 //======================================================================================================================
114 // MARK: - External Functions
116 #define LOG_MDNS_RDATA_FORMATTER_ITEM(RECORD_TYPE) { # RECORD_TYPE, _log_mdns_format_record_data_ ## RECORD_TYPE }
119 OSLogCopyFormattedString(const char * const specifier, const id arg, __unused const os_log_type_info_t info)
121 if ([arg isKindOfClass:[NSData class]]) {
122 NSData * const data = (NSData *)arg;
123 if (stricmp_prefix(specifier, LOG_MDNS_SPECIFIER_RDATA_PREFIX) == 0) {
124 const char * const type_str = specifier + sizeof_string(LOG_MDNS_SPECIFIER_RDATA_PREFIX);
125 const int type_value = DNSRecordTypeStringToValue(type_str);
126 if (type_value != 0) {
127 return _log_mdns_format_record_data(data, type_value);
130 const log_mdns_data_formatter_item_t log_mdns_data_formatter_table[] = {
131 { LOG_MDNS_SPECIFIER_DNS_MESSAGE, _log_mdns_format_dns_message },
132 { LOG_MDNS_SPECIFIER_DNS_MESSAGE_HEADER, _log_mdns_format_dns_message_header },
133 LOG_MDNS_RDATA_FORMATTER_ITEM(DNSKEY),
134 LOG_MDNS_RDATA_FORMATTER_ITEM(DS),
135 LOG_MDNS_RDATA_FORMATTER_ITEM(NSEC),
136 LOG_MDNS_RDATA_FORMATTER_ITEM(NSEC3),
137 LOG_MDNS_RDATA_FORMATTER_ITEM(RRSIG)
139 for (size_t i = 0; i < countof(log_mdns_data_formatter_table); ++i) {
140 const log_mdns_data_formatter_item_t * const item = &log_mdns_data_formatter_table[i];
141 if (strcasecmp(specifier, item->specifier) == 0) {
142 return item->formatter(data);
146 } else if ([arg isKindOfClass:[NSNumber class]]) {
147 const log_mdns_number_formatter_item_t log_mdns_number_formatter_table[] = {
148 { LOG_MDNS_SPECIFIER_ERROR, _log_mdns_format_err },
149 { LOG_MDNS_SPECIFIER_DNS_RECORD_TYPE, _log_mdns_format_dns_record_type }
151 NSNumber * const number = (NSNumber *)arg;
152 for (size_t i = 0; i < countof(log_mdns_number_formatter_table); ++i) {
153 const log_mdns_number_formatter_item_t * const item = &log_mdns_number_formatter_table[i];
154 if (strcasecmp(specifier, item->specifier) == 0) {
155 return item->formatter(number);
162 //======================================================================================================================
163 // MARK: - Internal Functions
165 static NSAttributedString *
166 _log_mdns_format_dns_message(NSData * const data)
168 return _log_mdns_format_dns_message_ex(data, kDNSMessageToStringFlag_Null);
171 //======================================================================================================================
173 static NSAttributedString *
174 _log_mdns_format_dns_message_header(NSData * const data)
176 return _log_mdns_format_dns_message_ex(data, kDNSMessageToStringFlag_HeaderOnly);
179 //======================================================================================================================
181 static NSAttributedString *
182 _log_mdns_format_err(NSNumber * const number)
184 return NSPrintTypedObject("err", number, NULL);
187 //======================================================================================================================
189 static NSAttributedString *
190 _log_mdns_format_dns_record_type(NSNumber * const number)
192 unsigned long long value = [number unsignedLongLongValue];
193 require_return_value(value <= INT_MAX, nil);
196 const char *cstr = DNSRecordTypeValueToString((int)value);
198 nsstr = [[NSString alloc] initWithFormat:@"%s", cstr];
199 require_return_value(nsstr, nil);
201 nsstr = [[NSString alloc] initWithFormat:@"TYPE%u", (unsigned int)value];
202 require_return_value(nsstr, nil);
204 return [[NSAttributedString alloc] initWithString:nsstr];
207 //======================================================================================================================
209 static NSAttributedString *
210 _log_mdns_format_record_data(NSData * const rdata, const int record_type)
213 DNSRecordDataToString(rdata.bytes, rdata.length, record_type, &cstr);
217 const size_t len = strlen(cstr);
218 NSString * const nsstr = [[NSString alloc] initWithBytesNoCopy:cstr length:len encoding:NSUTF8StringEncoding
224 return [[NSAttributedString alloc] initWithString:nsstr];
227 //======================================================================================================================
229 static NSAttributedString *
230 _log_mdns_format_dns_message_ex(NSData * const data, const DNSMessageToStringFlags extra_flags)
232 char *msg_cstr = NULL;
233 const DNSMessageToStringFlags flags = kDNSMessageToStringFlag_OneLine | extra_flags;
234 DNSMessageToString(data.bytes, data.length, flags, &msg_cstr);
235 require_return_value(msg_cstr, nil);
237 NSString *msg_nsstr = [[NSString alloc] initWithBytesNoCopy:msg_cstr length:strlen(msg_cstr)
238 encoding:NSUTF8StringEncoding freeWhenDone:YES];
239 require_return_value_action(msg_nsstr, nil, ForgetMem(&msg_cstr));
241 return [[NSAttributedString alloc] initWithString:msg_nsstr];