/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.0 (the 'License'). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dns.h" #include "dns_util.h" #include "dns_private.h" #include "res_private.h" #define DNS_RESOLVER_DIR "/etc/resolver" #define DNS_PRIVATE_HANDLE_TYPE_SUPER 0 #define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1 #define DNS_DEFAULT_RECEIVE_SIZE 8192 #define SDNS_DEFAULT_STAT_LATENCY 10 #define DNS_FLAGS_QR_MASK 0x8000 #define DNS_FLAGS_QR_QUERY 0x0000 #define DNS_FLAGS_OPCODE_MASK 0x7800 #define DNS_FLAGS_RCODE_MASK 0x000f #define DNS_FLAGS_AA 0x0400 #define DNS_FLAGS_TC 0x0200 #define DNS_FLAGS_RD 0x0100 #define DNS_FLAGS_RA 0x0080 #define DNS_SOCK_UDP 0 #define DNS_SOCK_TCP_UNCONNECTED 1 #define DNS_SOCK_TCP_CONNECTED 2 #define INET_NTOP_AF_INET_OFFSET 4 #define INET_NTOP_AF_INET6_OFFSET 8 extern void res_client_close(res_state res); extern res_state res_client_open(char *path); extern int __res_nquery(res_state statp, const char *name, int class, int type, u_char *answer, int anslen); static pthread_mutex_t _dnsPrintLock = PTHREAD_MUTEX_INITIALIZER; static void _dns_print_lock(void) { pthread_mutex_lock(&_dnsPrintLock); } static void _dns_print_unlock(void) { pthread_mutex_unlock(&_dnsPrintLock); } static uint8_t _dns_parse_uint8(char **p) { uint8_t v; v = (uint8_t)**p; *p += 1; return v; } static uint16_t _dns_parse_uint16(char **p) { uint16_t *x, v; x = (uint16_t *)*p; v = ntohs(*x); *p += 2; return v; } static uint32_t _dns_parse_uint32(char **p) { uint32_t *x, v; x = (uint32_t *)*p; v = ntohl(*x); *p += 4; return v; } static uint8_t _dns_cname_length(char *s) { uint8_t l; if (s == NULL) return 1; l = strlen(s); while ((s[l - 1] == '.') && (l > 1)) l--; return l; } static void _dns_insert_cname(char *s, char *p) { int i; uint8_t len, dlen; if (s == NULL) { *p = 0; return; } if (!strcmp(s, ".")) { p[0] = 1; p[1] = '.'; p[2] = 0; return; } len = _dns_cname_length(s); p[0] = '.'; memmove(p + 1, s, len); p[len + 1] = '.'; dlen = 0; for (i = len + 1; i >= 0; i--) { if (p[i] == '.') { p[i] = dlen; dlen = 0; } else dlen++; } } static char * _dns_parse_string(const char *p, char **x, int32_t *remaining) { char *str; uint8_t len; if (*remaining < 1) return NULL; *remaining -= 1; len = (uint8_t)**x; *x += 1; if (*remaining < len) return NULL; *remaining -= len; str = malloc(len + 1); memmove(str, *x, len); str[len] = '\0'; *x += len; return str; } static char * _dns_parse_domain_name(const char *p, char **x, int32_t *remaining) { uint8_t *v8; uint16_t *v16, skip; uint16_t i, j, dlen, len; int more, compressed; char *name, *start, *z; if (*remaining < 1) return NULL; z = *x + *remaining; start = *x; compressed = 0; more = 1; name = malloc(1); name[0] = '\0'; len = 1; j = 0; skip = 0; while (more == 1) { if ((*x + 1) > z) { free(name); return NULL; } v8 = (uint8_t *)*x; dlen = *v8; if ((dlen & 0xc0) == 0xc0) { if ((*x + 2) > z) { free(name); return NULL; } v16 = (uint16_t *)*x; if ((p + (ntohs(*v16) & 0x3fff)) > z) { free(name); return NULL; } *x = (char *)p + (ntohs(*v16) & 0x3fff); if (compressed == 0) skip += 2; compressed = 1; continue; } if ((*x + 1) > z) { free(name); return NULL; } *x += 1; if (dlen > 0) { len += dlen; name = realloc(name, len); } if ((*x + dlen) > z) { free(name); return NULL; } for (i = 0; i < dlen; i++) { name[j++] = **x; *x += 1; } name[j] = '\0'; if (compressed == 0) skip += (dlen + 1); if (dlen == 0) more = 0; else { if ((*x + 1) > z) { free(name); return NULL; } v8 = (uint8_t *)*x; if (*v8 != 0) { len += 1; name = realloc(name, len); name[j++] = '.'; name[j] = '\0'; } } } if ((start + skip) > z) { free(name); return NULL; } *x = start + skip; *remaining -= skip; return name; } dns_resource_record_t * _dns_parse_resource_record_internal(const char *p, char **x, int32_t *remaining) { uint32_t size, bx, mi; uint16_t rdlen; uint8_t byte, i; dns_resource_record_t *r; char *eor; if (*remaining < 1) return NULL; r = (dns_resource_record_t *)calloc(1, sizeof(dns_resource_record_t)); r->name = _dns_parse_domain_name(p, x, remaining); if (r->name == NULL) { free(r); return NULL; } if (*remaining < 10) { free(r); return NULL; } r->dnstype = _dns_parse_uint16(x); r->dnsclass = _dns_parse_uint16(x); r->ttl = _dns_parse_uint32(x); rdlen = _dns_parse_uint16(x); *remaining -= 10; eor = *x; r->data.A = NULL; switch (r->dnstype) { case ns_t_a: if (*remaining < 4) { free(r); return NULL; } *remaining -= 4; size = sizeof(dns_address_record_t); r->data.A = (dns_address_record_t *)calloc(1, size); r->data.A->addr.s_addr = htonl(_dns_parse_uint32(x)); break; case ns_t_aaaa: if (*remaining < 16) { free(r); return NULL; } *remaining -= 16; size = sizeof(dns_in6_address_record_t); r->data.AAAA = (dns_in6_address_record_t *)calloc(1, size); r->data.AAAA->addr.__u6_addr.__u6_addr32[0] = htonl(_dns_parse_uint32(x)); r->data.AAAA->addr.__u6_addr.__u6_addr32[1] = htonl(_dns_parse_uint32(x)); r->data.AAAA->addr.__u6_addr.__u6_addr32[2] = htonl(_dns_parse_uint32(x)); r->data.AAAA->addr.__u6_addr.__u6_addr32[3] = htonl(_dns_parse_uint32(x)); break; case ns_t_ns: case ns_t_md: case ns_t_mf: case ns_t_cname: case ns_t_mb: case ns_t_mg: case ns_t_mr: case ns_t_ptr: size = sizeof(dns_domain_name_record_t); r->data.CNAME = (dns_domain_name_record_t *)calloc(1,size); r->data.CNAME->name = _dns_parse_domain_name(p, x, remaining); if (r->data.CNAME->name == NULL) { free(r->data.CNAME); free(r); return NULL; } break; case ns_t_soa: size = sizeof(dns_SOA_record_t); r->data.SOA = (dns_SOA_record_t *)calloc(1, size); r->data.SOA->mname = _dns_parse_domain_name(p, x, remaining); if (r->data.SOA->mname == NULL) { free(r->data.SOA); free(r); return NULL; } r->data.SOA->rname = _dns_parse_domain_name(p, x, remaining); if (r->data.SOA->rname == NULL) { free(r->data.SOA->mname); free(r->data.SOA); free(r); return NULL; } if (*remaining < 20) { free(r->data.SOA->mname); free(r->data.SOA->rname); free(r->data.SOA); free(r); return NULL; } *remaining -= 20; r->data.SOA->serial = _dns_parse_uint32(x); r->data.SOA->refresh = _dns_parse_uint32(x); r->data.SOA->retry = _dns_parse_uint32(x); r->data.SOA->expire = _dns_parse_uint32(x); r->data.SOA->minimum = _dns_parse_uint32(x); break; case ns_t_wks: if (*remaining < 5) { free(r); return NULL; } *remaining -= rdlen; size = sizeof(dns_WKS_record_t); r->data.WKS = (dns_WKS_record_t *)calloc(1, size); r->data.WKS->addr.s_addr = htonl(_dns_parse_uint32(x)); r->data.WKS->protocol = _dns_parse_uint8(x); size = rdlen - 5; r->data.WKS->maplength = size * 8; r->data.WKS->map = NULL; if (size == 0) break; r->data.WKS->map = (uint8_t *)calloc(1, r->data.WKS->maplength); mi = 0; for (bx = 0; bx < size; bx++) { byte = _dns_parse_uint8(x); for (i = 128; i >= 1; i = i/2) { if (byte & i) r->data.WKS->map[mi] = 0xff; else r->data.WKS->map[mi] = 0; mi++; } } break; case ns_t_hinfo: size = sizeof(dns_HINFO_record_t); r->data.HINFO = (dns_HINFO_record_t *)calloc(1, size); r->data.HINFO->cpu = _dns_parse_string(p, x, remaining); if (r->data.HINFO->cpu == NULL) { free(r->data.HINFO); free(r); return NULL; } r->data.HINFO->os = _dns_parse_string(p, x, remaining); if (r->data.HINFO->os == NULL) { free(r->data.HINFO->cpu); free(r->data.HINFO); free(r); return NULL; } break; case ns_t_minfo: size = sizeof(dns_MINFO_record_t); r->data.MINFO = (dns_MINFO_record_t *)calloc(1, size); r->data.MINFO->rmailbx = _dns_parse_domain_name(p, x, remaining); if (r->data.MINFO->rmailbx == NULL) { free(r->data.MINFO); free(r); return NULL; } r->data.MINFO->emailbx = _dns_parse_domain_name(p, x, remaining); if (r->data.MINFO->emailbx == NULL) { free(r->data.MINFO->rmailbx); free(r->data.MINFO); free(r); return NULL; } break; case ns_t_mx: if (*remaining < 2) { free(r); return NULL; } *remaining -= 2; size = sizeof(dns_MX_record_t); r->data.MX = (dns_MX_record_t *)calloc(1, size); r->data.MX->preference = _dns_parse_uint16(x); r->data.MX->name = _dns_parse_domain_name(p, x, remaining); if (r->data.MX->name == NULL) { free(r->data.MX); free(r); return NULL; } break; case ns_t_txt: size = sizeof(dns_TXT_record_t); r->data.TXT = (dns_TXT_record_t *)malloc(size); r->data.TXT->string_count = 0; r->data.TXT->strings = NULL; while (*x < (eor + rdlen)) { if (r->data.TXT->string_count == 0) { r->data.TXT->strings = (char **)calloc(1, sizeof(char *)); } else { r->data.TXT->strings = (char **)realloc(r->data.TXT->strings, (r->data.TXT->string_count + 1) * sizeof(char *)); } r->data.TXT->strings[r->data.TXT->string_count] = _dns_parse_string(p, x, remaining); if (r->data.TXT->strings[r->data.TXT->string_count] == NULL) { free(r->data.TXT->strings); free(r->data.TXT); free(r); return NULL; } r->data.TXT->string_count++; } break; case ns_t_rp: size = sizeof(dns_RP_record_t); r->data.RP = (dns_RP_record_t *)calloc(1, size); r->data.RP->mailbox = _dns_parse_domain_name(p, x, remaining); if (r->data.RP->mailbox == NULL) { free(r->data.RP); free(r); return NULL; } r->data.RP->txtdname = _dns_parse_domain_name(p, x, remaining); if (r->data.RP->txtdname == NULL) { free(r->data.RP->mailbox); free(r->data.RP); free(r); return NULL; } break; case ns_t_afsdb: if (*remaining < 4) { free(r); return NULL; } *remaining -= 4; size = sizeof(dns_AFSDB_record_t); r->data.AFSDB = (dns_AFSDB_record_t *)calloc(1, size); r->data.AFSDB->subtype = _dns_parse_uint32(x); r->data.AFSDB->hostname = _dns_parse_domain_name(p, x, remaining); if (r->data.AFSDB->hostname == NULL) { free(r->data.AFSDB); free(r); return NULL; } break; case ns_t_x25: size = sizeof(dns_X25_record_t); r->data.X25 = (dns_X25_record_t *)calloc(1, size); r->data.X25->psdn_address = _dns_parse_string(p, x, remaining); if (r->data.X25->psdn_address == NULL) { free(r->data.X25); free(r); return NULL; } break; case ns_t_isdn: size = sizeof(dns_ISDN_record_t); r->data.ISDN = (dns_ISDN_record_t *)calloc(1, size); r->data.ISDN->isdn_address = _dns_parse_string(p, x, remaining); if (r->data.ISDN->isdn_address == NULL) { free(r->data.ISDN); free(r); return NULL; } if (*x < (eor + rdlen)) { r->data.ISDN->subaddress = _dns_parse_string(p, x, remaining); if (r->data.ISDN->subaddress == NULL) { free(r->data.ISDN->isdn_address); free(r->data.ISDN); free(r); return NULL; } } else { r->data.ISDN->subaddress = NULL; } break; case ns_t_rt: if (*remaining < 2) { free(r); return NULL; } *remaining -= 2; size = sizeof(dns_RT_record_t); r->data.RT = (dns_RT_record_t *)calloc(1, size); r->data.RT->preference = _dns_parse_uint16(x); r->data.RT->intermediate = _dns_parse_domain_name(p, x, remaining); if (r->data.RT->intermediate == NULL) { free(r->data.RT); free(r); return NULL; } break; case ns_t_loc: if (*remaining < 16) { free(r); return NULL; } *remaining -= 16; size = sizeof(dns_LOC_record_t); r->data.LOC = (dns_LOC_record_t *)calloc(1, size); r->data.LOC->version = _dns_parse_uint8(x); r->data.LOC->size = _dns_parse_uint8(x); r->data.LOC->horizontal_precision = _dns_parse_uint8(x); r->data.LOC->vertical_precision = _dns_parse_uint8(x); r->data.LOC->latitude = _dns_parse_uint32(x); r->data.LOC->longitude = _dns_parse_uint32(x); r->data.LOC->altitude = _dns_parse_uint32(x); break; case ns_t_srv: if (*remaining < 6) { free(r); return NULL; } *remaining -= 6; size = sizeof(dns_SRV_record_t); r->data.SRV = (dns_SRV_record_t *)calloc(1, size); r->data.SRV->priority = _dns_parse_uint16(x); r->data.SRV->weight = _dns_parse_uint16(x); r->data.SRV->port = _dns_parse_uint16(x); r->data.SRV->target = _dns_parse_domain_name(p, x, remaining); if (r->data.SRV->target == NULL) { free(r->data.SRV); free(r); return NULL; } break; case ns_t_null: default: if (*remaining < rdlen) { free(r); return NULL; } *remaining -= rdlen; size = sizeof(dns_raw_resource_record_t); r->data.DNSNULL = (dns_raw_resource_record_t *)calloc(1, size); r->data.DNSNULL->length = rdlen; r->data.DNSNULL->data = calloc(1, rdlen); memmove(r->data.DNSNULL->data, *x, rdlen); *x += rdlen; break; } *x = eor + rdlen; return r; } dns_resource_record_t * dns_parse_resource_record(const char *buf, uint32_t len) { char *x; int32_t remaining; remaining = len; x = (char *)buf; return _dns_parse_resource_record_internal(buf, &x, &remaining); } dns_question_t * _dns_parse_question_internal(const char *p, char **x, int32_t *remaining) { dns_question_t *q; if (x == NULL) return NULL; if (*x == NULL) return NULL; if (*remaining < 1) return NULL; q = (dns_question_t *)calloc(1, sizeof(dns_question_t)); q->name = _dns_parse_domain_name(p, x, remaining); if (q->name == NULL) { free(q); return NULL; } if (*remaining < 4) { free(q->name); free(q); return NULL; } *remaining = *remaining - 4; q->dnstype = _dns_parse_uint16(x); q->dnsclass = _dns_parse_uint16(x); return q; } dns_question_t * dns_parse_question(const char *buf, uint32_t len) { char *x; int32_t remaining; remaining = len; x = (char *)buf; return _dns_parse_question_internal(buf, &x, &remaining); } dns_reply_t * dns_parse_packet(const char *p, uint32_t len) { dns_reply_t *r; dns_header_t *h; char *x; uint32_t i, size; int32_t remaining; if (p == NULL) return NULL; if (len < NS_HFIXEDSZ) return NULL; x = (char *)p; r = (dns_reply_t *)calloc(1, sizeof(dns_reply_t)); r->header = (dns_header_t *)calloc(1, sizeof(dns_header_t)); h = r->header; h->xid = _dns_parse_uint16(&x); h->flags = _dns_parse_uint16(&x); h->qdcount = _dns_parse_uint16(&x); h->ancount = _dns_parse_uint16(&x); h->nscount = _dns_parse_uint16(&x); h->arcount = _dns_parse_uint16(&x); remaining = len - NS_HFIXEDSZ; size = sizeof(dns_question_t *); r->question = (dns_question_t **)calloc(h->qdcount, size); for (i = 0; i < h->qdcount; i++) { r->question[i] = _dns_parse_question_internal(p, &x, &remaining); if (r->question[i] ==NULL) { h->qdcount = 0; if (i > 0) h->qdcount = i - 1; h->ancount = 0; h->nscount = 0; h->arcount = 0; dns_free_reply(r); return NULL; } } size = sizeof(dns_resource_record_t *); r->answer = (dns_resource_record_t **)calloc(h->ancount, size); for (i = 0; i < h->ancount; i++) { r->answer[i] = _dns_parse_resource_record_internal(p, &x, &remaining); if (r->answer[i] == NULL) { h->ancount = 0; if (i > 0) h->ancount = i - 1; h->nscount = 0; h->arcount = 0; dns_free_reply(r); return NULL; } } r->authority = (dns_resource_record_t **)calloc(h->nscount, size); for (i = 0; i < h->nscount; i++) { r->authority[i] = _dns_parse_resource_record_internal(p, &x, &remaining); if (r->authority[i] == NULL) { h->nscount = 0; if (i > 0) h->nscount = i - 1; h->arcount = 0; dns_free_reply(r); return NULL; } } r->additional = (dns_resource_record_t **)calloc(h->arcount, size); for (i = 0; i < h->arcount; i++) { r->additional[i] = _dns_parse_resource_record_internal(p, &x, &remaining); if (r->additional[i] == NULL) { h->arcount = 0; if (i > 0) h->arcount = i - 1; dns_free_reply(r); return NULL; } } return r; } void dns_free_resource_record(dns_resource_record_t *r) { int i; free(r->name); switch (r->dnstype) { case ns_t_a: free(r->data.A); break; case ns_t_aaaa: free(r->data.AAAA); break; case ns_t_ns: case ns_t_md: case ns_t_mf: case ns_t_cname: case ns_t_mb: case ns_t_mg: case ns_t_mr: case ns_t_ptr: free(r->data.CNAME->name); free(r->data.CNAME); break; case ns_t_soa: free(r->data.SOA->mname); free(r->data.SOA->rname); free(r->data.SOA); break; case ns_t_wks: free(r->data.WKS->map); free(r->data.WKS); break; case ns_t_hinfo: free(r->data.HINFO->cpu); free(r->data.HINFO->os); free(r->data.HINFO); break; case ns_t_minfo: free(r->data.MINFO->rmailbx); free(r->data.MINFO->emailbx); free(r->data.MINFO); break; case ns_t_mx: free(r->data.MX->name); free(r->data.MX); break; case ns_t_txt: for (i=0; idata.TXT->string_count; i++) { free(r->data.TXT->strings[i]); } if (r->data.TXT->strings != NULL) free(r->data.TXT->strings); free(r->data.TXT); break; case ns_t_rp: free(r->data.RP->mailbox); free(r->data.RP->txtdname); free(r->data.RP); break; case ns_t_afsdb: free(r->data.AFSDB->hostname); free(r->data.AFSDB); break; case ns_t_x25: free(r->data.X25->psdn_address); free(r->data.X25); break; case ns_t_isdn: free(r->data.ISDN->isdn_address); if (r->data.ISDN->subaddress != NULL) free(r->data.ISDN->subaddress); free(r->data.ISDN); break; case ns_t_rt: free(r->data.RT->intermediate); free(r->data.RT); break; case ns_t_loc: free(r->data.LOC); break; case ns_t_srv: free(r->data.SRV->target); free(r->data.SRV); break; case ns_t_null: default: free(r->data.DNSNULL->data); free(r->data.DNSNULL); break; } free(r); } void dns_free_reply(dns_reply_t *r) { uint32_t i; if (r == NULL) return; if (r->header != NULL) { for (i = 0; i < r->header->qdcount; i++) { free(r->question[i]->name); free(r->question[i]); } for (i = 0; i < r->header->ancount; i++) dns_free_resource_record(r->answer[i]); for (i = 0; i < r->header->nscount; i++) dns_free_resource_record(r->authority[i]); for (i = 0; i < r->header->arcount; i++) dns_free_resource_record(r->additional[i]); free(r->header); } if (r->question != NULL) free(r->question); if (r->answer != NULL) free(r->answer); if (r->authority != NULL) free(r->authority); if (r->additional != NULL) free(r->additional); if (r->server != NULL) free(r->server); free(r); } static void _dns_append_question(dns_question_t *q, char **s, uint16_t *l) { uint16_t len, *p; char *x; if (q == NULL) return; len = *l + _dns_cname_length(q->name) + 2 + 4; *s = realloc(*s, len); _dns_insert_cname(q->name, (char *)*s + *l); *l = len; x = *s + (len - 4); p = (uint16_t *)x; *p = htons(q->dnstype); x += 2; p = (uint16_t *)x; *p = htons(q->dnsclass); } static void _dns_append_resource_record(dns_resource_record_t *r, char **s, uint16_t *l) { uint16_t clen, len, *p, extra, rdlen; uint32_t *p2; char *x; if (r == NULL) return; extra = 10; switch (r->dnstype) { case ns_t_a: extra += 4; break; case ns_t_ptr: extra += 2; clen = _dns_cname_length(r->data.PTR->name); extra += clen; break; default: break; } len = *l + _dns_cname_length(r->name) + 2 + extra; *s = realloc(*s, len); _dns_insert_cname(r->name, (char *)*s + *l); *l = len; x = *s + (len - extra); p = (uint16_t *)x; *p = htons(r->dnstype); x += 2; p = (uint16_t *)x; *p = htons(r->dnsclass); x += 2; p2 = (uint32_t *)x; *p2 = htonl(r->ttl); x += 4; switch (r->dnstype) { case ns_t_a: rdlen = 4; p = (uint16_t *)x; *p = htons(rdlen); x += 2; p2 = (uint32_t *)x; *p2 = htons(r->data.A->addr.s_addr); x += 4; return; case ns_t_ptr: clen = _dns_cname_length(r->data.PTR->name) + 2; p = (uint16_t *)x; *p = htons(clen); x += 2; _dns_insert_cname(r->data.PTR->name, x); x += clen; return; default: return; } } char * dns_build_reply(dns_reply_t *dnsr, uint16_t *rl) { uint16_t i, len; dns_header_t *h; char *s, *x; if (dnsr == NULL) return NULL; len = NS_HFIXEDSZ; s = malloc(len); x = s + len; memset(s, 0, len); *rl = len; h = (dns_header_t *)s; h->xid = htons(dnsr->header->xid); h->flags = htons(dnsr->header->flags); h->qdcount = htons(dnsr->header->qdcount); h->ancount = htons(dnsr->header->ancount); h->nscount = htons(dnsr->header->nscount); h->arcount = htons(dnsr->header->arcount); for (i = 0; i < dnsr->header->qdcount; i++) { _dns_append_question(dnsr->question[i], &s, rl); } for (i = 0; i < dnsr->header->ancount; i++) { _dns_append_resource_record(dnsr->answer[i], &s, rl); } for (i = 0; i < dnsr->header->nscount; i++) { _dns_append_resource_record(dnsr->authority[i], &s, rl); } for (i = 0; i < dnsr->header->arcount; i++) { _dns_append_resource_record(dnsr->additional[i], &s, rl); } return s; } void dns_free_question(dns_question_t *q) { if (q == NULL) return; if (q->name != NULL) free(q->name); free(q); } void dns_set_buffer_size(dns_handle_t d, uint32_t len) { dns_private_handle_t *dns; if (d == NULL) return; dns = (dns_private_handle_t *)d; if (dns->recvsize == len) return; if (dns->recvbuf != NULL) { free(dns->recvbuf); dns->recvbuf = NULL; } dns->recvsize = len; } uint32_t dns_get_buffer_size(dns_handle_t d) { dns_private_handle_t *dns; if (d == NULL) return 0; dns = (dns_private_handle_t *)d; return dns->recvsize; } dns_reply_t * dns_lookup(dns_handle_t d, const char *name, uint32_t class, uint32_t type) { dns_private_handle_t *dns; dns_reply_t *r; int status, mymem; char *buf; uint32_t len; struct sockaddr_storage *from; uint32_t fromlen; if (d == NULL) return NULL; if (name == NULL) return NULL; dns = (dns_private_handle_t *)d; mymem = 0; buf = dns->recvbuf; len = dns->recvsize; fromlen = sizeof(struct sockaddr_storage); if (buf == NULL) { if (len == 0) { len = DNS_DEFAULT_RECEIVE_SIZE; mymem = 1; } buf = malloc(len); if (buf == NULL) return NULL; if (mymem == 0) dns->recvbuf = buf; } from = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage)); status = dns_search(dns, name, class, type, buf, len, (struct sockaddr *)from, &fromlen); if (status <= 0) { if (mymem != 0) free(buf); free(from); return NULL; } r = dns_parse_packet(buf, len); if (mymem != 0) free(buf); if (r == NULL) free(from); else r->server = (struct sockaddr *)from; return r; } /* * DNS printing utilities */ static char * coord_ntoa(int32_t coord, uint32_t islat) { int32_t deg, min, sec, secfrac; static char buf[64]; char dir; coord = coord - 0x80000000; dir = 'N'; if ((islat == 1) && (coord < 0)) { dir = 'S'; coord = -coord; } if (islat == 0) { dir = 'E'; if (coord < 0) { dir = 'W'; coord = -coord; } } secfrac = coord % 1000; coord = coord / 1000; sec = coord % 60; coord = coord / 60; min = coord % 60; coord = coord / 60; deg = coord; sprintf(buf, "%d %.2d %.2d.%.3d %c", deg, min, sec, secfrac, dir); return buf; } static char * alt_ntoa(int32_t alt) { int32_t ref, m, frac, sign; static char buf[128]; ref = 100000 * 100; sign = 1; if (alt < ref) { alt = ref - alt; sign = -1; } else { alt = alt - ref; } frac = alt % 100; m = (alt / 100) * sign; sprintf(buf, "%d.%.2d", m, frac); return buf; } static unsigned int poweroften[10] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; static char * precsize_ntoa(uint8_t prec) { static char buf[19]; unsigned long val; int mantissa, exponent; mantissa = (int)((prec >> 4) & 0x0f) % 10; exponent = (int)((prec >> 0) & 0x0f) % 10; val = mantissa * poweroften[exponent]; sprintf(buf, "%ld.%.2ld", val/100, val%100); return buf; } const char * dns_type_string(uint16_t t) { switch (t) { case ns_t_a: return "A "; case ns_t_ns: return "NS "; case ns_t_md: return "MD "; case ns_t_mf: return "MF "; case ns_t_cname: return "CNAME"; case ns_t_soa: return "SOA "; case ns_t_mb: return "MB "; case ns_t_mg: return "MG "; case ns_t_mr: return "MR "; case ns_t_null: return "NULL "; case ns_t_wks: return "WKS "; case ns_t_ptr: return "PTR "; case ns_t_hinfo: return "HINFO"; case ns_t_minfo: return "MINFO"; case ns_t_mx: return "MX "; case ns_t_txt: return "TXT "; case ns_t_rp: return "PR "; case ns_t_afsdb: return "AFSDB"; case ns_t_x25: return "X25 "; case ns_t_isdn: return "ISDN "; case ns_t_rt: return "RT "; case ns_t_nsap: return "NSAP "; case ns_t_nsap_ptr: return "NSPTR"; case ns_t_sig: return "SIG "; case ns_t_key: return "KEY "; case ns_t_px: return "PX "; case ns_t_gpos: return "GPOS "; case ns_t_aaaa: return "AAAA "; case ns_t_loc: return "LOC "; case ns_t_nxt: return "NXT "; case ns_t_eid: return "EID "; case ns_t_nimloc: return "NIMLC"; case ns_t_srv: return "SRV "; case ns_t_atma: return "ATMA "; case ns_t_naptr: return "NAPTR"; case ns_t_kx: return "KX "; case ns_t_cert: return "CERT "; case ns_t_a6: return "A6 "; case ns_t_dname: return "DNAME"; case ns_t_sink: return "SINK "; case ns_t_opt: return "OPT "; case ns_t_tkey: return "TKEY "; case ns_t_tsig: return "TSIG "; case ns_t_ixfr: return "IXFR "; case ns_t_axfr: return "AXFR "; case ns_t_mailb: return "MAILB"; case ns_t_maila: return "MAILA"; case ns_t_any: return "ANY "; case ns_t_zxfr: return "ZXFR "; default: return "?????"; } return "?????"; } int32_t dns_type_number(const char *t, uint16_t *n) { if (t == NULL) return -1; if (!strcasecmp(t, "A")) { *n = ns_t_a; return 0; } if (!strcasecmp(t, "NS")) { *n = ns_t_ns; return 0; } if (!strcasecmp(t, "MD")) { *n = ns_t_md; return 0; } if (!strcasecmp(t, "MF")) { *n = ns_t_mf; return 0; } if (!strcasecmp(t, "CNAME")) { *n = ns_t_cname; return 0; } if (!strcasecmp(t, "SOA")) { *n = ns_t_soa; return 0; } if (!strcasecmp(t, "MB")) { *n = ns_t_mb; return 0; } if (!strcasecmp(t, "MG")) { *n = ns_t_mg; return 0; } if (!strcasecmp(t, "MR")) { *n = ns_t_mr; return 0; } if (!strcasecmp(t, "NULL")) { *n = ns_t_null; return 0; } if (!strcasecmp(t, "WKS")) { *n = ns_t_wks; return 0; } if (!strcasecmp(t, "PTR")) { *n = ns_t_ptr; return 0; } if (!strcasecmp(t, "HINFO")) { *n = ns_t_hinfo; return 0; } if (!strcasecmp(t, "MINFO")) { *n = ns_t_minfo; return 0; } if (!strcasecmp(t, "TXT")) { *n = ns_t_txt; return 0; } if (!strcasecmp(t, "RP")) { *n = ns_t_rp; return 0; } if (!strcasecmp(t, "AFSDB")) { *n = ns_t_afsdb; return 0; } if (!strcasecmp(t, "X25")) { *n = ns_t_x25; return 0; } if (!strcasecmp(t, "ISDN")) { *n = ns_t_isdn; return 0; } if (!strcasecmp(t, "RT")) { *n = ns_t_rt; return 0; } if (!strcasecmp(t, "NSAP")) { *n = ns_t_nsap; return 0; } if (!strcasecmp(t, "NSPTR")) { *n = ns_t_nsap_ptr; return 0; } if (!strcasecmp(t, "NSAP_PTR")){ *n = ns_t_nsap_ptr; return 0; } if (!strcasecmp(t, "SIG")) { *n = ns_t_sig; return 0; } if (!strcasecmp(t, "KEY")) { *n = ns_t_key; return 0; } if (!strcasecmp(t, "PX")) { *n = ns_t_px; return 0; } if (!strcasecmp(t, "GPOS")) { *n = ns_t_gpos; return 0; } if (!strcasecmp(t, "AAAA")) { *n = ns_t_aaaa; return 0; } if (!strcasecmp(t, "LOC")) { *n = ns_t_loc; return 0; } if (!strcasecmp(t, "NXT")) { *n = ns_t_nxt; return 0; } if (!strcasecmp(t, "EID")) { *n = ns_t_eid; return 0; } if (!strcasecmp(t, "NIMLOC")) { *n = ns_t_nimloc; return 0; } if (!strcasecmp(t, "SRV")) { *n = ns_t_srv; return 0; } if (!strcasecmp(t, "ATMA")) { *n = ns_t_atma; return 0; } if (!strcasecmp(t, "NAPTR")) { *n = ns_t_naptr; return 0; } if (!strcasecmp(t, "KX")) { *n = ns_t_kx; return 0; } if (!strcasecmp(t, "CERT")) { *n = ns_t_cert; return 0; } if (!strcasecmp(t, "A6")) { *n = ns_t_a6; return 0; } if (!strcasecmp(t, "DNAME")) { *n = ns_t_dname; return 0; } if (!strcasecmp(t, "SINK")) { *n = ns_t_sink; return 0; } if (!strcasecmp(t, "OPT")) { *n = ns_t_opt; return 0; } if (!strcasecmp(t, "TKEY")) { *n = ns_t_tkey; return 0; } if (!strcasecmp(t, "TSIG")) { *n = ns_t_tsig; return 0; } if (!strcasecmp(t, "IXFR")) { *n = ns_t_ixfr; return 0; } if (!strcasecmp(t, "AXFR")) { *n = ns_t_axfr; return 0; } if (!strcasecmp(t, "MAILB")) { *n = ns_t_mailb; return 0; } if (!strcasecmp(t, "MAILA")) { *n = ns_t_maila; return 0; } if (!strcasecmp(t, "ANY")) { *n = ns_t_any; return 0; } if (!strcasecmp(t, "ZXFR")) { *n = ns_t_zxfr; return 0; } return -1; } const char * dns_class_string(uint16_t c) { switch (c) { case ns_c_in: return "IN"; case ns_c_2: return "CS"; case ns_c_chaos: return "CH"; case ns_c_hs: return "HS"; case ns_c_none: return "NONE"; case ns_c_any: return "ANY"; default: return "??"; } return "??"; } int32_t dns_class_number(const char *c, uint16_t *n) { if (c == NULL) return -1; if (!strcasecmp(c, "IN")) { *n = ns_c_in; return 0; } if (!strcasecmp(c, "CS")) { *n = ns_c_2; return 0; } if (!strcasecmp(c, "CH")) { *n = ns_c_chaos; return 0; } if (!strcasecmp(c, "HS")) { *n = ns_c_hs; return 0; } if (!strcasecmp(c, "NONE")) { *n = ns_c_none; return 0; } if (!strcasecmp(c, "ANY")) { *n = ns_c_any; return 0; } return -1; } static void _dns_print_question_lock(const dns_question_t *q, FILE *f, int lockit) { if (lockit != 0) _dns_print_lock(); fprintf(f, "%s %s %s\n", q->name, dns_class_string(q->dnsclass), dns_type_string(q->dnstype)); if (lockit != 0) _dns_print_unlock(); } void dns_print_question(const dns_question_t *q, FILE *f) { _dns_print_question_lock(q, f, 1); } static void _dns_print_resource_record_lock(const dns_resource_record_t *r, FILE *f, int lockit) { struct protoent *p; struct servent *s; uint32_t i, len; uint8_t x; struct sockaddr_in6 s6; char pbuf[64]; if (lockit != 0) _dns_print_lock(); fprintf(f, "%s %s %s ", r->name, dns_class_string(r->dnsclass), dns_type_string(r->dnstype)); fprintf(f, "%u", r->ttl); switch (r->dnstype) { case ns_t_a: fprintf(f, " %s", inet_ntoa(r->data.A->addr)); break; case ns_t_aaaa: memset(&s6, 0, sizeof(struct sockaddr_in6)); s6.sin6_len = sizeof(struct sockaddr_in6); s6.sin6_family = AF_INET6; s6.sin6_addr = r->data.AAAA->addr; fprintf(f, " %s", inet_ntop(AF_INET6, (char *)(&s6) + INET_NTOP_AF_INET6_OFFSET, pbuf, 64)); break; case ns_t_md: case ns_t_mf: case ns_t_cname: case ns_t_mb: case ns_t_mg: case ns_t_mr: case ns_t_ptr: case ns_t_ns: fprintf(f, " %s", r->data.CNAME->name); break; case ns_t_soa: fprintf(f, " %s %s %u %u %u %u %u", r->data.SOA->mname, r->data.SOA->rname, r->data.SOA->serial, r->data.SOA->refresh, r->data.SOA->retry, r->data.SOA->expire, r->data.SOA->minimum); break; case ns_t_wks: fprintf(f, " %s", inet_ntoa(r->data.WKS->addr)); p = getprotobynumber(r->data.WKS->protocol); if (p != NULL) { fprintf(f, " %s", p->p_name); for (i = 0; i < r->data.WKS->maplength; i++) { if (r->data.WKS->map[i]) { s = getservbyport(i, p->p_name); if (s == NULL) fprintf(f, " %u", i); else fprintf(f, " %s", s->s_name); } } } else fprintf(f, " UNKNOWN PROTOCOL %u", r->data.WKS->protocol); break; case ns_t_hinfo: fprintf(f, " %s %s", r->data.HINFO->cpu, r->data.HINFO->os); break; case ns_t_minfo: fprintf(f, " %s %s", r->data.MINFO->rmailbx, r->data.MINFO->emailbx); break; case ns_t_mx: fprintf(f, " %u %s", r->data.MX->preference, r->data.MX->name); break; case ns_t_txt: for (i = 0; i < r->data.TXT->string_count; i++) { fprintf(f, " \"%s\"", r->data.TXT->strings[i]); } break; case ns_t_rp: fprintf(f, " %s %s", r->data.RP->mailbox, r->data.RP->txtdname); break; case ns_t_afsdb: fprintf(f, " %u %s", r->data.AFSDB->subtype, r->data.AFSDB->hostname); break; case ns_t_x25: fprintf(f, " %s", r->data.X25->psdn_address); break; case ns_t_isdn: fprintf(f, " %s", r->data.ISDN->isdn_address); if (r->data.ISDN->subaddress != NULL) fprintf(f, " %s", r->data.ISDN->subaddress); break; case ns_t_rt: fprintf(f, " %hu %s", r->data.RT->preference, r->data.RT->intermediate); break; case ns_t_loc: fprintf(f, " %s", coord_ntoa(r->data.LOC->latitude, 1)); fprintf(f, " %s", coord_ntoa(r->data.LOC->longitude, 0)); fprintf(f, " %sm", alt_ntoa(r->data.LOC->altitude)); fprintf(f, " %sm", precsize_ntoa(r->data.LOC->size)); fprintf(f, " %sm", precsize_ntoa(r->data.LOC->horizontal_precision)); fprintf(f, " %sm", precsize_ntoa(r->data.LOC->vertical_precision)); break; case ns_t_srv: fprintf(f, " %hu %hu %hu %s", r->data.SRV->priority, r->data.SRV->weight, r->data.SRV->port, r->data.SRV->target); break; case ns_t_null: default: len = r->data.DNSNULL->length; fprintf(f, " %hu ", len); for (i = 0; i < len; i++) { x = r->data.DNSNULL->data[i]; fprintf(f, "%x", x); } fprintf(f, " ("); len = r->data.DNSNULL->length; for (i = 0; i < len; i++) { x = r->data.DNSNULL->data[i]; if (isascii(x)) fprintf(f, "%c", x); else fprintf(f, " "); } fprintf(f, ")\n"); } fprintf(f, "\n"); if (lockit != 0) _dns_print_unlock(); } void dns_print_resource_record(const dns_resource_record_t *r, FILE *f) { _dns_print_resource_record_lock(r, f, 1); } void dns_print_reply(const dns_reply_t *r, FILE *f, uint16_t mask) { uint16_t i; dns_header_t *h; char scratch[1024]; uint32_t offset, iface; _dns_print_lock(); if (r == NULL) { fprintf(f, "-nil-\n"); _dns_print_unlock(); return; } if (r->status != DNS_STATUS_OK) { if (r->status == DNS_STATUS_TIMEOUT) fprintf(f, "Timeout\n"); else if (r->status == DNS_STATUS_SEND_FAILED) fprintf(f, "Send failed\n"); else if (r->status == DNS_STATUS_RECEIVE_FAILED) fprintf(f, "Receive failed\n"); else fprintf(f, "status %u\n", r->status); _dns_print_unlock(); return; } h = r->header; if (mask & DNS_PRINT_XID) { fprintf(f, "Xid: %u\n", h->xid); } if (mask & DNS_PRINT_QR) { if ((h->flags & DNS_FLAGS_QR_MASK) == DNS_FLAGS_QR_QUERY) fprintf(f, "QR: Query\n"); else fprintf(f, "QR: Reply\n"); } if (mask & DNS_PRINT_SERVER) { if (r->server == NULL) { fprintf(f, "Server: -nil-\n"); } else { offset = INET_NTOP_AF_INET_OFFSET; if (r->server->sa_family == AF_INET6) offset = INET_NTOP_AF_INET6_OFFSET; fprintf(f, "Server: %s", inet_ntop(r->server->sa_family, (char *)(r->server) + offset, scratch, 1024)); if (r->server->sa_family == AF_INET) { memcpy(&iface, (((struct sockaddr_in *)(r->server))->sin_zero), 4); if (iface > 0) fprintf(f, "%%%s", if_indextoname(iface, scratch)); } else if (r->server->sa_family == AF_INET6) { iface = ((struct sockaddr_in6 *)(r->server))->sin6_scope_id; if (iface > 0) fprintf(f, "%%%s", if_indextoname(iface, scratch)); } fprintf(f, "\n"); } } if (mask & DNS_PRINT_OPCODE) { fprintf(f, "Opcode: "); switch (h->flags & DNS_FLAGS_OPCODE_MASK) { case ns_o_query: fprintf(f, "Standard\n"); break; case ns_o_iquery: fprintf(f, "Inverse\n"); break; case ns_o_status: fprintf(f, "Status\n"); break; case ns_o_notify: fprintf(f, "Notify\n"); break; case ns_o_update: fprintf(f, "Update\n"); break; default: fprintf(f, "Reserved (%hu)\n", (h->flags & DNS_FLAGS_OPCODE_MASK) >> 11); } } if (mask & DNS_PRINT_AA) { if (h->flags & DNS_FLAGS_AA) fprintf(f, "AA: Authoritative\n"); else fprintf(f, "AA: Non-Authoritative\n"); } if (mask & DNS_PRINT_TC) { if (h->flags & DNS_FLAGS_TC) fprintf(f, "TC: Truncated\n"); else fprintf(f, "TC: Non-Truncated\n"); } if (mask & DNS_PRINT_RD) { if (h->flags & DNS_FLAGS_RD) fprintf(f, "RD: Recursion desired\n"); else fprintf(f, "RD: No recursion desired\n"); } if (mask & DNS_PRINT_RA) { if (h->flags & DNS_FLAGS_RA) fprintf(f, "RA: Recursion available\n"); else fprintf(f, "RA: No recursion available \n"); } if (mask & DNS_PRINT_RCODE) { fprintf(f, "Rcode: "); switch (h->flags & DNS_FLAGS_RCODE_MASK) { case ns_r_noerror: fprintf(f, "No error\n"); break; case ns_r_formerr: fprintf(f, "Format error \n"); break; case ns_r_servfail: fprintf(f, "Server failure\n"); break; case ns_r_nxdomain: fprintf(f, "Name error \n"); break; case ns_r_notimpl: fprintf(f, "Not implemented\n"); break; case ns_r_refused: fprintf(f, "Refused\n"); break; case ns_r_yxdomain: fprintf(f, "Name exists\n"); break; case ns_r_yxrrset: fprintf(f, "RR Set exists\n"); break; case ns_r_nxrrset: fprintf(f, "RR Set does not exist\n"); break; case ns_r_notauth: fprintf(f, "Not authoritative\n"); break; case ns_r_notzone: fprintf(f, "Record zone does not match section zone\n"); break; case ns_r_badvers: fprintf(f, "Invalid EDNS version or TSIG signature\n"); break; case ns_r_badkey: fprintf(f, "Invalid key\n"); break; case ns_r_badtime: fprintf(f, "Invalid time\n"); break; default: fprintf(f, "Reserved (%hu)\n",h->flags & DNS_FLAGS_RCODE_MASK); } } if (mask & DNS_PRINT_QUESTION) { fprintf(f, "Question (%hu):\n", h->qdcount); for (i = 0; i < h->qdcount; i++) _dns_print_question_lock(r->question[i], f, 0); } if (mask & DNS_PRINT_ANSWER) { fprintf(f, "Answer (%hu):\n", h->ancount); for (i = 0; i < h->ancount; i++) _dns_print_resource_record_lock(r->answer[i], f, 0); } if (mask & DNS_PRINT_AUTHORITY) { fprintf(f, "Authority (%hu):\n", h->nscount); for (i = 0; i < h->nscount; i++) _dns_print_resource_record_lock(r->authority[i], f, 0); } if (mask & DNS_PRINT_ADDITIONAL) { fprintf(f, "Additional records (%hu):\n", h->arcount); for (i = 0; i < h->arcount; i++) _dns_print_resource_record_lock(r->additional[i], f, 0); } _dns_print_unlock(); } static void _pdns_print_handle(pdns_handle_t *pdns, FILE *f) { uint32_t i, offset; struct in_addr a; char scratch[1024]; struct sockaddr *sa; res_state r; if (pdns == NULL) { fprintf(f, "-nil-\n"); return; } if (pdns->name == NULL) fprintf(f, "Name: -nil-\n"); else fprintf(f, "Name: %s\n", pdns->name); r = pdns->res; if (r == NULL) return; if (r->defdname[0] == '\0') fprintf(f, "Domain: -no default name-\n"); else fprintf(f, "Domain: %s\n", r->defdname); fprintf(f, "Server%s:\n", (r->nscount == 1) ? "" : "s"); for (i = 0; i < r->nscount; i++) { sa = get_nsaddr(r, i); offset = INET_NTOP_AF_INET_OFFSET; if (sa->sa_family == AF_INET6) offset = INET_NTOP_AF_INET6_OFFSET; fprintf(f, " %u: %s", i, inet_ntop(sa->sa_family, (char *)sa + offset, scratch, 1024)); fprintf(f, "\n"); } if ((r->dnsrch[0] != NULL) && (r->dnsrch[0][0] != '\0')) { fprintf(f, "Search List:\n"); for (i = 0; r->dnsrch[i] != NULL; i++) fprintf(f, " %u: %s\n", i, r->dnsrch[i]); } if (r->sort_list[0].addr.s_addr != 0) { fprintf(f, "Sortlist:\n"); for (i = 0; (r->sort_list[i].addr.s_addr != 0); i++) { fprintf(f, " %u: ", i); a.s_addr = r->sort_list[i].addr.s_addr; fprintf(f, "%s/", inet_ntoa(a)); a.s_addr = r->sort_list[i].mask; fprintf(f, "%s\n", inet_ntoa(a)); } } } static void _sdns_print_handle(sdns_handle_t *sdns, FILE *f) { int i; if (sdns == NULL) { fprintf(f, "-nil-\n"); return; } fprintf(f, "DNS default (/etc/resolv.conf)\n"); _pdns_print_handle(sdns->dns_default, f); fprintf(f, "\n"); for (i = 0; i < sdns->client_count; i++) { fprintf(f, "DNS client %d\n", i); _pdns_print_handle(sdns->client[i], f); fprintf(f, "\n"); } fprintf(f, "resolver dir mod time = %u\n", sdns->modtime); fprintf(f, "resolver dir stat time = %u\n", sdns->stattime); fprintf(f, "resolver dir stat latency = %u\n", sdns->stat_latency); } void dns_print_handle(dns_handle_t d, FILE *f) { dns_private_handle_t *dns; _dns_print_lock(); if (d == NULL) { fprintf(f, "-nil-\n"); _dns_print_unlock(); return; } dns = (dns_private_handle_t *)d; if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER) { _sdns_print_handle(dns->sdns, f); } else { _pdns_print_handle(dns->pdns, f); } _dns_print_unlock(); } void dns_all_server_addrs(dns_handle_t d, struct sockaddr ***addrs, uint32_t *count) { int i, j, k, n, found; dns_private_handle_t *dns; pdns_handle_t *pdns; struct sockaddr *sa; struct sockaddr_storage **l; res_state r; *addrs = NULL; *count = 0; l = NULL; n = 0; if (d == NULL) return; dns = (dns_private_handle_t *)d; if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_SUPER) return; if (dns->sdns == NULL) return; /* Just to initialize / validate clients */ i = dns_search_list_count(d); for (i = 0; i <= dns->sdns->client_count; i++) { pdns = NULL; if (i == 0) pdns = dns->sdns->dns_default; else pdns = dns->sdns->client[i - 1]; if (pdns == NULL) continue; r = pdns->res; if (r == NULL) continue; for (j = 0; j < r->nscount; j++) { sa = get_nsaddr(r, j); found = 0; for (k = 0; (found == 0) && (k < n); k++) { if (memcmp(l[k], sa, sa->sa_len) == 0) found = 1; } if (found == 1) continue; if (n == 0) { l = (struct sockaddr_storage **)calloc(1, sizeof(struct sockaddr_storage *)); } else { l = (struct sockaddr_storage **)realloc(l, (n + 1) * sizeof(struct sockaddr_storage *)); } l[n] = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage)); memset(l[n], 0, sizeof(struct sockaddr_storage)); memcpy(l[n], sa, sa->sa_len); n++; } } *addrs = (struct sockaddr **)l; *count = n; }