]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/uDNSPathEvaluation.c
mDNSResponder-1310.60.4.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / uDNSPathEvaluation.c
1 /*
2 * Copyright (c) 2013-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 "mDNSMacOSX.h"
18 #include <libproc.h>
19 #include <nw/private.h>
20
21 #include "dns_sd_internal.h"
22
23 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
24 #include "QuerierSupport.h"
25 #endif
26
27 #define _nw_forget(PTR) \
28 do \
29 { \
30 if (*(PTR)) \
31 { \
32 nw_release(*(PTR)); \
33 *(PTR) = NULL; \
34 } \
35 } while (0)
36
37 //Gets the DNSPolicy from NW PATH EVALUATOR
38 mDNSexport void mDNSPlatformGetDNSRoutePolicy(DNSQuestion *q)
39 {
40 nw_endpoint_t host = NULL;
41 nw_parameters_t parameters = NULL;
42 nw_path_evaluator_t evaluator = NULL;
43 nw_path_t path = NULL;
44 mDNSBool isBlocked = mDNSfalse;
45 q->ServiceID = -1; // initialize the ServiceID to default value of -1
46
47 // Return for non-unicast DNS queries, or invalid PID.
48 if (mDNSOpaque16IsZero(q->TargetQID) || (q->pid < 0))
49 {
50 goto exit;
51 }
52
53 mDNSs32 service_id;
54 mDNSu32 client_ifindex, dnspol_ifindex;
55 int retval;
56 struct proc_uniqidentifierinfo info;
57 mDNSBool isUUIDSet;
58
59 char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
60 ConvertDomainNameToCString(&q->qname, unenc_name);
61
62 host = nw_endpoint_create_host(unenc_name, "0");
63 if (host == NULL)
64 {
65 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
66 "[Q%u] mDNSPlatformGetDNSRoutePolicy: Query for " PRI_DM_NAME " (" PUB_S "), PID[%d], EUID[%d], ServiceID[%d]"
67 " host is NULL",
68 mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
69 goto exit;
70 }
71 parameters = nw_parameters_create();
72 if (parameters == NULL)
73 {
74 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
75 "[Q%u] mDNSPlatformGetDNSRoutePolicy: Query for " PRI_DM_NAME " (" PUB_S "), PID[%d], EUID[%d], ServiceID[%d]"
76 " parameters is NULL",
77 mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
78 goto exit;
79 }
80 #if TARGET_OS_WATCH
81 static xpc_object_t prohibited_interface_subtypes = NULL;
82 // Companion interface on watchOS does not support DNS, so we don't want path evalution to return it to us.
83 if (prohibited_interface_subtypes == NULL)
84 {
85 prohibited_interface_subtypes = xpc_array_create(NULL, 0);
86 if (prohibited_interface_subtypes != NULL)
87 {
88 xpc_array_set_uint64(prohibited_interface_subtypes, XPC_ARRAY_APPEND, nw_interface_subtype_companion);
89 }
90 }
91 if (prohibited_interface_subtypes == NULL)
92 {
93 LogRedact(MDNS_LOG_CATEGORY_UDNS, MDNS_LOG_ERROR,
94 "mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: prohibited_interface_subtypes returned by xpc_array_create() is NULL");
95 }
96 else
97 {
98 nw_parameters_set_prohibited_interface_subtypes(parameters, prohibited_interface_subtypes);
99 }
100 #endif // TARGET_OS_WATCH
101
102 // Check for all the special (negative) internal value interface indices before initializing client_ifindex
103 if ( (q->InterfaceID == mDNSInterface_Any)
104 || (q->InterfaceID == mDNSInterface_LocalOnly)
105 || (q->InterfaceID == mDNSInterfaceMark)
106 || (q->InterfaceID == mDNSInterface_P2P)
107 || (q->InterfaceID == mDNSInterface_BLE)
108 || (q->InterfaceID == uDNSInterfaceMark))
109 {
110 client_ifindex = 0;
111 }
112 else
113 {
114 client_ifindex = (mDNSu32)(uintptr_t)q->InterfaceID;
115 }
116
117 if (client_ifindex > 0)
118 {
119 nw_interface_t client_intf = nw_interface_create_with_index(client_ifindex);
120 if (client_intf)
121 {
122 nw_parameters_require_interface(parameters, client_intf);
123 _nw_forget(&client_intf);
124 }
125 else
126 {
127 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
128 "[Q%u] mDNSPlatformGetDNSRoutePolicy: nw_interface_create_with_index() returned NULL for index %u",
129 mDNSVal16(q->TargetQID), client_ifindex);
130 }
131 }
132
133 nw_parameters_set_uid(parameters,(uid_t)q->euid);
134
135 if (q->pid != 0)
136 {
137 nw_parameters_set_pid(parameters, q->pid);
138 retval = proc_pidinfo(q->pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
139 if (retval == (int)sizeof(info))
140 {
141 nw_parameters_set_e_proc_uuid(parameters, info.p_uuid);
142 isUUIDSet = mDNStrue;
143 }
144 else
145 {
146 debugf("mDNSPlatformGetDNSRoutePolicy: proc_pidinfo returned %d", retval);
147 isUUIDSet = mDNSfalse;
148 }
149 }
150 else
151 {
152 nw_parameters_set_e_proc_uuid(parameters, q->uuid);
153 isUUIDSet = mDNStrue;
154 }
155
156 evaluator = nw_path_create_evaluator_for_endpoint(host, parameters);
157 if (evaluator == NULL)
158 {
159 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
160 "[Q%u] mDNSPlatformGetDNSRoutePolicy: Query for " PRI_DM_NAME " (" PUB_S "), PID[%d], EUID[%d], ServiceID[%d]"
161 " evaluator is NULL",
162 mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
163 goto exit;
164 }
165 _nw_forget(&host);
166 _nw_forget(&parameters);
167
168 path = nw_path_evaluator_copy_path(evaluator);
169 if (path == NULL)
170 {
171 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
172 "[Q%u] mDNSPlatformGetDNSRoutePolicy: Query for " PRI_DM_NAME " (" PUB_S "), PID[%d], EUID[%d], ServiceID[%d]"
173 " path is NULL",
174 mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
175 goto exit;
176 }
177 service_id = nw_path_get_flow_divert_unit(path);
178 if (service_id != 0)
179 {
180 q->ServiceID = service_id;
181 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
182 "[Q%u] mDNSPlatformGetDNSRoutePolicy: Query for " PRI_DM_NAME " service ID is set ->service_ID:[%d] ",
183 mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), service_id);
184 }
185 else
186 {
187 nw_interface_t nwpath_intf = nw_path_copy_scoped_interface(path);
188 if (nwpath_intf != NULL)
189 {
190 // Use the new scoped interface given by NW PATH EVALUATOR
191 dnspol_ifindex = nw_interface_get_index(nwpath_intf);
192 q->InterfaceID = (mDNSInterfaceID)(uintptr_t)dnspol_ifindex;
193
194 _nw_forget(&nwpath_intf);
195
196 if (dnspol_ifindex != client_ifindex)
197 {
198 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
199 "[Q%u] mDNSPlatformGetDNSRoutePolicy: DNS Route Policy has changed the scoped ifindex from [%d] to [%d]",
200 mDNSVal16(q->TargetQID), client_ifindex, dnspol_ifindex);
201 }
202 }
203 else
204 {
205 debugf("mDNSPlatformGetDNSRoutePolicy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_interface_t nwpath_intf is NULL ", q->qname.c, DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
206 }
207 }
208
209 #if MDNSRESPONDER_SUPPORTS(APPLE, QUERIER)
210 uuid_clear(q->ResolverUUID);
211 if (__builtin_available(macOS 10.16, iOS 14.0, watchOS 7.0, tvOS 14.0, *))
212 {
213 if (path != NULL)
214 {
215 __block nw_resolver_config_t best_config = NULL;
216 __block nw_resolver_class_t best_class = nw_resolver_class_default_direct;
217 nw_path_enumerate_resolver_configs(path,
218 ^bool(nw_resolver_config_t config)
219 {
220 const nw_resolver_class_t class = nw_resolver_config_get_class(config);
221 if (class != nw_resolver_class_default_direct &&
222 (best_class == nw_resolver_class_default_direct || class < best_class))
223 {
224 best_class = class;
225 best_config = config;
226 }
227 return true;
228 });
229 if (best_config != NULL)
230 {
231 nw_resolver_config_get_identifier(best_config, q->ResolverUUID);
232 }
233 }
234 }
235 if (!uuid_is_null(q->ResolverUUID))
236 {
237 Querier_RegisterPathResolver(q->ResolverUUID);
238 }
239 #endif
240 if (isUUIDSet && path && (nw_path_get_status(path) == nw_path_status_unsatisfied) && (nw_path_get_reason(path) != nw_path_reason_no_route))
241 {
242 isBlocked = mDNStrue;
243 }
244
245 exit:
246 _nw_forget(&host);
247 _nw_forget(&parameters);
248 _nw_forget(&path);
249 _nw_forget(&evaluator);
250 q->BlockedByPolicy = isBlocked;
251 }