blob: 99bba2efe67d668fb33abf78f37dfdcdc6f7fcf8 [file]
/*
* Copyright (c) 2019-2022 Apple Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import <Foundation/Foundation.h>
#import <arpa/inet.h>
#import <os/log_private.h>
#import <AssertMacros.h>
#import <CoreUtils/CoreUtils.h>
#import <mdns/DNSMessage.h>
#import "mdns_strict.h"
#if !COMPILER_ARC
#error "This file must be compiled with ARC."
#endif
// MDNS Mutable Attribute String
#define MDNSAS(str) [[NSAttributedString alloc] initWithString:(str)]
#define MDNSASWithFormat(format, ...) MDNSAS(([[NSString alloc] initWithFormat:format, ##__VA_ARGS__]))
// os_log(OS_LOG_DEFAULT, "IP Address(IPv4/IPv6): %{mdnsresponder:ip_addr}.20P", <the address of mDNSAddr structure>);
typedef struct
{
int32_t type;
union
{
uint8_t v4[4];
uint8_t v6[16];
} ip;
} mDNSAddrCompat;
static NS_RETURNS_RETAINED NSAttributedString *
MDNSOLCopyFormattedStringmDNSIPAddr(id value)
{
NSAttributedString * nsa_str;
NSData *data;
NSString *str;
require_action_quiet([(NSObject *)value isKindOfClass:[NSData class]], exit,
nsa_str = MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]));
data = (NSData *)value;
if (data.bytes == NULL || data.length == 0) {
nsa_str = MDNSAS(@"<NULL IP ADDRESS>");
goto exit;
}
mDNSAddrCompat addr;
require_quiet(data.length == sizeof(addr), exit);
memcpy(&addr, data.bytes, sizeof(addr));
if (addr.type == 0) {
nsa_str = MDNSAS(@"<UNSPECIFIED IP ADDRESS>");
goto exit;
}
str = NSPrintF("%#a", &addr);
require_action_quiet(str != nil, exit, nsa_str = MDNSAS(@"<Could not create NSString>"));
nsa_str = MDNSAS(str);
require_action_quiet(nsa_str != nil, exit, nsa_str = MDNSAS(@"<Could not create NSAttributedString>"));
exit:
return nsa_str;
}
// os_log(OS_LOG_DEFAULT, "MAC Address: %{mdnsresponder:mac_addr}.6P", <the address of 6-byte MAC address>);
#define MAC_ADDRESS_LEN 6
static NS_RETURNS_RETAINED NSAttributedString *
MDNSOLCopyFormattedStringmDNSMACAddr(id value)
{
NSAttributedString * nsa_str;
NSData *data;
NSString *str;
require_action_quiet([(NSObject *)value isKindOfClass:[NSData class]], exit,
nsa_str = MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]));
data = (NSData *)value;
if (data.bytes == NULL || data.length == 0) {
nsa_str = MDNSAS(@"<NULL MAC ADDRESS>");
goto exit;
}
require_action_quiet(data.length == MAC_ADDRESS_LEN, exit,
nsa_str = MDNSASWithFormat(@"<fail decode - size> %zu != %d", (size_t)data.length, MAC_ADDRESS_LEN));
str = NSPrintF("%.6a", data.bytes);
require_action_quiet(str != nil, exit, nsa_str = MDNSAS(@"<Could not create NSString>"));
nsa_str = MDNSAS(str);
require_action_quiet(nsa_str != nil, exit, nsa_str = MDNSAS(@"<Could not create NSAttributedString>"));
exit:
return nsa_str;
}
// os_log(OS_LOG_DEFAULT, "Domain Name: %{mdnsresponder:domain_name}.*P", <the address of domainname structure>);
static NS_RETURNS_RETAINED NSAttributedString *
MDNSOLCopyFormattedStringmDNSLabelSequenceName(id value)
{
NSAttributedString * nsa_str;
NSData *data;
NSString *str;
require_action_quiet([(NSObject *)value isKindOfClass:[NSData class]], exit,
nsa_str = MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]));
data = (NSData *)value;
if (data.bytes == NULL || data.length == 0) {
nsa_str = MDNSAS(@"<NULL DOMAIN NAME>");
goto exit;
}
const uint8_t * const name = (const uint8_t *)data.bytes;
const uint8_t * const limit = name + data.length;
char cstr[kDNSServiceMaxDomainName];
const OSStatus err = DomainNameToString(name, limit, cstr, NULL);
require_noerr_quiet(err, exit);
str = @(cstr);
require_quiet(str != nil, exit);
nsa_str = MDNSAS(str);
require_action_quiet(nsa_str != nil, exit, nsa_str = MDNSAS(@"<Could not create NSAttributedString>"));
exit:
return nsa_str;
}
// os_log(OS_LOG_DEFAULT, "Domain Name: %{mdnsresponder:domain_label}.*P", <the length of the label>,
// <the address of the domain label>);
static NS_RETURNS_RETAINED NSAttributedString *
MDNSOLCopyFormattedStringmDNSLabel(id value)
{
NSAttributedString * nsa_str;
NSData *data;
size_t label_length;
NSString *str;
require_action_quiet([(NSObject *)value isKindOfClass:[NSData class]], exit,
nsa_str = MDNSASWithFormat(@"<failed to decode - invalid data type: %@>", [(NSObject *)value description]));
data = (NSData *)value;
label_length = ((uint8_t *)data.bytes)[0];
require_action_quiet(data.bytes != NULL && data.length != 0, exit,
nsa_str = MDNSASWithFormat(@"failed to decoded - malformed domain label"));
require_action_quiet((label_length <= kDomainLabelLengthMax) && (data.length == (1 + label_length)), exit,
nsa_str = MDNSASWithFormat(@"failed to decode - invalid domain label length - "
"data length: %lu, label length: %lu", (unsigned long)data.length, label_length));
// Enough space for the domain label and a root label.
uint8_t name[1 + kDomainLabelLengthMax + 1];
memcpy(name, data.bytes, data.length);
name[data.length] = 0;
char cstr[kDNSServiceMaxDomainName];
const OSStatus err = DomainNameToString(name, NULL, cstr, NULL);
require_noerr_quiet(err, exit);
const size_t len = strlen(cstr);
if (len > 0) {
// Remove trailing root dot.
cstr[len - 1] = '\0';
}
str = @(cstr);
require_quiet(str != nil, exit);
nsa_str = MDNSAS(str);
require_action_quiet(nsa_str != nil, exit, nsa_str = MDNSAS(@"<Could not create NSAttributedString>"));
exit:
return nsa_str;
}
// os_log(OS_LOG_DEFAULT, "Hex Sequence: %{mdnsresponder:hex_sequence}.*P",
// <the length of the hex length>, <the address of hex data>);
static NS_RETURNS_RETAINED NSAttributedString *
MDNSOLCopyFormattedStringHexSequence(id value)
{
NSAttributedString * nsa_str;
NSData *data;
require_action_quiet([(NSObject *)value isKindOfClass:[NSData class]], exit,
nsa_str = MDNSASWithFormat(@"<failed to decode - invalid data type: %@>", [(NSObject *)value description]));
data = (NSData *)value;
require_action_quiet(data.bytes != NULL, exit, nsa_str = MDNSASWithFormat(@"<failed to decode - NIL data >"));
nsa_str = NSPrintTypedObject("hex", data, NULL);
exit:
return nsa_str;
}
struct MDNSOLFormatters {
const char *type;
NS_RETURNS_RETAINED NSAttributedString *(*function)(id);
};
NS_RETURNS_RETAINED
NSAttributedString *
OSLogCopyFormattedString(const char *type, id value, __unused os_log_type_info_t info)
{
NSAttributedString *nsa_str = nil;
static const struct MDNSOLFormatters formatters[] = {
{ .type = "ip_addr", .function = MDNSOLCopyFormattedStringmDNSIPAddr },
{ .type = "mac_addr", .function = MDNSOLCopyFormattedStringmDNSMACAddr },
{ .type = "domain_name", .function = MDNSOLCopyFormattedStringmDNSLabelSequenceName },
{ .type = "domain_label", .function = MDNSOLCopyFormattedStringmDNSLabel},
{ .type = "hex_sequence", .function = MDNSOLCopyFormattedStringHexSequence},
};
for (int i = 0; i < (int)(sizeof(formatters) / sizeof(formatters[0])); i++) {
if (strcmp(type, formatters[i].type) == 0) {
nsa_str = formatters[i].function(value);
}
}
return nsa_str;
}