KDCENTRY* krb_locate_kdc(rdpSettings* settings) { #ifdef WITH_RESOLV char *qname; int reslen, i; unsigned char response[4096]; char kdc_host[4096]; unsigned char* temp; KDCENTRY* head; KDCENTRY* kdcentry; KDCENTRY* srvans; ns_msg handle; ns_rr rr; head = kdcentry = NULL; if (get_krb_realm(settings)) return NULL; if (settings->kerberos_kdc) { srvans = xnew(KDCENTRY); srvans->kdchost = xstrdup(settings->kerberos_kdc); srvans->port = 88; return srvans; } qname = get_dns_queryname(settings->kerberos_realm, "_tcp."); if ((reslen = res_query(qname, ns_c_in, ns_t_srv, response, sizeof(response))) < 0) return NULL; ns_initparse(response, reslen, &handle); for (i = 0;i < ns_msg_count(handle, ns_s_an);i++) { ns_parserr(&handle, ns_s_an, i, &rr); srvans = xnew(KDCENTRY); temp = (unsigned char*)ns_rr_rdata(rr); GETUINT16(temp, &(srvans->priority)); GETUINT16(temp, &(srvans->weight)); GETUINT16(temp, &(srvans->port)); if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), temp, (char*)kdc_host, sizeof(kdc_host)) < 0) srvans->kdchost = xstrdup((const char*)temp); else srvans->kdchost = xstrdup(kdc_host); if (head == NULL || head->priority > srvans->priority) { srvans->next = head; head = srvans; } else { for (kdcentry = head;kdcentry->next != NULL && kdcentry->next->priority < srvans->priority;kdcentry = kdcentry->next); srvans->next = kdcentry->next; kdcentry->next = srvans; } } return head; #else return NULL; #endif }
static char *dns_dname_from_msg( ns_msg msg, const unsigned char *pos ) { int len; char *str, dname[NS_MAXDNAME] = "."; /* returns *compressed* length, ignore it */ dns_ns_name_uncompress( ns_msg_base(msg), ns_msg_end(msg), pos, dname, sizeof(dname) ); len = strlen( dname ); str = heap_alloc( len + 1 ); if (str) strcpy( str, dname ); return str; }
static void test_res_fake_srv_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; int port; char hostname[MAXDNAME]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_ldap._tcp.cwrap.org", ns_c_in, ns_t_srv, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SRV and have the priority, weight, * port and hostname as in the fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_srv); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); NS_GET16(port, rrdata); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, hostname, MAXDNAME); assert_int_not_equal(rv, -1); assert_int_equal(prio, 1); assert_int_equal(weight, 5); assert_int_equal(port, 389); assert_string_equal(hostname, "ldap.cwrap.org"); }
static JSBool parse_name(JSContext *cx, JSObject *robj, const ns_msg *hdl, const ns_rr *rr) { char name[MAXDNAME]; JSString *str; const unsigned char *base = ns_msg_base(*hdl), *end = ns_msg_end(*hdl); if (ns_name_uncompress(base, end, ns_rr_rdata(*rr), name, sizeof(name)) < 0) return JS_TRUE; str = JS_NewStringCopyZ(cx, name); if (!str) return JS_RetErrno(cx, ENOMEM); if (!JS_DefineProperty(cx, robj, "data", STRING_TO_JSVAL(str), NULL, NULL, JSPROP_ENUMERATE)) return JS_RetErrno(cx, ENOMEM); return JS_TRUE; }
int get_krb_realm(rdpSettings* settings) { #ifdef WITH_RESOLV char* s; char* queryname; int reslen; unsigned char response[2048]; char ns_realm[2048]; ns_msg handle; ns_rr rr; s = settings->hostname; if (settings->kerberos_realm) return 0; do { queryname = get_dns_queryname(s, NULL); if ((reslen = res_query(queryname, ns_c_in, ns_t_txt, response, sizeof(response)))) { ns_initparse(response, reslen, &handle); ns_parserr(&handle, ns_s_an, 0, &rr); if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), ns_rr_rdata(rr), (char*)ns_realm, sizeof(ns_realm)) < 0) goto end; else settings->kerberos_realm = xstrdup(ns_realm); xfree(queryname); return 0; } end: xfree(queryname); for (;*s != '.' && *s != '\0';s++); if (*s != '\0') s++; } while (*s != '\0'); s = settings->hostname; for (;*s != '.';s++); s++; settings->kerberos_realm = xstrdup(s); #endif return 0; }
static void afsdb_hosts_to_addrs(char *vllist[], int *vlsnum, ns_msg handle, ns_sect section, unsigned mask, unsigned long *_ttl) { int rrnum; ns_rr rr; int subtype, i, ret; unsigned int ttl = UINT_MAX, rr_ttl; debug("AFSDB RR count is %d", ns_msg_count(handle, section)); /* Look at all the resource records in this section. */ for (rrnum = 0; rrnum < ns_msg_count(handle, section); rrnum++) { /* Expand the resource record number rrnum into rr. */ if (ns_parserr(&handle, section, rrnum, &rr)) { _error("ns_parserr failed : %m"); continue; } /* We're only interested in AFSDB records */ if (ns_rr_type(rr) == ns_t_afsdb) { vllist[*vlsnum] = malloc(MAXDNAME); if (!vllist[*vlsnum]) error("Out of memory"); subtype = ns_get16(ns_rr_rdata(rr)); /* Expand the name server's domain name */ if (ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), ns_rr_rdata(rr) + 2, vllist[*vlsnum], MAXDNAME) < 0) error("ns_name_uncompress failed"); rr_ttl = ns_rr_ttl(rr); if (ttl > rr_ttl) ttl = rr_ttl; /* Check the domain name we've just unpacked and add it to * the list of VL servers if it is not a duplicate. * If it is a duplicate, just ignore it. */ for (i = 0; i < *vlsnum; i++) if (strcasecmp(vllist[i], vllist[*vlsnum]) == 0) goto next_one; /* Turn the hostname into IP addresses */ ret = dns_resolver(vllist[*vlsnum], mask); if (ret) { debug("AFSDB RR can't resolve." "subtype:%d, server name:%s, netmask:%u", subtype, vllist[*vlsnum], mask); goto next_one; } info("AFSDB RR subtype:%d, server name:%s, ip:%*.*s, ttl:%u", subtype, vllist[*vlsnum], (int)payload[payload_index - 1].iov_len, (int)payload[payload_index - 1].iov_len, (char *)payload[payload_index - 1].iov_base, ttl); /* prepare for the next record */ *vlsnum += 1; continue; next_one: free(vllist[*vlsnum]); } } *_ttl = ttl; info("ttl: %u", ttl); }
static DNS_STATUS dns_copy_rdata( ns_msg msg, const ns_rr *rr, DNS_RECORDA *r, WORD *dlen ) { DNS_STATUS ret = ERROR_SUCCESS; const unsigned char *pos = rr->rdata; unsigned int i, size; switch (rr->type) { case ns_t_a: { r->Data.A.IpAddress = *(const DWORD *)pos; *dlen = sizeof(DNS_A_DATA); break; } case ns_t_aaaa: { for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++) { r->Data.AAAA.Ip6Address.IP6Dword[i] = *(const DWORD *)pos; pos += sizeof(DWORD); } *dlen = sizeof(DNS_AAAA_DATA); break; } case ns_t_key: { /* FIXME: byte order? */ r->Data.KEY.wFlags = *(const WORD *)pos; pos += sizeof(WORD); r->Data.KEY.chProtocol = *(const BYTE *)pos++; r->Data.KEY.chAlgorithm = *(const BYTE *)pos++; size = rr->rdata + rr->rdlength - pos; for (i = 0; i < size; i++) r->Data.KEY.Key[i] = *(const BYTE *)pos++; *dlen = sizeof(DNS_KEY_DATA) + (size - 1) * sizeof(BYTE); break; } case ns_t_rp: case ns_t_minfo: { r->Data.MINFO.pNameMailbox = dns_dname_from_msg( msg, pos ); if (!r->Data.MINFO.pNameMailbox) return ERROR_NOT_ENOUGH_MEMORY; if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0) return DNS_ERROR_BAD_PACKET; r->Data.MINFO.pNameErrorsMailbox = dns_dname_from_msg( msg, pos ); if (!r->Data.MINFO.pNameErrorsMailbox) { dns_free( r->Data.MINFO.pNameMailbox ); return ERROR_NOT_ENOUGH_MEMORY; } *dlen = sizeof(DNS_MINFO_DATAA); break; } case ns_t_afsdb: case ns_t_rt: case ns_t_mx: { r->Data.MX.wPreference = ntohs( *(const WORD *)pos ); r->Data.MX.pNameExchange = dns_dname_from_msg( msg, pos + sizeof(WORD) ); if (!r->Data.MX.pNameExchange) return ERROR_NOT_ENOUGH_MEMORY; *dlen = sizeof(DNS_MX_DATAA); break; } case ns_t_null: { r->Data.Null.dwByteCount = rr->rdlength; memcpy( r->Data.Null.Data, rr->rdata, rr->rdlength ); *dlen = sizeof(DNS_NULL_DATA) + rr->rdlength - 1; break; } case ns_t_cname: case ns_t_ns: case ns_t_mb: case ns_t_md: case ns_t_mf: case ns_t_mg: case ns_t_mr: case ns_t_ptr: { r->Data.PTR.pNameHost = dns_dname_from_msg( msg, pos ); if (!r->Data.PTR.pNameHost) return ERROR_NOT_ENOUGH_MEMORY; *dlen = sizeof(DNS_PTR_DATAA); break; } case ns_t_sig: { r->Data.SIG.pNameSigner = dns_dname_from_msg( msg, pos ); if (!r->Data.SIG.pNameSigner) return ERROR_NOT_ENOUGH_MEMORY; if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0) return DNS_ERROR_BAD_PACKET; /* FIXME: byte order? */ r->Data.SIG.wTypeCovered = *(const WORD *)pos; pos += sizeof(WORD); r->Data.SIG.chAlgorithm = *(const BYTE *)pos++; r->Data.SIG.chLabelCount = *(const BYTE *)pos++; r->Data.SIG.dwOriginalTtl = *(const DWORD *)pos; pos += sizeof(DWORD); r->Data.SIG.dwExpiration = *(const DWORD *)pos; pos += sizeof(DWORD); r->Data.SIG.dwTimeSigned = *(const DWORD *)pos; pos += sizeof(DWORD); r->Data.SIG.wKeyTag = *(const WORD *)pos; size = rr->rdata + rr->rdlength - pos; for (i = 0; i < size; i++) r->Data.SIG.Signature[i] = *(const BYTE *)pos++; *dlen = sizeof(DNS_SIG_DATAA) + (size - 1) * sizeof(BYTE); break; } case ns_t_soa: { r->Data.SOA.pNamePrimaryServer = dns_dname_from_msg( msg, pos ); if (!r->Data.SOA.pNamePrimaryServer) return ERROR_NOT_ENOUGH_MEMORY; if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0) return DNS_ERROR_BAD_PACKET; r->Data.SOA.pNameAdministrator = dns_dname_from_msg( msg, pos ); if (!r->Data.SOA.pNameAdministrator) { dns_free( r->Data.SOA.pNamePrimaryServer ); return ERROR_NOT_ENOUGH_MEMORY; } if (dns_ns_name_skip( &pos, ns_msg_end( msg ) ) < 0) return DNS_ERROR_BAD_PACKET; r->Data.SOA.dwSerialNo = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD); r->Data.SOA.dwRefresh = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD); r->Data.SOA.dwRetry = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD); r->Data.SOA.dwExpire = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD); r->Data.SOA.dwDefaultTtl = ntohl( *(const DWORD *)pos ); pos += sizeof(DWORD); *dlen = sizeof(DNS_SOA_DATAA); break; } case ns_t_srv: { r->Data.SRV.wPriority = ntohs( *(const WORD *)pos ); pos += sizeof(WORD); r->Data.SRV.wWeight = ntohs( *(const WORD *)pos ); pos += sizeof(WORD); r->Data.SRV.wPort = ntohs( *(const WORD *)pos ); pos += sizeof(WORD); r->Data.SRV.pNameTarget = dns_dname_from_msg( msg, pos ); if (!r->Data.SRV.pNameTarget) return ERROR_NOT_ENOUGH_MEMORY; *dlen = sizeof(DNS_SRV_DATAA); break; } case ns_t_hinfo: case ns_t_isdn: case ns_t_x25: case ns_t_txt: { i = 0; while (pos[0] && pos < rr->rdata + rr->rdlength) { r->Data.TXT.pStringArray[i] = dns_str_from_rdata( pos ); if (!r->Data.TXT.pStringArray[i]) { while (i > 0) dns_free( r->Data.TXT.pStringArray[--i] ); return ERROR_NOT_ENOUGH_MEMORY; } i++; pos += pos[0] + 1; } r->Data.TXT.dwStringCount = i; *dlen = sizeof(DNS_TXT_DATAA) + (i - 1) * sizeof(PCHAR); break; } case ns_t_atma: case ns_t_loc: case ns_t_nxt: case ns_t_tsig: case ns_t_wks: case 0x00f9: /* TKEY */ case 0xff01: /* WINS */ case 0xff02: /* WINSR */ default: FIXME( "unhandled type: %s\n", dns_type_to_str( rr->type ) ); return DNS_ERROR_RCODE_NOT_IMPLEMENTED; } return ret; }
static void test_res_fake_a_via_cname(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char cname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); /* Query for A record, but the key is a CNAME. The expected result is * that the whole chain of CNAMEs will be included in the answer section * along with the resulting A */ rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_a, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have three answers and the answers * must be a parseable RR of type CNAME and have the cname as in the * fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 3); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "web.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_an, 1, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "www.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_an, 2, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "www.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.22"); }
static void test_res_fake_cname_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char cname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "rwrap.org", ns_c_in, ns_t_cname, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, 256, &handle); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type CNAME and have the cname as in the * fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "web.cwrap.org"); /* The CNAME points to an A record that's present in the additional * section */ assert_int_equal(ns_msg_count(handle, ns_s_ar), 2); assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_cname); assert_string_equal(ns_rr_name(rr), "web.cwrap.org"); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, cname, MAXDNAME); assert_int_not_equal(rv, -1); assert_string_equal(cname, "www.cwrap.org"); assert_int_equal(ns_parserr(&handle, ns_s_ar, 1, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "www.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.22"); }
static void test_res_fake_soa_query(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; char nameser[MAXDNAME]; char admin[MAXDNAME]; int serial; int refresh; int retry; int expire; int minimum; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "cwrap.org", ns_c_in, ns_t_soa, answer, sizeof(answer)); assert_in_range(rv, 1, 100); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SOA and have the data as in the fake * hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_soa); rrdata = ns_rr_rdata(rr); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, nameser, MAXDNAME); assert_int_not_equal(rv, -1); rrdata += rv; rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, admin, MAXDNAME); assert_int_not_equal(rv, -1); rrdata += rv; NS_GET32(serial, rrdata); NS_GET32(refresh, rrdata); NS_GET32(retry, rrdata); NS_GET32(expire, rrdata); NS_GET32(minimum, rrdata); assert_string_equal(nameser, "ns1.cwrap.org"); assert_string_equal(admin, "admin.cwrap.org"); assert_int_equal(serial, 2014100457); assert_int_equal(refresh, 3600); assert_int_equal(retry, 300); assert_int_equal(expire, 1814400); assert_int_equal(minimum, 600); }
/* * Test the case of a SRV record query where the * fake hosts file entry is minimal in the sense * that it omits the priority and weight entries. * The server then fills in some default values. */ static void test_res_fake_srv_query_minimal(void **state) { int rv; struct __res_state dnsstate; unsigned char answer[ANSIZE]; ns_msg handle; ns_rr rr; /* expanded resource record */ const uint8_t *rrdata; int prio; int weight; int port; char hostname[MAXDNAME]; char addr[INET_ADDRSTRLEN]; (void) state; /* unused */ memset(&dnsstate, 0, sizeof(struct __res_state)); rv = res_ninit(&dnsstate); assert_int_equal(rv, 0); rv = res_nquery(&dnsstate, "_krb5._tcp.cwrap.org", ns_c_in, ns_t_srv, answer, sizeof(answer)); assert_in_range(rv, 1, 256); ns_initparse(answer, sizeof(answer), &handle); /* * The query must finish w/o an error, have one answer and the answer * must be a parseable RR of type SRV and have the priority, weight, * port and hostname as in the fake hosts file */ assert_int_equal(ns_msg_getflag(handle, ns_f_rcode), ns_r_noerror); assert_int_equal(ns_msg_count(handle, ns_s_an), 1); assert_int_equal(ns_parserr(&handle, ns_s_an, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_srv); rrdata = ns_rr_rdata(rr); NS_GET16(prio, rrdata); NS_GET16(weight, rrdata); NS_GET16(port, rrdata); rv = ns_name_uncompress(ns_msg_base(handle), ns_msg_end(handle), rrdata, hostname, MAXDNAME); assert_int_not_equal(rv, -1); assert_int_equal(prio, 1); assert_int_equal(weight, 100); assert_int_equal(port, 88); assert_string_equal(hostname, "krb5.cwrap.org"); /* The additional section contains the A record of krb5.cwrap.org */ assert_int_equal(ns_msg_count(handle, ns_s_ar), 1); assert_int_equal(ns_parserr(&handle, ns_s_ar, 0, &rr), 0); assert_int_equal(ns_rr_type(rr), ns_t_a); assert_string_equal(ns_rr_name(rr), "krb5.cwrap.org"); assert_non_null(inet_ntop(AF_INET, ns_rr_rdata(rr), addr, sizeof(addr))); assert_string_equal(addr, "127.0.0.23"); }
int dns_get_mx_list(const char *host, int port, struct mx_hostentry **he, int no_mx) { char outname[MAXDNAME]; ns_msg msg; ns_rr rr; const char *searchhost; const unsigned char *cp; unsigned char *ans; struct mx_hostentry *hosts = NULL; size_t nhosts = 0; size_t anssz; int pref; int cname_recurse; int err; int i; res_init(); searchhost = host; cname_recurse = 0; anssz = 65536; ans = malloc(anssz); if (ans == NULL) return (1); if (no_mx) goto out; repeat: err = res_search(searchhost, ns_c_in, ns_t_mx, ans, anssz); if (err < 0) { switch (h_errno) { case NO_DATA: /* * Host exists, but no MX (or CNAME) entry. * Not an error, use host name instead. */ goto out; case TRY_AGAIN: /* transient error */ goto transerr; case NO_RECOVERY: case HOST_NOT_FOUND: default: errno = ENOENT; goto err; } } if (!ns_initparse(ans, anssz, &msg)) goto transerr; switch (ns_msg_getflag(msg, ns_f_rcode)) { case ns_r_noerror: break; case ns_r_nxdomain: goto err; default: goto transerr; } for (i = 0; i < ns_msg_count(msg, ns_s_an); i++) { if (ns_parserr(&msg, ns_s_an, i, &rr)) goto transerr; cp = ns_rr_rdata(rr); switch (ns_rr_type(rr)) { case ns_t_mx: pref = ns_get16(cp); cp += 2; err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), cp, outname, sizeof(outname)); if (err < 0) goto transerr; add_host(pref, outname, port, &hosts, &nhosts); break; case ns_t_cname: err = ns_name_uncompress(ns_msg_base(msg), ns_msg_end(msg), cp, outname, sizeof(outname)); if (err < 0) goto transerr; /* Prevent a CNAME loop */ if (cname_recurse++ > 10) goto err; searchhost = outname; goto repeat; default: break; } } out: err = 0; if (0) { transerr: if (nhosts == 0) err = 1; } if (0) { err: err = -1; } free(ans); if (!err) { /* * If we didn't find any MX, use the hostname instead. */ if (nhosts == 0) add_host(0, searchhost, port, &hosts, &nhosts); qsort(hosts, nhosts, sizeof(*hosts), sort_pref); } if (nhosts > 0) { /* terminate list */ *hosts[nhosts].host = 0; } else { if (hosts != NULL) free(hosts); hosts = NULL; } *he = hosts; return (err); free(ans); if (hosts != NULL) free(hosts); return (err); }
static void dump_dns_rr(ns_msg *msg, ns_rr *rr, ns_sect sect, FILE *trace) { char buf[NS_MAXDNAME]; u_int class, type; const u_char *rd; u_int32_t soa[5]; u_int16_t mx; int n; memset(buf, 0, sizeof(buf)); class = ns_rr_class(*rr); type = ns_rr_type(*rr); fprintf(trace, "%s,%s,%s", ns_rr_name(*rr), p_class(class), p_type(type)); if (sect == ns_s_qd) return; fprintf(trace, ",%lu", (u_long)ns_rr_ttl(*rr)); rd = ns_rr_rdata(*rr); switch (type) { case ns_t_soa: n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg), rd, buf, sizeof buf); if (n < 0) goto error; putc(',', trace); fputs(buf, trace); rd += n; n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg), rd, buf, sizeof buf); if (n < 0) goto error; putc(',', trace); fputs(buf, trace); rd += n; if (ns_msg_end(*msg) - rd < 5*NS_INT32SZ) goto error; for (n = 0; n < 5; n++) MY_GET32(soa[n], rd); sprintf(buf, "%u,%u,%u,%u,%u", soa[0], soa[1], soa[2], soa[3], soa[4]); break; case ns_t_a: if (ns_msg_end(*msg) - rd < 4) goto error; inet_ntop(AF_INET, rd, buf, sizeof buf); break; case ns_t_aaaa: if (ns_msg_end(*msg) - rd < 16) goto error; inet_ntop(AF_INET6, rd, buf, sizeof buf); break; case ns_t_mx: if (ns_msg_end(*msg) - rd < 2) goto error; MY_GET16(mx, rd); fprintf(trace, ",%u", mx); /* FALLTHROUGH */ case ns_t_ns: case ns_t_ptr: case ns_t_cname: n = ns_name_uncompress(ns_msg_base(*msg), ns_msg_end(*msg), rd, buf, sizeof buf); if (n < 0) goto error; break; /* * GGM 2014/09/04 deal with edns0 a bit more clearly */ case ns_t_opt: { u_long edns0csize; u_short edns0version; u_short edns0rcode; u_char edns0dobit; u_char edns0z; /* class encodes client UDP size accepted */ edns0csize = (u_long)(class); /* * the first two bytes of ttl encode edns0 version, and the extended rcode */ edns0version = ((u_long)ns_rr_ttl(*rr) & 0x00ff0000) >> 16; edns0rcode = ((u_long)ns_rr_ttl(*rr) & 0xff000000) >> 24; /* * the next two bytes of ttl encode DO bit as the top bit, and the remainder is the 'z' value */ edns0dobit = (u_long)ns_rr_ttl(*rr) & 0x8000 ? '1' : '0'; edns0z = (u_long)ns_rr_ttl(*rr) & 0x7fff; /* optlen is the size of the OPT rdata */ u_short optlen = ns_rr_rdlen(*rr); fprintf(trace, ",edns0[len=%d,UDP=%lu,ver=%d,rcode=%d,DO=%c,z=%d] %c\n\t", optlen, edns0csize, edns0version, edns0rcode, edns0dobit, edns0z, '\\'); /* if we have any data */ while (optlen >= 4) { /* the next two shorts are the edns0 opt code, and the length of the optionsection */ u_short edns0optcod; u_short edns0lenopt; MY_GET16(edns0optcod, rd); MY_GET16(edns0lenopt, rd); optlen -= 4; fprintf(trace, "edns0[code=%d,codelen=%d] ", edns0optcod, edns0lenopt); /* * Check that the OPTION-LENGTH for this EDNS0 option doesn't * exceed the size of the remaining OPT record rdata. If it does, * just bail. */ if (edns0lenopt > optlen) goto error; /* * "pre-consume" edns0lenopt bytes from optlen here because * below we're going to decrement edns0lenopt as we go. * At this point optlen will refer to the size of the remaining * OPT_T rdata after parsing the current option. */ optlen -= edns0lenopt; /* if we have edns0_client_subnet */ if (edns0optcod == 0x08) { if (edns0lenopt < 4) goto error; u_short afi; MY_GET16(afi, rd); u_short masks; MY_GET16(masks, rd); edns0lenopt -= 4; u_short srcmask = (masks & 0xff00) >> 8; u_short scomask = (masks & 0xff); char buf[128]; u_char addr[16]; memset(addr, 0, sizeof addr); memcpy(addr, rd, edns0lenopt < sizeof(addr) ? edns0lenopt : sizeof(addr)); if (afi == 0x1) { inet_ntop(AF_INET, addr, buf, sizeof buf); } else if (afi == 0x2) { inet_ntop(AF_INET6, addr, buf, sizeof buf); } else { fprintf(trace, "unknown AFI %d\n", afi); strcpy(buf,"<unknown>"); } fprintf(trace, "edns0_client_subnet=%s/%d (scope %d)", buf, srcmask, scomask); } /* increment the rd pointer by the remaining option data size */ rd += edns0lenopt; } } break; default: error: sprintf(buf, "[%u]", ns_rr_rdlen(*rr)); } if (buf[0] != '\0') { putc(',', trace); fputs(buf, trace); } }
/*! \brief Returns a MEM STACK with the requested DNS records */ PKI_MEM_STACK *URL_get_data_dns_url(URL *url, ssize_t size) { PKI_MEM_STACK *ret = NULL; #ifdef HAVE_LIBRESOLV int type = T_A; PKI_MEM *obj = NULL; if( (!url) || (!url->addr)) { return NULL; } unsigned char response[NS_PACKETSZ]; ns_msg dnsMessage; ns_rr dnsRecord; int dnsRecordSection = ns_s_an; int dns_msgCount = 0; int len = 0; // Check the Type of record if ((type = URL_get_dns_type(url->attrs)) == -1) return NULL; PKI_log_debug("DNS URI: Searching for %s (%s/%d)", url->addr, url->attrs, type); if ((len = res_search(url->addr, C_IN, type, response, sizeof(response))) < 0) { // An Error Occurred PKI_log_err("DNS URI: search failed\n"); return NULL; } if (ns_initparse(response, len, &dnsMessage) < 0) { // This should not happen if the record is correct PKI_log_err("DNS URI: can not init DNS parsing of the dnsMessage\n"); return NULL; } len = ns_msg_count(dnsMessage, dnsRecordSection); PKI_log_debug("DNS_URI: msg count ==> %d\n", len); if (len <= 0) return NULL; if((ret = PKI_STACK_MEM_new()) == NULL ) { PKI_log_debug ("DNS URI: Memory Failure"); return NULL; } for (dns_msgCount = 0; dns_msgCount < len; dns_msgCount++) { PKI_log_debug("DNS URI: Retrieving DNS record #%d",dns_msgCount); if (ns_parserr(&dnsMessage, dnsRecordSection, dns_msgCount, &dnsRecord)) { // ERROR: ns_parserr failed, let's continue to the next record PKI_log_err("DNS URI: Can not parse record %d of %d", dns_msgCount, len); continue; } PKI_log_debug("DNS URI: type = %d (req: %d)\n", ns_rr_type(dnsRecord), type); if (type == pki_ns_t_address) { switch (ns_rr_type(dnsRecord)) { case T_A: case T_AAAA: case T_CNAME: break; default: continue; } } else if (type != ns_rr_type(dnsRecord)) { PKI_log_debug("DNS URI: recived type %d is different from requested (%d)", type, ns_rr_type(dnsRecord)); // continue; } // int i = 0; int rv = 0; // int len = 0; int offset = 0; char dnsRecordName[MAXDNAME]; memset(dnsRecordName, '\x0', MAXDNAME); // Parse the different types of DNS records if ((ns_rr_type(dnsRecord) == T_A) || (ns_rr_type(dnsRecord) == T_AAAA)) { // These require Translation using IPv4/IPv6 functions int family = AF_INET; if (ns_rr_type(dnsRecord) == T_A) family = AF_INET; else family = AF_INET6; if(inet_ntop(family, ns_rr_rdata(dnsRecord), dnsRecordName, sizeof(dnsRecordName)) == NULL) { // Can not convert continue; } } else if ((ns_rr_type(dnsRecord) == T_CNAME) || (ns_rr_type(dnsRecord) == T_MX) || (ns_rr_type(dnsRecord) == T_NS)) { if (ns_rr_type(dnsRecord) == T_MX) offset = NS_INT16SZ; rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage), ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME); // ERROR, can not uncompress the names if (rv < 0) continue; } else if (ns_rr_type(dnsRecord) == T_SRV) { // This requires special handling, the format is [SHORT][SHORT][SHORT][DATA] // unsigned short *pri = (unsigned short *) ns_rr_rdata(dnsRecord); // unsigned short *weight = (unsigned short *) &(ns_rr_rdata(dnsRecord)[2]); // unsigned short *port = (unsigned short *) &(ns_rr_rdata(dnsRecord)[4]); // Shall we return the additional data too ? // printf("PRI : %d\n", *pri); // printf("WEIGHT : %d\n", ntohs(*weight)); // printf("PORT : %d\n", ntohs(*port)); offset = 6; rv = ns_name_uncompress(ns_msg_base(dnsMessage), ns_msg_end(dnsMessage), ns_rr_rdata(dnsRecord) + offset, dnsRecordName, MAXDNAME); if (rv < 0) continue; } else if (ns_rr_type(dnsRecord) == T_TXT) { // Special handling required. Format is [BYTE][DATA] unsigned char *p = (unsigned char *)ns_rr_rdata(dnsRecord); snprintf(dnsRecordName, (size_t) *p+1, "%s", &ns_rr_rdata(dnsRecord)[1]); } else { PKI_log_debug("DNS URI: record type not supported [%d]", ns_rr_type(dnsRecord)); continue; } if((obj = PKI_MEM_new_null()) == NULL ) { // Memory Allocation Error, we abort break; } if (strlen(dnsRecordName) > 0) { // If it is a printable value, we add the parsed version of the // record if(PKI_MEM_add(obj, (char *) dnsRecordName, strlen(dnsRecordName)) == PKI_ERR) { /* ERROR in memory growth */; PKI_log_err("DNS URI: Memory Allocation Error"); break; } } else { // The value is not parsed/parsable, we return the raw data // the application should know what to do with the data! if(PKI_MEM_add(obj, (char *) ns_rr_rdata(dnsRecord), ns_rr_rdlen(dnsRecord)) == PKI_ERR) { /* ERROR in memory growth */; PKI_log_err("DNS URI: Memory Allocation Error"); break; } } /* printf("MSG Data [%d]:\n", ns_rr_rdlen(dnsRecord)); for (i=0; i < ns_rr_rdlen(dnsRecord); i++) { unsigned char *kk; kk = (unsigned char *) &ns_rr_rdata(dnsRecord)[i]; printf("%x:", *kk); }; printf("\n"); fprintf(stderr, "DEBUG: RV => %d (err: %d, %s)\n", rv, h_errno, hstrerror(h_errno)); fprintf(stderr, "DEBUG: name => %s (%s)\n", ns_rr_name(dnsRecord), url->addr); fprintf(stderr, "DEBUG: value => %s\n", dnsRecordName); fprintf(stderr, "DEBUG: type => %d\n", ns_rr_type(dnsRecord)); fprintf(stderr, "DEBUG: class => %d\n", ns_rr_class(dnsRecord)); */ PKI_STACK_MEM_push(ret, obj); // PKI_log_debug("DNS URI: Added object #%d to stack", PKI_STACK_MEM_elements(ret)); } #endif return ret; };