1/* 2 * Copyright (c) 2004, 2006, 2008-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/* 25 * Modification History 26 * 27 * March 9, 2004 Allan Nathanson <ajn@apple.com> 28 * - initial revision 29 */ 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <pthread.h> 34#include <mach/mach.h> 35#include <mach/mach_error.h> 36#include <dispatch/dispatch.h> 37#include <xpc/xpc.h> 38 39#include "libSystemConfiguration_client.h" 40#include "dnsinfo.h" 41#include "dnsinfo_private.h" 42 43typedef uint32_t getflags; 44 45static boolean_t 46add_list(void **padding, uint32_t *n_padding, int32_t count, int32_t size, void **list) 47{ 48 int32_t need; 49 50 need = count * size; 51 if (need > *n_padding) { 52 return FALSE; 53 } 54 55 *list = (need == 0) ? NULL : *padding; 56 *padding += need; 57 *n_padding -= need; 58 return TRUE; 59} 60 61 62#define DNS_CONFIG_BUF_MAX 1024*1024 63 64 65static dns_resolver_t * 66expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32_t *n_padding) 67{ 68 dns_attribute_t *attribute; 69 uint32_t n_attribute; 70 int32_t n_nameserver = 0; 71 int32_t n_search = 0; 72 int32_t n_sortaddr = 0; 73 dns_resolver_t *resolver = (dns_resolver_t *)&buf->resolver; 74 75 if (n_buf < sizeof(_dns_resolver_buf_t)) { 76 goto error; 77 } 78 79 // initialize domain 80 81 resolver->domain = NULL; 82 83 // initialize nameserver list 84 85 resolver->n_nameserver = ntohl(resolver->n_nameserver); 86 if (!add_list(padding, 87 n_padding, 88 resolver->n_nameserver, 89 sizeof(DNS_PTR(struct sockaddr *, x)), 90 (void **)&resolver->nameserver)) { 91 goto error; 92 } 93 94 // initialize port 95 96 resolver->port = ntohs(resolver->port); 97 98 // initialize search list 99 100 resolver->n_search = ntohl(resolver->n_search); 101 if (!add_list(padding, 102 n_padding, 103 resolver->n_search, 104 sizeof(DNS_PTR(char *, x)), 105 (void **)&resolver->search)) { 106 goto error; 107 } 108 109 // initialize sortaddr list 110 111 resolver->n_sortaddr = ntohl(resolver->n_sortaddr); 112 if (!add_list(padding, 113 n_padding, 114 resolver->n_sortaddr, 115 sizeof(DNS_PTR(dns_sortaddr_t *, x)), 116 (void **)&resolver->sortaddr)) { 117 goto error; 118 } 119 120 // initialize options 121 122 resolver->options = NULL; 123 124 // initialize timeout 125 126 resolver->timeout = ntohl(resolver->timeout); 127 128 // initialize search_order 129 130 resolver->search_order = ntohl(resolver->search_order); 131 132 // initialize if_index 133 134 resolver->if_index = ntohl(resolver->if_index); 135 136 // initialize service_identifier 137 138 resolver->service_identifier = ntohl(resolver->service_identifier); 139 140 // initialize flags 141 142 resolver->flags = ntohl(resolver->flags); 143 144 // initialize SCNetworkReachability flags 145 146 resolver->reach_flags = ntohl(resolver->reach_flags); 147 148 // process resolver buffer "attribute" data 149 150 n_attribute = n_buf - sizeof(_dns_resolver_buf_t); 151 /* ALIGN: alignment not assumed, using accessors */ 152 attribute = (dns_attribute_t *)(void *)&buf->attribute[0]; 153 if (n_attribute != ntohl(buf->n_attribute)) { 154 goto error; 155 } 156 157 while (n_attribute >= sizeof(dns_attribute_t)) { 158 uint32_t attribute_length = ntohl(attribute->length); 159 160 switch (ntohl(attribute->type)) { 161 case RESOLVER_ATTRIBUTE_DOMAIN : 162 resolver->domain = (char *)&attribute->attribute[0]; 163 break; 164 165 case RESOLVER_ATTRIBUTE_ADDRESS : 166 resolver->nameserver[n_nameserver++] = (struct sockaddr *)&attribute->attribute[0]; 167 break; 168 169 case RESOLVER_ATTRIBUTE_SEARCH : 170 resolver->search[n_search++] = (char *)&attribute->attribute[0]; 171 break; 172 173 case RESOLVER_ATTRIBUTE_SORTADDR : 174 resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)(void *)&attribute->attribute[0]; 175 break; 176 177 case RESOLVER_ATTRIBUTE_OPTIONS : 178 resolver->options = (char *)&attribute->attribute[0]; 179 break; 180 181 default : 182 break; 183 } 184 185 attribute = (dns_attribute_t *)((void *)attribute + attribute_length); 186 n_attribute -= attribute_length; 187 } 188 189 if ((n_nameserver != resolver->n_nameserver) || 190 (n_search != resolver->n_search ) || 191 (n_sortaddr != resolver->n_sortaddr )) { 192 goto error; 193 } 194 195 return resolver; 196 197 error : 198 199 return NULL; 200} 201 202 203static dns_config_t * 204expand_config(_dns_config_buf_t *buf) 205{ 206 dns_attribute_t *attribute; 207 dns_config_t *config = (dns_config_t *)buf; 208 uint32_t n_attribute; 209 uint32_t n_padding; 210 int32_t n_resolver = 0; 211 int32_t n_scoped_resolver = 0; 212 int32_t n_service_specific_resolver = 0; 213 void *padding; 214 215 // establish padding 216 217 padding = &buf->attribute[ntohl(buf->n_attribute)]; 218 n_padding = ntohl(buf->n_padding); 219 220 // initialize resolver lists 221 222 config->n_resolver = ntohl(config->n_resolver); 223 if (!add_list(&padding, 224 &n_padding, 225 config->n_resolver, 226 sizeof(DNS_PTR(dns_resolver_t *, x)), 227 (void **)&config->resolver)) { 228 goto error; 229 } 230 231 config->n_scoped_resolver = ntohl(config->n_scoped_resolver); 232 if (!add_list(&padding, 233 &n_padding, 234 config->n_scoped_resolver, 235 sizeof(DNS_PTR(dns_resolver_t *, x)), 236 (void **)&config->scoped_resolver)) { 237 goto error; 238 } 239 240 config->n_service_specific_resolver = ntohl(config->n_service_specific_resolver); 241 if (!add_list(&padding, 242 &n_padding, 243 config->n_service_specific_resolver, 244 sizeof(DNS_PTR(dns_resolver_t *, x)), 245 (void **)&config->service_specific_resolver)) { 246 goto error; 247 } 248 249 // process configuration buffer "attribute" data 250 251 n_attribute = ntohl(buf->n_attribute); 252 attribute = (dns_attribute_t *)(void *)&buf->attribute[0]; 253 254 while (n_attribute >= sizeof(dns_attribute_t)) { 255 uint32_t attribute_length = ntohl(attribute->length); 256 uint32_t attribute_type = ntohl(attribute->type); 257 258 switch (attribute_type) { 259 case CONFIG_ATTRIBUTE_RESOLVER : 260 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER : 261 case CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER : { 262 dns_resolver_t *resolver; 263 264 // expand resolver buffer 265 266 resolver = expand_resolver((_dns_resolver_buf_t *)(void *)&attribute->attribute[0], 267 attribute_length - sizeof(dns_attribute_t), 268 &padding, 269 &n_padding); 270 if (resolver == NULL) { 271 goto error; 272 } 273 274 // add resolver to config list 275 276 if (attribute_type == CONFIG_ATTRIBUTE_RESOLVER) { 277 config->resolver[n_resolver++] = resolver; 278 } else if (attribute_type == CONFIG_ATTRIBUTE_SCOPED_RESOLVER) { 279 config->scoped_resolver[n_scoped_resolver++] = resolver; 280 } else if (attribute_type == CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER) { 281 config->service_specific_resolver[n_service_specific_resolver++] = resolver; 282 } 283 284 break; 285 } 286 287 default : 288 break; 289 } 290 291 attribute = (dns_attribute_t *)((void *)attribute + attribute_length); 292 n_attribute -= attribute_length; 293 } 294 295 if (n_resolver != config->n_resolver) { 296 goto error; 297 } 298 299 if (n_scoped_resolver != config->n_scoped_resolver) { 300 goto error; 301 } 302 303 if (n_service_specific_resolver != config->n_service_specific_resolver) { 304 goto error; 305 } 306 307 return config; 308 309 error : 310 311 return NULL; 312} 313 314 315const char * 316dns_configuration_notify_key() 317{ 318 const char *key; 319 320#if !TARGET_IPHONE_SIMULATOR 321 key = "com.apple.system.SystemConfiguration.dns_configuration"; 322#else // !TARGET_IPHONE_SIMULATOR 323 key = "com.apple.iOS_Simulator.SystemConfiguration.dns_configuration"; 324#endif // !TARGET_IPHONE_SIMULATOR 325 return key; 326} 327 328 329#pragma mark - 330#pragma mark DNS configuration [dnsinfo] client support 331 332 333// Note: protected by __dns_configuration_queue() 334static int dnsinfo_active = 0; 335static libSC_info_client_t *dnsinfo_client = NULL; 336 337 338static dispatch_queue_t 339__dns_configuration_queue() 340{ 341 static dispatch_once_t once; 342 static dispatch_queue_t q; 343 344 dispatch_once(&once, ^{ 345 q = dispatch_queue_create(DNSINFO_SERVICE_NAME, NULL); 346 }); 347 348 return q; 349} 350 351 352dns_config_t * 353dns_configuration_copy() 354{ 355 uint8_t *buf = NULL; 356 dns_config_t *config = NULL; 357 static const char *proc_name = NULL; 358 xpc_object_t reqdict; 359 xpc_object_t reply; 360 361 dispatch_sync(__dns_configuration_queue(), ^{ 362 if ((dnsinfo_active++ == 0) || (dnsinfo_client == NULL)) { 363 static dispatch_once_t once; 364 static const char *service_name = DNSINFO_SERVICE_NAME; 365 366 dispatch_once(&once, ^{ 367 const char *name; 368 369 // get [XPC] service name 370 name = getenv(service_name); 371 if ((name != NULL) && (issetugid() == 0)) { 372 service_name = strdup(name); 373 } 374 375 // get process name 376 proc_name = getprogname(); 377 }); 378 379 dnsinfo_client = 380 libSC_info_client_create(__dns_configuration_queue(), // dispatch queue 381 service_name, // XPC service name 382 "DNS configuration"); // service description 383 if (dnsinfo_client == NULL) { 384 --dnsinfo_active; 385 } 386 } 387 }); 388 389 if ((dnsinfo_client == NULL) || !dnsinfo_client->active) { 390 // if DNS configuration server not available 391 return NULL; 392 } 393 394 // create message 395 reqdict = xpc_dictionary_create(NULL, NULL, 0); 396 397 // set process name 398 if (proc_name != NULL) { 399 xpc_dictionary_set_string(reqdict, DNSINFO_PROC_NAME, proc_name); 400 } 401 402 // set request 403 xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_COPY); 404 405 // send request to the DNS configuration server 406 reply = libSC_send_message_with_reply_sync(dnsinfo_client, reqdict); 407 xpc_release(reqdict); 408 409 if (reply != NULL) { 410 const void *dataRef; 411 size_t dataLen = 0; 412 413 dataRef = xpc_dictionary_get_data(reply, DNSINFO_CONFIGURATION, &dataLen); 414 if ((dataRef != NULL) && 415 ((dataLen >= sizeof(_dns_config_buf_t)) && (dataLen <= DNS_CONFIG_BUF_MAX))) { 416 _dns_config_buf_t *config = (_dns_config_buf_t *)(void *)dataRef; 417 uint32_t n_padding = ntohl(config->n_padding); 418 419 if (n_padding <= (DNS_CONFIG_BUF_MAX - dataLen)) { 420 uint32_t len; 421 422 len = dataLen + n_padding; 423 buf = malloc(len); 424 bcopy((void *)dataRef, buf, dataLen); 425 bzero(&buf[dataLen], n_padding); 426 } 427 } 428 429 xpc_release(reply); 430 } 431 432 if (buf != NULL) { 433 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */ 434 config = expand_config((_dns_config_buf_t *)(void *)buf); 435 if (config == NULL) { 436 free(buf); 437 } 438 } 439 440 return config; 441} 442 443 444void 445dns_configuration_free(dns_config_t *config) 446{ 447 if (config == NULL) { 448 return; // ASSERT 449 } 450 451 dispatch_sync(__dns_configuration_queue(), ^{ 452 if (--dnsinfo_active == 0) { 453 // if last reference, drop connection 454 libSC_info_client_release(dnsinfo_client); 455 dnsinfo_client = NULL; 456 } 457 }); 458 459 free((void *)config); 460 return; 461} 462 463 464void 465_dns_configuration_ack(dns_config_t *config, const char *bundle_id) 466{ 467 xpc_object_t reqdict; 468 469 if (config == NULL) { 470 return; // ASSERT 471 } 472 473 if ((dnsinfo_client == NULL) || !dnsinfo_client->active) { 474 // if DNS configuration server not available 475 return; 476 } 477 478 dispatch_sync(__dns_configuration_queue(), ^{ 479 dnsinfo_active++; // keep connection active (for the life of the process) 480 }); 481 482 // create message 483 reqdict = xpc_dictionary_create(NULL, NULL, 0); 484 485 // set request 486 xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_ACKNOWLEDGE); 487 488 // set generation 489 xpc_dictionary_set_uint64(reqdict, DNSINFO_GENERATION, config->generation); 490 491 // send acknowledgement to the DNS configuration server 492 xpc_connection_send_message(dnsinfo_client->connection, reqdict); 493 494 xpc_release(reqdict); 495 return; 496} 497 498#ifdef MAIN 499 500int 501main(int argc, char **argv) 502{ 503 dns_config_t *config; 504 505 config = dns_configuration_copy(); 506 if (config != NULL) { 507 dns_configuration_free(config); 508 } 509 510 exit(0); 511} 512 513#endif 514