2 * Copyright (c) 2015-2019 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 * http://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 #include "SymptomReporter.h"
19 #include <arpa/inet.h>
23 #include <sys/socket.h>
24 #include <AvailabilityMacros.h>
25 #include <SymptomReporter/SymptomReporter.h>
27 #define SYMPTOM_REPORTER_mDNSResponder_NUMERIC_ID 101
28 #define SYMPTOM_REPORTER_mDNSResponder_TEXT_ID "com.apple.mDNSResponder"
30 #define SYMPTOM_DNS_NO_REPLIES 0x00065001
31 #define SYMPTOM_DNS_RESUMED_RESPONDING 0x00065002
33 mDNSu32 NumUnreachableDNSServers
;
35 static symptom_framework_t symptomReporter
= mDNSNULL
;
36 static symptom_framework_t (*symptom_framework_init_f
)(symptom_ident_t id
, const char *originator_string
) = mDNSNULL
;
37 static symptom_t (*symptom_new_f
)(symptom_framework_t framework
, symptom_ident_t id
) = mDNSNULL
;
38 static int (*symptom_set_additional_qualifier_f
)(symptom_t symptom
, uint32_t qualifier_type
, size_t qualifier_len
, void *qualifier_data
) = mDNSNULL
;
39 static int (*symptom_send_f
)(symptom_t symptom
) = mDNSNULL
;
41 mDNSlocal mStatus
SymptomReporterInitCheck(void)
44 static mDNSBool triedInit
= mDNSfalse
;
45 static void *symptomReporterLib
= mDNSNULL
;
46 static const char path
[] = "/System/Library/PrivateFrameworks/SymptomReporter.framework/SymptomReporter";
52 symptomReporterLib
= dlopen(path
, RTLD_LAZY
| RTLD_LOCAL
);
53 if (!symptomReporterLib
)
56 symptom_framework_init_f
= dlsym(symptomReporterLib
, "symptom_framework_init");
57 if (!symptom_framework_init_f
)
60 symptom_new_f
= dlsym(symptomReporterLib
, "symptom_new");
64 symptom_set_additional_qualifier_f
= dlsym(symptomReporterLib
, "symptom_set_additional_qualifier");
65 if (!symptom_set_additional_qualifier_f
)
68 symptom_send_f
= dlsym(symptomReporterLib
, "symptom_send");
72 symptomReporter
= symptom_framework_init_f(SYMPTOM_REPORTER_mDNSResponder_NUMERIC_ID
, SYMPTOM_REPORTER_mDNSResponder_TEXT_ID
);
76 err
= symptomReporter
? mStatus_NoError
: mStatus_NotInitializedErr
;
80 mDNSlocal mStatus
SymptomReporterReportDNSReachability(const mDNSAddr
*addr
, mDNSBool isReachable
)
84 struct sockaddr_storage sockAddr
;
87 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
88 "SymptomReporterReportDNSReachability: DNS server " PRI_IP_ADDR
" is " PUB_S
"reachable", addr
, isReachable
? "" : "un");
90 if (addr
->type
== mDNSAddrType_IPv4
)
92 struct sockaddr_in
*sin
= (struct sockaddr_in
*)&sockAddr
;
93 sockAddrSize
= sizeof(*sin
);
94 mDNSPlatformMemZero(sin
, sockAddrSize
);
95 sin
->sin_len
= sockAddrSize
;
96 sin
->sin_family
= AF_INET
;
97 sin
->sin_addr
.s_addr
= addr
->ip
.v4
.NotAnInteger
;
99 else if (addr
->type
== mDNSAddrType_IPv6
)
101 struct sockaddr_in6
* sin6
= (struct sockaddr_in6
*)&sockAddr
;
102 sockAddrSize
= sizeof(*sin6
);
103 mDNSPlatformMemZero(sin6
, sockAddrSize
);
104 sin6
->sin6_len
= sockAddrSize
;
105 sin6
->sin6_family
= AF_INET6
;
106 sin6
->sin6_addr
= *(struct in6_addr
*)&addr
->ip
.v6
;
110 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_ERROR
,
111 "SymptomReporterReportDNSReachability: addr is not an IPv4 or IPv6 address!");
112 err
= mStatus_BadParamErr
;
116 symptom
= symptom_new_f(symptomReporter
, isReachable
? SYMPTOM_DNS_RESUMED_RESPONDING
: SYMPTOM_DNS_NO_REPLIES
);
117 symptom_set_additional_qualifier_f(symptom
, 1, sockAddrSize
, (void *)&sockAddr
);
118 symptom_send_f(symptom
);
119 err
= mStatus_NoError
;
125 mDNSexport mStatus
SymptomReporterDNSServerReachable(mDNS
*const m
, const mDNSAddr
*addr
)
129 mDNSBool found
= mDNSfalse
;
131 err
= SymptomReporterInitCheck();
132 if (err
!= mStatus_NoError
)
135 for (s
= m
->DNSServers
; s
; s
= s
->next
)
137 if (s
->flags
& DNSServerFlag_Delete
)
139 if ((s
->flags
& DNSServerFlag_Unreachable
) && mDNSSameAddress(addr
, &s
->addr
))
141 s
->flags
&= ~DNSServerFlag_Unreachable
;
142 NumUnreachableDNSServers
--;
149 err
= mStatus_NoSuchNameErr
;
153 err
= SymptomReporterReportDNSReachability(addr
, mDNStrue
);
159 mDNSexport mStatus
SymptomReporterDNSServerUnreachable(DNSServer
*s
)
163 err
= SymptomReporterInitCheck();
164 if (err
!= mStatus_NoError
)
167 if ((s
->flags
& DNSServerFlag_Delete
) || (s
->flags
& DNSServerFlag_Unreachable
))
170 s
->flags
|= DNSServerFlag_Unreachable
;
171 NumUnreachableDNSServers
++;
173 err
= SymptomReporterReportDNSReachability(&s
->addr
, mDNSfalse
);