1/* 2 * Copyright (c) 1999, 2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights 7 * Reserved. This file contains Original Code and/or Modifications of 8 * Original Code as defined in and that are subject to the Apple Public 9 * Source License Version 1.1 (the "License"). You may not use this file 10 * except in compliance with the License. Please obtain a copy of the 11 * License at http://www.apple.com/publicsource and read it before using 12 * this file. 13 * 14 * The Original Code and all software distributed under the License are 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the 19 * License for the specific language governing rights and limitations 20 * under the License. 21 * 22 * @APPLE_LICENSE_HEADER_END@ 23 */ 24 25#include <dns_sd.h> 26#include <errno.h> 27 28#include <arpa/nameser_compat.h> 29#include <nameser.h> 30 31#include "si_module.h" 32 33extern int h_errno; 34 35// Storage for the global struct __res_9_state. 36// The BIND9 libresolv.dylib shares the same storage for this structure as the 37// legacy BIND8 libsystem_info.dylib. This implementation does not require the 38// _res structure but libresolv.dylib does and many 3rd-party applications 39// access this global symbol directly so we preserve it here. 40#ifdef __LP64__ 41#define RES_9_STATE_SIZE 552 42#else 43#define RES_9_STATE_SIZE 512 44#endif 45char _res[RES_9_STATE_SIZE] = {0}; 46 47int 48res_init(void) 49{ 50 // For compatibility only. 51 return 0; 52} 53 54// Perform a DNS query. Returned DNS response is placed in the answer buffer. 55// A preliminary check of the answer is performed and success is returned only 56// if no error is indicated in the answer and the answer count is nonzero. 57// Returns the size of the response on success, or -1 with h_errno set. 58static int 59_mdns_query(int call, const char *name, int class, int type, u_char *answer, int anslen) 60{ 61 int res = -1; 62 si_item_t *item; 63 uint32_t err; 64 65 si_mod_t *dns = si_module_with_name("mdns"); 66 if (dns == NULL) { 67 h_errno = NO_RECOVERY; 68 return -1; 69 } 70 71 item = dns->vtable->sim_item_call(dns, call, name, NULL, NULL, class, type, &err); 72 73 if (item != NULL) { 74 si_dnspacket_t *p; 75 76 p = (si_dnspacket_t *)((uintptr_t)item + sizeof(si_item_t)); 77 78 res = p->dns_packet_len; 79 80 // Truncate to destination buffer size. 81 memcpy(answer, p->dns_packet, MIN(res, anslen)); 82 83 si_item_release(item); 84 } else { 85 h_errno = HOST_NOT_FOUND; 86 res = -1; 87 } 88 89 if (MIN(res, anslen) >= sizeof(HEADER)) { 90 HEADER *hp = (HEADER *)answer; 91 switch (hp->rcode) { 92 case NXDOMAIN: 93 h_errno = HOST_NOT_FOUND; 94 res = -1; 95 break; 96 case SERVFAIL: 97 h_errno = TRY_AGAIN; 98 res = -1; 99 break; 100 case NOERROR: 101 if (ntohs(hp->ancount) == 0) { 102 h_errno = NO_DATA; 103 res = -1; 104 } 105 break; 106 case FORMERR: 107 case NOTIMP: 108 case REFUSED: 109 default: 110 h_errno = NO_RECOVERY; 111 res = -1; 112 break; 113 } 114 } 115 116 si_module_release(dns); 117 return res; 118} 119 120int 121res_query(const char *name, int class, int type, u_char *answer, int anslen) 122{ 123 return _mdns_query(SI_CALL_DNS_QUERY, name, class, type, answer, anslen); 124} 125 126int 127res_search(const char *name, int class, int type, u_char *answer, int anslen) 128{ 129 return _mdns_query(SI_CALL_DNS_SEARCH, name, class, type, answer, anslen); 130} 131