2 * Copyright (c) 2013, 2015-2018 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 <os/availability.h>
28 #include <TargetConditionals.h>
29 #include <sys/cdefs.h>
30 #include <SystemConfiguration/SCPrivate.h> // for SC_log
31 #include <arpa/inet.h>
34 #include "dnsinfo_private.h"
36 #define DNS_CONFIG_BUF_MAX 1024*1024
41 #define my_log(__level, __format, ...) SC_log(__level, __format, ## __VA_ARGS__)
42 #define MY_LOG_DEFINED_LOCALLY
46 * claim space for a list [of pointers] from the expanded DNS configuration padding
48 static __inline__ boolean_t
49 __dns_configuration_expand_add_list(void **padding
, uint32_t *n_padding
, uint32_t count
, uint32_t size
, void **list
)
54 if (need
> *n_padding
) {
58 *list
= (need
== 0) ? NULL
: *padding
;
66 * expand a DNS "resolver" from the provided buffer
68 static __inline__ dns_resolver_t
*
69 _dns_configuration_expand_resolver(_dns_resolver_buf_t
*buf
, uint32_t n_buf
, void **padding
, uint32_t *n_padding
)
71 dns_attribute_t
*attribute
;
73 int32_t n_nameserver
= 0;
75 int32_t n_sortaddr
= 0;
77 dns_resolver_t
*resolver
= (dns_resolver_t
*)&buf
->resolver
;
79 if (n_buf
< sizeof(_dns_resolver_buf_t
)) {
85 resolver
->domain
= NULL
;
87 // initialize nameserver list
89 resolver
->n_nameserver
= ntohl(resolver
->n_nameserver
);
90 if (!__dns_configuration_expand_add_list(padding
,
92 resolver
->n_nameserver
,
93 sizeof(DNS_PTR(struct sockaddr
*, x
)),
97 resolver
->nameserver
= ptr
;
101 resolver
->port
= ntohs(resolver
->port
);
103 // initialize search list
105 resolver
->n_search
= ntohl(resolver
->n_search
);
106 if (!__dns_configuration_expand_add_list(padding
,
109 sizeof(DNS_PTR(char *, x
)),
113 resolver
->search
= ptr
;
115 // initialize sortaddr list
117 resolver
->n_sortaddr
= ntohl(resolver
->n_sortaddr
);
118 if (!__dns_configuration_expand_add_list(padding
,
120 resolver
->n_sortaddr
,
121 sizeof(DNS_PTR(dns_sortaddr_t
*, x
)),
125 resolver
->sortaddr
= ptr
;
127 // initialize options
129 resolver
->options
= NULL
;
131 // initialize timeout
133 resolver
->timeout
= ntohl(resolver
->timeout
);
135 // initialize search_order
137 resolver
->search_order
= ntohl(resolver
->search_order
);
139 // initialize if_index
141 resolver
->if_index
= ntohl(resolver
->if_index
);
143 // initialize service_identifier
145 resolver
->service_identifier
= ntohl(resolver
->service_identifier
);
149 resolver
->flags
= ntohl(resolver
->flags
);
151 // initialize SCNetworkReachability flags
153 resolver
->reach_flags
= ntohl(resolver
->reach_flags
);
155 // process resolver buffer "attribute" data
157 n_attribute
= n_buf
- sizeof(_dns_resolver_buf_t
);
158 /* ALIGN: alignment not assumed, using accessors */
159 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
160 if (n_attribute
!= ntohl(buf
->n_attribute
)) {
164 while (n_attribute
>= sizeof(dns_attribute_t
)) {
165 uint32_t attribute_length
= ntohl(attribute
->length
);
167 switch (ntohl(attribute
->type
)) {
168 case RESOLVER_ATTRIBUTE_DOMAIN
:
169 resolver
->domain
= (char *)&attribute
->attribute
[0];
172 case RESOLVER_ATTRIBUTE_ADDRESS
:
173 if (resolver
->nameserver
== NULL
) {
176 resolver
->nameserver
[n_nameserver
++] = (struct sockaddr
*)&attribute
->attribute
[0];
179 case RESOLVER_ATTRIBUTE_SEARCH
:
180 if (resolver
->search
== NULL
) {
183 resolver
->search
[n_search
++] = (char *)&attribute
->attribute
[0];
186 case RESOLVER_ATTRIBUTE_SORTADDR
:
187 if (resolver
->sortaddr
== NULL
) {
190 resolver
->sortaddr
[n_sortaddr
++] = (dns_sortaddr_t
*)(void *)&attribute
->attribute
[0];
193 case RESOLVER_ATTRIBUTE_OPTIONS
:
194 resolver
->options
= (char *)&attribute
->attribute
[0];
197 case RESOLVER_ATTRIBUTE_CONFIGURATION_ID
:
198 resolver
->cid
= (char *)&attribute
->attribute
[0];
201 case RESOLVER_ATTRIBUTE_INTERFACE_NAME
:
202 resolver
->if_name
= (char *)&attribute
->attribute
[0];
209 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
210 n_attribute
-= attribute_length
;
213 if ((n_nameserver
!= resolver
->n_nameserver
) ||
214 (n_search
!= resolver
->n_search
) ||
215 (n_sortaddr
!= resolver
->n_sortaddr
)) {
228 * initialize a DNS "configuration" buffer
230 static __inline__ _dns_config_buf_t
*
231 _dns_configuration_buffer_create(const void *dataRef
, size_t dataLen
)
235 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)dataRef
;
237 uint32_t n_attribute
= ntohl(config
->n_attribute
);
238 uint32_t n_padding
= ntohl(config
->n_padding
);
241 * Check that the size of the configuration header plus the size of the
242 * attribute data matches the size of the configuration buffer.
244 * If the sizes are different, something that should NEVER happen, CRASH!
246 configLen
= sizeof(_dns_config_buf_t
) + n_attribute
;
248 assert(configLen
== dataLen
);
250 if (configLen
!= dataLen
) {
251 my_log(LOG_ERR
, "DNS configuration: size error (%zu != %zu)", configLen
, dataLen
);
257 * Check that the size of the requested padding would not result in our
258 * allocating a configuration + padding buffer larger than our maximum size.
260 * If the requested padding size is too large, something that should NEVER
264 assert(n_padding
<= (DNS_CONFIG_BUF_MAX
- dataLen
));
266 if (n_padding
> (DNS_CONFIG_BUF_MAX
- dataLen
)) {
267 my_log(LOG_ERR
, "DNS configuration: padding error (%u > %zu)",
269 (DNS_CONFIG_BUF_MAX
- dataLen
));
275 * Check that the actual size of the configuration data and any requested
276 * padding will be less than the maximum possible size of the in-memory
277 * configuration buffer.
279 * If the length needed is too large, something that should NEVER happen, CRASH!
281 bufLen
= dataLen
+ n_padding
;
283 assert(bufLen
<= DNS_CONFIG_BUF_MAX
);
285 if (bufLen
> DNS_CONFIG_BUF_MAX
) {
286 my_log(LOG_ERR
, "DNS configuration: length error (%zu > %u)",
293 // allocate a buffer large enough to hold both the configuration
294 // data and the padding.
295 buf
= malloc(bufLen
);
296 memcpy(buf
, (void *)dataRef
, dataLen
);
297 memset(&buf
[dataLen
], 0, n_padding
);
299 return (_dns_config_buf_t
*)(void *)buf
;
304 * expand a DNS "configuration" from the provided buffer
306 static __inline__
void
307 _dns_configuration_buffer_free(_dns_config_buf_t
**buf
)
309 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*buf
;
318 * expand a DNS "configuration" from the provided buffer
320 static __inline__ dns_config_t
*
321 _dns_configuration_buffer_expand(_dns_config_buf_t
*buf
)
323 dns_attribute_t
*attribute
;
324 dns_config_t
*config
= (dns_config_t
*)buf
;
325 uint32_t n_attribute
;
327 int32_t n_resolver
= 0;
328 int32_t n_scoped_resolver
= 0;
329 int32_t n_service_specific_resolver
= 0;
333 n_attribute
= ntohl(buf
->n_attribute
); // pre-validated (or known OK) at entry
334 n_padding
= ntohl(buf
->n_padding
); // pre-validated (or known OK) at entry
336 // establish the start of padding to be after the last attribute
338 padding
= &buf
->attribute
[n_attribute
];
340 // initialize resolver lists
342 config
->n_resolver
= ntohl(config
->n_resolver
);
343 if (!__dns_configuration_expand_add_list(&padding
,
346 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
350 config
->resolver
= ptr
;
352 config
->n_scoped_resolver
= ntohl(config
->n_scoped_resolver
);
353 if (!__dns_configuration_expand_add_list(&padding
,
355 config
->n_scoped_resolver
,
356 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
360 config
->scoped_resolver
= ptr
;
362 config
->n_service_specific_resolver
= ntohl(config
->n_service_specific_resolver
);
363 if (!__dns_configuration_expand_add_list(&padding
,
365 config
->n_service_specific_resolver
,
366 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
370 config
->service_specific_resolver
= ptr
;
372 // process configuration buffer "attribute" data
374 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
376 while (n_attribute
>= sizeof(dns_attribute_t
)) {
377 uint32_t attribute_length
= ntohl(attribute
->length
);
378 uint32_t attribute_type
= ntohl(attribute
->type
);
380 switch (attribute_type
) {
381 case CONFIG_ATTRIBUTE_RESOLVER
:
382 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER
:
383 case CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER
: {
384 dns_resolver_t
*resolver
;
386 // expand resolver buffer
388 resolver
= _dns_configuration_expand_resolver((_dns_resolver_buf_t
*)(void *)&attribute
->attribute
[0],
389 attribute_length
- sizeof(dns_attribute_t
),
392 if (resolver
== NULL
) {
396 // add resolver to config list
398 if (attribute_type
== CONFIG_ATTRIBUTE_RESOLVER
) {
399 if (config
->resolver
== NULL
) {
402 config
->resolver
[n_resolver
++] = resolver
;
403 } else if (attribute_type
== CONFIG_ATTRIBUTE_SCOPED_RESOLVER
) {
404 if (config
->scoped_resolver
== NULL
) {
407 config
->scoped_resolver
[n_scoped_resolver
++] = resolver
;
408 } else if (attribute_type
== CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER
) {
409 if (config
->service_specific_resolver
== NULL
) {
412 config
->service_specific_resolver
[n_service_specific_resolver
++] = resolver
;
422 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
423 n_attribute
-= attribute_length
;
426 if (n_resolver
!= config
->n_resolver
) {
430 if (n_scoped_resolver
!= config
->n_scoped_resolver
) {
434 if (n_service_specific_resolver
!= config
->n_service_specific_resolver
) {
445 #ifdef MY_LOG_DEFINED_LOCALLY
447 #undef MY_LOG_DEFINED_LOCALLY
448 #endif // MY_LOG_DEFINED_LOCALLY
452 #endif /* !_S_DNSINFO_INTERNAL_H */