1/*
2 * Copyright (c) 2004-2006, 2009, 2011-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <stdlib.h>
25#include <strings.h>
26#include <mach/mach.h>
27#include <mach/mach_error.h>
28#include <mach/mach_time.h>
29#include <CommonCrypto/CommonDigest.h>
30#include <CoreFoundation/CoreFoundation.h>
31#include <SystemConfiguration/SystemConfiguration.h>
32#include <SystemConfiguration/SCPrivate.h>
33
34#include "dnsinfo_create.h"
35#include "dnsinfo_private.h"
36#include "network_information_priv.h"
37
38#include "ip_plugin.h"
39
40
41#define ROUNDUP(a, size) \
42	(((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
43
44
45/*
46 * to avoid extra calls to realloc() we want to pre-allocate the initial
47 * resolver and configuration buffers of a sufficient size that they would
48 * not normally need to be expanded.
49 */
50#define INITIAL_CONFIGURATION_BUF_SIZE  8192
51#define INITIAL_RESOLVER_BUF_SIZE       1024
52
53
54/*
55 * DNS [configuration] buffer functions
56 */
57
58
59__private_extern__
60dns_create_config_t
61_dns_configuration_create()
62{
63	_dns_config_buf_t	*config;
64
65	config = calloc(1, INITIAL_CONFIGURATION_BUF_SIZE);
66	config->config.generation = mach_absolute_time();
67//	config->n_attribute = 0;
68//	config->n_padding = 0;
69	return (dns_create_config_t)config;
70}
71
72
73static void
74config_add_attribute(dns_create_config_t	*_config,
75		     uint32_t			attribute_type,
76		     uint32_t			attribute_length,
77		     void			*attribute,
78		     uint32_t			extra_padding)
79{
80	_dns_config_buf_t	*config	= (_dns_config_buf_t *)*_config;
81	dns_attribute_t		*header;
82	int			i;
83	uint32_t		newLen;
84	uint32_t		newSize;
85	uint32_t		oldLen;
86	uint32_t		rounded_length;
87
88	// add space
89
90	oldLen         = ntohl(config->n_attribute);
91	rounded_length = ROUNDUP(attribute_length, sizeof(uint32_t));
92	newLen         = sizeof(dns_attribute_t) + rounded_length;
93	newSize = sizeof(_dns_config_buf_t) + oldLen + newLen;
94	if (newSize > INITIAL_CONFIGURATION_BUF_SIZE) {
95		config = realloc(config, newSize);
96	}
97	config->n_attribute = htonl(ntohl(config->n_attribute) + newLen);
98
99	// increment additional padding that will be needed (later)
100	config->n_padding = htonl(ntohl(config->n_padding) + extra_padding);
101
102	// add attribute [header]
103
104	/* ALIGN: _dns_config_buf_t is int aligned */
105	header = (dns_attribute_t *)(void *)&config->attribute[oldLen];
106	header->type   = htonl(attribute_type);
107	header->length = htonl(newLen);
108
109	// add attribute [data]
110
111	bcopy(attribute, &header->attribute[0], attribute_length);
112	for (i = attribute_length; i < rounded_length; i++) {
113		header->attribute[i] = 0;
114	}
115
116	*_config = (dns_create_config_t)config;
117	return;
118}
119
120
121static void
122_dns_resolver_set_reach_flags(dns_create_resolver_t _resolver);
123
124
125__private_extern__
126void
127_dns_configuration_add_resolver(dns_create_config_t     *_config,
128				dns_create_resolver_t	_resolver)
129{
130	_dns_config_buf_t	*config		= (_dns_config_buf_t *)*_config;
131	uint32_t		padding		= 0;
132	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)_resolver;
133
134	/*
135	 * add reachability flags for this resovler configuration
136	 */
137	_dns_resolver_set_reach_flags(_resolver);
138
139	/*
140	 * compute the amount of space that will be needed for
141	 * pointers to the resolver, the nameservers, the search
142	 * list, and the sortaddr list.
143	 */
144	padding += sizeof(DNS_PTR(dns_resolver_t *, x));
145	if (resolver->resolver.n_nameserver != 0) {
146		padding += ntohl(resolver->resolver.n_nameserver) * sizeof(DNS_PTR(struct sockaddr *, x));
147	}
148	if (resolver->resolver.n_search != 0) {
149		padding += ntohl(resolver->resolver.n_search) * sizeof(DNS_PTR(char *, x));
150	}
151	if (resolver->resolver.n_sortaddr != 0) {
152		padding += ntohl(resolver->resolver.n_sortaddr) * sizeof(DNS_PTR(dns_sortaddr_t *, x));
153	}
154
155	if ((ntohl(resolver->resolver.flags) & DNS_RESOLVER_FLAGS_SCOPED)) {
156		config->config.n_scoped_resolver = htonl(ntohl(config->config.n_scoped_resolver) + 1);
157		config_add_attribute(_config,
158				     CONFIG_ATTRIBUTE_SCOPED_RESOLVER,
159				     sizeof(_dns_resolver_buf_t) + ntohl(resolver->n_attribute),
160				     (void *)resolver,
161				     padding);
162	} else if ((ntohl(resolver->resolver.flags) & DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC)) {
163		config->config.n_service_specific_resolver = htonl(ntohl(config->config.n_service_specific_resolver) + 1);
164		config_add_attribute(_config,
165				     CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER,
166				     sizeof(_dns_resolver_buf_t) + ntohl(resolver->n_attribute),
167				     (void *)resolver,
168				     padding);
169	} else {
170		config->config.n_resolver = htonl(ntohl(config->config.n_resolver) + 1);
171		config_add_attribute(_config,
172				     CONFIG_ATTRIBUTE_RESOLVER,
173				     sizeof(_dns_resolver_buf_t) + ntohl(resolver->n_attribute),
174				     (void *)resolver,
175				     padding);
176	}
177
178	return;
179}
180
181
182__private_extern__
183void
184_dns_configuration_signature(dns_create_config_t	*_config,
185			     unsigned char		*signature,
186			     size_t			signature_len)
187{
188	bzero(signature, signature_len);
189
190	if (_config != NULL) {
191		_dns_config_buf_t	*config	= (_dns_config_buf_t *)*_config;
192
193		if (config != NULL) {
194			CC_SHA1_CTX	ctx;
195			uint64_t	generation_save;
196			unsigned char	*sha1;
197			unsigned char	sha1_buf[CC_SHA1_DIGEST_LENGTH];
198
199			generation_save = config->config.generation;
200			config->config.generation = 0;
201
202			sha1 = (signature_len >= CC_SHA1_DIGEST_LENGTH) ? signature : sha1_buf;
203			CC_SHA1_Init(&ctx);
204			CC_SHA1_Update(&ctx,
205				       config,
206				       sizeof(_dns_config_buf_t) + ntohl(config->n_attribute));
207			CC_SHA1_Final(sha1, &ctx);
208			if (sha1 != signature) {
209				bcopy(sha1, signature, signature_len);
210			}
211
212			config->config.generation = generation_save;
213		}
214	}
215
216	return;
217}
218
219
220__private_extern__
221void
222_dns_configuration_free(dns_create_config_t *_config)
223{
224	_dns_config_buf_t	*config	= (_dns_config_buf_t *)*_config;
225
226	free(config);
227	*_config = NULL;
228	return;
229}
230
231
232/*
233 * DNS resolver configuration functions
234 */
235
236__private_extern__
237dns_create_resolver_t
238_dns_resolver_create()
239{
240	_dns_resolver_buf_t	*buf;
241
242	buf = calloc(1, INITIAL_RESOLVER_BUF_SIZE);
243//	buf->n_attribute = 0;
244	return (dns_create_resolver_t)buf;
245}
246
247
248static void
249_dns_resolver_add_attribute(dns_create_resolver_t	*_resolver,
250			    uint32_t			attribute_type,
251			    uint32_t			attribute_length,
252			    void			*attribute)
253{
254	dns_attribute_t		*header;
255	int			i;
256	uint32_t		newLen;
257	uint32_t		newSize;
258	uint32_t		oldLen;
259	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
260	uint32_t		rounded_length;
261
262	// add space
263
264	oldLen         = ntohl(resolver->n_attribute);
265	rounded_length = ROUNDUP(attribute_length, sizeof(uint32_t));
266	newLen         = sizeof(dns_attribute_t) + rounded_length;
267	newSize = sizeof(_dns_resolver_buf_t) + oldLen + newLen;
268	if (newSize > INITIAL_RESOLVER_BUF_SIZE) {
269		resolver = realloc(resolver, newSize);
270	}
271	resolver->n_attribute = htonl(ntohl(resolver->n_attribute) + newLen);
272
273	// add attribute [header]
274
275	/* ALIGN: _dns_resolver_buf_t is int aligned */
276	header = (dns_attribute_t *)(void *)&resolver->attribute[oldLen];
277	header->type   = htonl(attribute_type);
278	header->length = htonl(newLen);
279
280	// add attribute [data]
281
282	bcopy(attribute, &header->attribute[0], attribute_length);
283	for (i = attribute_length; i < rounded_length; i++) {
284		header->attribute[i] = 0;
285	}
286
287	*_resolver = (dns_create_resolver_t)resolver;
288	return;
289}
290
291
292__private_extern__
293void
294_dns_resolver_add_nameserver(dns_create_resolver_t *_resolver, struct sockaddr *nameserver)
295{
296	uint32_t		new_flags	= 0;
297	uint32_t		old_flags;
298	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
299
300	old_flags = ntohl(resolver->resolver.flags);
301
302	switch (nameserver->sa_family) {
303		case AF_INET:
304			if (ntohl(((struct sockaddr_in*)(void *)nameserver)->sin_addr.s_addr) == INADDR_LOOPBACK) {
305				new_flags = DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
306			}
307			break;
308		case AF_INET6:
309			if (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)nameserver)->sin6_addr)){
310				new_flags = DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
311			}
312			break;
313		default:
314			break;
315	}
316
317	resolver->resolver.n_nameserver = htonl(ntohl(resolver->resolver.n_nameserver) + 1);
318	_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_ADDRESS, nameserver->sa_len, (void *)nameserver);
319
320	if (new_flags != 0) {
321		// if DNS request flags not explicitly set and we are
322		// adding a LOOPBACK resolver address
323		_dns_resolver_set_flags(_resolver, old_flags | new_flags);
324	}
325	return;
326}
327
328
329__private_extern__
330void
331_dns_resolver_add_search(dns_create_resolver_t *_resolver, const char *search)
332{
333	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
334
335	resolver->resolver.n_search = htonl(ntohl(resolver->resolver.n_search) + 1);
336	_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SEARCH, (uint32_t)strlen(search) + 1, (void *)search);
337	return;
338}
339
340
341__private_extern__
342void
343_dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr)
344{
345	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
346
347	resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1);
348	_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, (uint32_t)sizeof(dns_sortaddr_t), (void *)sortaddr);
349	return;
350}
351
352
353__private_extern__
354void
355_dns_resolver_set_domain(dns_create_resolver_t *_resolver, const char *domain)
356{
357	_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_DOMAIN, (uint32_t)strlen(domain) + 1, (void *)domain);
358	return;
359}
360
361
362__private_extern__
363void
364_dns_resolver_set_flags(dns_create_resolver_t *_resolver, uint32_t flags)
365{
366	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
367
368	resolver->resolver.flags = htonl(flags);
369	return;
370}
371
372
373__private_extern__
374void
375_dns_resolver_set_if_index(dns_create_resolver_t *_resolver, uint32_t if_index)
376{
377	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
378
379	resolver->resolver.if_index = htonl(if_index);
380	return;
381}
382
383
384__private_extern__
385void
386_dns_resolver_set_options(dns_create_resolver_t *_resolver, const char *options)
387{
388	_dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_OPTIONS, (uint32_t)strlen(options) + 1, (void *)options);
389	return;
390}
391
392
393__private_extern__
394void
395_dns_resolver_set_order(dns_create_resolver_t *_resolver, uint32_t order)
396{
397	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
398
399	resolver->resolver.search_order = htonl(order);
400	return;
401}
402
403
404__private_extern__
405void
406_dns_resolver_set_port(dns_create_resolver_t *_resolver, uint16_t port)
407{
408	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
409
410	resolver->resolver.port = htons(port);
411	return;
412}
413
414
415/*
416 * rankReachability()
417 *   Not reachable       == 0
418 *   Connection Required == 1
419 *   Reachable           == 2
420 */
421static int
422rankReachability(SCNetworkReachabilityFlags flags)
423{
424	int	rank = 0;
425
426	if (flags & kSCNetworkReachabilityFlagsReachable)		rank = 2;
427	if (flags & kSCNetworkReachabilityFlagsConnectionRequired)	rank = 1;
428	return rank;
429}
430
431
432static void
433_dns_resolver_set_reach_flags(dns_create_resolver_t _resolver)
434{
435	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)_resolver;
436
437	if (resolver->resolver.n_nameserver != 0) {
438		dns_attribute_t			*attribute;
439		SCNetworkReachabilityFlags	flags		= kSCNetworkReachabilityFlagsReachable;
440		uint32_t			n_attribute;
441		uint32_t			n_nameserver	= 0;
442		CFMutableDictionaryRef		targetOptions;
443
444		targetOptions = CFDictionaryCreateMutable(NULL,
445							  0,
446							  &kCFTypeDictionaryKeyCallBacks,
447							  &kCFTypeDictionaryValueCallBacks);
448		CFDictionarySetValue(targetOptions,
449				     kSCNetworkReachabilityOptionServerBypass,
450				     kCFBooleanTrue);
451		if (resolver->resolver.if_index != 0) {
452			char		if_name[IFNAMSIZ];
453
454			if (if_indextoname(ntohl(resolver->resolver.if_index), if_name) != NULL) {
455				CFStringRef	targetInterface;
456
457				targetInterface = CFStringCreateWithCString(NULL,
458									    if_name,
459									    kCFStringEncodingASCII);
460				CFDictionarySetValue(targetOptions,
461						     kSCNetworkReachabilityOptionInterface,
462						     targetInterface);
463				CFRelease(targetInterface);
464			}
465		}
466
467		attribute   = (dns_attribute_t *)(void *)&resolver->attribute[0];
468		n_attribute = ntohl(resolver->n_attribute);
469
470		while (n_attribute >= sizeof(dns_attribute_t)) {
471			uint32_t	attribute_length	= ntohl(attribute->length);
472			uint32_t	attribute_type		= ntohl(attribute->type);
473
474			if (attribute_type == RESOLVER_ATTRIBUTE_ADDRESS) {
475				struct sockaddr			*addr;
476				CFDataRef			addrData;
477				SCNetworkReachabilityFlags	ns_flags;
478				Boolean				ok;
479				SCNetworkReachabilityRef	target;
480
481				addr = (struct sockaddr *)&attribute->attribute[0];
482				addrData = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
483				CFDictionarySetValue(targetOptions,
484						     kSCNetworkReachabilityOptionRemoteAddress,
485						     addrData);
486				CFRelease(addrData);
487
488				target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
489				if (target == NULL) {
490					CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface);
491					target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
492					if (target != NULL) {
493						// if interface name not (no longer) valid
494						CFRelease(target);
495						flags = 0;
496						break;
497					}
498
499					// address not valid?
500					my_log(LOG_ERR,
501					       "_dns_resolver_set_reach_flags SCNetworkReachabilityCreateWithOptions() failed:\n  options = %@",
502					       targetOptions);
503					break;
504				}
505
506				ok = SCNetworkReachabilityGetFlags(target, &ns_flags);
507				CFRelease(target);
508				if (!ok) {
509					break;
510				}
511
512				if ((n_nameserver++ == 0) ||
513				    (rankReachability(ns_flags) < rankReachability(flags))) {
514					/* return the first (and later, worst case) result */
515					flags = ns_flags;
516				}
517			}
518
519			attribute   = (dns_attribute_t *)((void *)attribute + attribute_length);
520			n_attribute -= attribute_length;
521		}
522
523		CFRelease(targetOptions);
524
525		resolver->resolver.reach_flags = htonl(flags);
526	}
527
528	return;
529}
530
531
532__private_extern__
533void
534_dns_resolver_set_timeout(dns_create_resolver_t *_resolver, uint32_t timeout)
535{
536	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
537
538	resolver->resolver.timeout = htonl(timeout);
539	return;
540}
541
542
543__private_extern__
544void
545_dns_resolver_set_service_identifier(dns_create_resolver_t *_resolver, uint32_t service_identifier)
546{
547	_dns_resolver_buf_t *resolver	= (_dns_resolver_buf_t *)*_resolver;
548
549	resolver->resolver.service_identifier = htonl(service_identifier);
550}
551
552
553__private_extern__
554void
555_dns_resolver_free(dns_create_resolver_t *_resolver)
556{
557	_dns_resolver_buf_t	*resolver	= (_dns_resolver_buf_t *)*_resolver;
558
559	free(resolver);
560	*_resolver = NULL;
561	return;
562}
563