2 * Copyright (c) 2013, 2015-2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #ifndef _S_DNSINFO_INTERNAL_H
25 #define _S_DNSINFO_INTERNAL_H
27 #include <Availability.h>
28 #include <TargetConditionals.h>
29 #include <sys/cdefs.h>
30 #include <SystemConfiguration/SystemConfiguration.h>
31 #include <SystemConfiguration/SCPrivate.h>
32 #include <arpa/inet.h>
35 #include "dnsinfo_private.h"
37 #define DNS_CONFIG_BUF_MAX 1024*1024
42 #define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__)
43 #define MY_LOG_DEFINED_LOCALLY
47 * claim space for a list [of pointers] from the expanded DNS configuration padding
49 static __inline__ boolean_t
50 __dns_configuration_expand_add_list(void **padding
, uint32_t *n_padding
, uint32_t count
, uint32_t size
, void **list
)
55 if (need
> *n_padding
) {
59 *list
= (need
== 0) ? NULL
: *padding
;
67 * expand a DNS "resolver" from the provided buffer
69 static __inline__ dns_resolver_t
*
70 _dns_configuration_expand_resolver(_dns_resolver_buf_t
*buf
, uint32_t n_buf
, void **padding
, uint32_t *n_padding
)
72 dns_attribute_t
*attribute
;
74 int32_t n_nameserver
= 0;
76 int32_t n_sortaddr
= 0;
78 dns_resolver_t
*resolver
= (dns_resolver_t
*)&buf
->resolver
;
80 if (n_buf
< sizeof(_dns_resolver_buf_t
)) {
86 resolver
->domain
= NULL
;
88 // initialize nameserver list
90 resolver
->n_nameserver
= ntohl(resolver
->n_nameserver
);
91 if (!__dns_configuration_expand_add_list(padding
,
93 resolver
->n_nameserver
,
94 sizeof(DNS_PTR(struct sockaddr
*, x
)),
98 resolver
->nameserver
= ptr
;
102 resolver
->port
= ntohs(resolver
->port
);
104 // initialize search list
106 resolver
->n_search
= ntohl(resolver
->n_search
);
107 if (!__dns_configuration_expand_add_list(padding
,
110 sizeof(DNS_PTR(char *, x
)),
114 resolver
->search
= ptr
;
116 // initialize sortaddr list
118 resolver
->n_sortaddr
= ntohl(resolver
->n_sortaddr
);
119 if (!__dns_configuration_expand_add_list(padding
,
121 resolver
->n_sortaddr
,
122 sizeof(DNS_PTR(dns_sortaddr_t
*, x
)),
126 resolver
->sortaddr
= ptr
;
128 // initialize options
130 resolver
->options
= NULL
;
132 // initialize timeout
134 resolver
->timeout
= ntohl(resolver
->timeout
);
136 // initialize search_order
138 resolver
->search_order
= ntohl(resolver
->search_order
);
140 // initialize if_index
142 resolver
->if_index
= ntohl(resolver
->if_index
);
144 // initialize service_identifier
146 resolver
->service_identifier
= ntohl(resolver
->service_identifier
);
150 resolver
->flags
= ntohl(resolver
->flags
);
152 // initialize SCNetworkReachability flags
154 resolver
->reach_flags
= ntohl(resolver
->reach_flags
);
156 // process resolver buffer "attribute" data
158 n_attribute
= n_buf
- sizeof(_dns_resolver_buf_t
);
159 /* ALIGN: alignment not assumed, using accessors */
160 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
161 if (n_attribute
!= ntohl(buf
->n_attribute
)) {
165 while (n_attribute
>= sizeof(dns_attribute_t
)) {
166 uint32_t attribute_length
= ntohl(attribute
->length
);
168 switch (ntohl(attribute
->type
)) {
169 case RESOLVER_ATTRIBUTE_DOMAIN
:
170 resolver
->domain
= (char *)&attribute
->attribute
[0];
173 case RESOLVER_ATTRIBUTE_ADDRESS
:
174 if (resolver
->nameserver
== NULL
) {
177 resolver
->nameserver
[n_nameserver
++] = (struct sockaddr
*)&attribute
->attribute
[0];
180 case RESOLVER_ATTRIBUTE_SEARCH
:
181 if (resolver
->search
== NULL
) {
184 resolver
->search
[n_search
++] = (char *)&attribute
->attribute
[0];
187 case RESOLVER_ATTRIBUTE_SORTADDR
:
188 if (resolver
->sortaddr
== NULL
) {
191 resolver
->sortaddr
[n_sortaddr
++] = (dns_sortaddr_t
*)(void *)&attribute
->attribute
[0];
194 case RESOLVER_ATTRIBUTE_OPTIONS
:
195 resolver
->options
= (char *)&attribute
->attribute
[0];
198 case RESOLVER_ATTRIBUTE_CONFIGURATION_ID
:
199 resolver
->cid
= (char *)&attribute
->attribute
[0];
202 case RESOLVER_ATTRIBUTE_INTERFACE_NAME
:
203 resolver
->if_name
= (char *)&attribute
->attribute
[0];
210 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
211 n_attribute
-= attribute_length
;
214 if ((n_nameserver
!= resolver
->n_nameserver
) ||
215 (n_search
!= resolver
->n_search
) ||
216 (n_sortaddr
!= resolver
->n_sortaddr
)) {
229 * initialize a DNS "configuration" buffer
231 static __inline__ _dns_config_buf_t
*
232 _dns_configuration_buffer_create(const void *dataRef
, size_t dataLen
)
236 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)dataRef
;
238 uint32_t n_attribute
= ntohl(config
->n_attribute
);
239 uint32_t n_padding
= ntohl(config
->n_padding
);
242 * Check that the size of the configuration header plus the size of the
243 * attribute data matches the size of the configuration buffer.
245 * If the sizes are different, something that should NEVER happen, CRASH!
247 configLen
= sizeof(_dns_config_buf_t
) + n_attribute
;
249 assert(configLen
== dataLen
);
251 if (configLen
!= dataLen
) {
252 my_log(LOG_ERR
, "DNS configuration: size error (%zu != %zu)", configLen
, dataLen
);
258 * Check that the size of the requested padding would not result in our
259 * allocating a configuration + padding buffer larger than our maximum size.
261 * If the requested padding size is too large, something that should NEVER
265 assert(n_padding
<= (DNS_CONFIG_BUF_MAX
- dataLen
));
267 if (n_padding
> (DNS_CONFIG_BUF_MAX
- dataLen
)) {
268 my_log(LOG_ERR
, "DNS configuration: padding error (%u > %zu)",
270 (DNS_CONFIG_BUF_MAX
- dataLen
));
276 * Check that the actual size of the configuration data and any requested
277 * padding will be less than the maximum possible size of the in-memory
278 * configuration buffer.
280 * If the length needed is too large, something that should NEVER happen, CRASH!
282 bufLen
= dataLen
+ n_padding
;
284 assert(bufLen
<= DNS_CONFIG_BUF_MAX
);
286 if (bufLen
> DNS_CONFIG_BUF_MAX
) {
287 my_log(LOG_ERR
, "DNS configuration: length error (%zu > %u)",
294 // allocate a buffer large enough to hold both the configuration
295 // data and the padding.
296 buf
= malloc(bufLen
);
297 bcopy((void *)dataRef
, buf
, dataLen
);
298 bzero(&buf
[dataLen
], n_padding
);
300 return (_dns_config_buf_t
*)(void *)buf
;
305 * expand a DNS "configuration" from the provided buffer
307 static __inline__
void
308 _dns_configuration_buffer_free(_dns_config_buf_t
**buf
)
310 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*buf
;
319 * expand a DNS "configuration" from the provided buffer
321 static __inline__ dns_config_t
*
322 _dns_configuration_buffer_expand(_dns_config_buf_t
*buf
)
324 dns_attribute_t
*attribute
;
325 dns_config_t
*config
= (dns_config_t
*)buf
;
326 uint32_t n_attribute
;
328 int32_t n_resolver
= 0;
329 int32_t n_scoped_resolver
= 0;
330 int32_t n_service_specific_resolver
= 0;
334 n_attribute
= ntohl(buf
->n_attribute
); // pre-validated (or known OK) at entry
335 n_padding
= ntohl(buf
->n_padding
); // pre-validated (or known OK) at entry
337 // establish the start of padding to be after the last attribute
339 padding
= &buf
->attribute
[n_attribute
];
341 // initialize resolver lists
343 config
->n_resolver
= ntohl(config
->n_resolver
);
344 if (!__dns_configuration_expand_add_list(&padding
,
347 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
351 config
->resolver
= ptr
;
353 config
->n_scoped_resolver
= ntohl(config
->n_scoped_resolver
);
354 if (!__dns_configuration_expand_add_list(&padding
,
356 config
->n_scoped_resolver
,
357 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
361 config
->scoped_resolver
= ptr
;
363 config
->n_service_specific_resolver
= ntohl(config
->n_service_specific_resolver
);
364 if (!__dns_configuration_expand_add_list(&padding
,
366 config
->n_service_specific_resolver
,
367 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
371 config
->service_specific_resolver
= ptr
;
373 // process configuration buffer "attribute" data
375 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
377 while (n_attribute
>= sizeof(dns_attribute_t
)) {
378 uint32_t attribute_length
= ntohl(attribute
->length
);
379 uint32_t attribute_type
= ntohl(attribute
->type
);
381 switch (attribute_type
) {
382 case CONFIG_ATTRIBUTE_RESOLVER
:
383 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER
:
384 case CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER
: {
385 dns_resolver_t
*resolver
;
387 // expand resolver buffer
389 resolver
= _dns_configuration_expand_resolver((_dns_resolver_buf_t
*)(void *)&attribute
->attribute
[0],
390 attribute_length
- sizeof(dns_attribute_t
),
393 if (resolver
== NULL
) {
397 // add resolver to config list
399 if (attribute_type
== CONFIG_ATTRIBUTE_RESOLVER
) {
400 if (config
->resolver
== NULL
) {
403 config
->resolver
[n_resolver
++] = resolver
;
404 } else if (attribute_type
== CONFIG_ATTRIBUTE_SCOPED_RESOLVER
) {
405 if (config
->scoped_resolver
== NULL
) {
408 config
->scoped_resolver
[n_scoped_resolver
++] = resolver
;
409 } else if (attribute_type
== CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER
) {
410 if (config
->service_specific_resolver
== NULL
) {
413 config
->service_specific_resolver
[n_service_specific_resolver
++] = resolver
;
423 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
424 n_attribute
-= attribute_length
;
427 if (n_resolver
!= config
->n_resolver
) {
431 if (n_scoped_resolver
!= config
->n_scoped_resolver
) {
435 if (n_service_specific_resolver
!= config
->n_service_specific_resolver
) {
446 #ifdef MY_LOG_DEFINED_LOCALLY
448 #undef MY_LOG_DEFINED_LOCALLY
449 #endif // MY_LOG_DEFINED_LOCALLY
453 #endif /* !_S_DNSINFO_INTERNAL_H */