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 }
/*% * Convert an RR to presentation format. * * return: *\li Number of characters written to buf, or -1 (check errno). */ int ns_sprintrr(const ns_msg* handle, const ns_rr* rr, const char* name_ctx, const char* origin, char* buf, size_t buflen) { int n; n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle), ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr), ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr), name_ctx, origin, buf, buflen); return (n); }
char* getMailserver(const char* domain) { int len; char answer[NS_PACKETSZ]; char *mailserver = malloc(NS_PACKETSZ); ns_msg msg; ns_rr rr; if(res_init() == -1) { return NULL; } len = res_query(domain,C_ANY,T_MX,answer,NS_PACKETSZ); if(len == -1) { return NULL; } /* return first MX record */ ns_initparse(answer,len,&msg); ns_parserr(&msg,ns_s_an,0,&rr); dn_expand(ns_msg_base(msg),ns_msg_base(msg)+ns_msg_size(msg),ns_rr_rdata(rr)+NS_INT16SZ,mailserver,NS_PACKETSZ); return mailserver; }
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 int app_parse_srv(radiodns_app_t *app, ns_msg handle, ns_rr rr, char *dnbuf, radiodns_srv_t *srv) { const unsigned char *rdata; (void) app; rdata = ns_rr_rdata(rr); srv->priority = ns_get16(rdata); rdata += NS_INT16SZ; srv->weight = ns_get16(rdata); rdata += NS_INT16SZ; srv->port = ns_get16(rdata); rdata += NS_INT16SZ; dn_expand(ns_msg_base(handle), ns_msg_base(handle) + ns_msg_size(handle), rdata, dnbuf, MAXDNAME); if(!(srv->target = strdup(dnbuf))) { return -2; } return 0; }
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); }
/** * create_naptr_record() */ static NAPTR_record *create_naptr_record(const ns_msg *handle, const ns_rr *rr) { size_t rdchars; const u_char *rdata, *edata; const u_char *message = ns_msg_base(*handle); size_t message_len = ns_msg_size(*handle); char buf[NS_MAXDNAME]; /* defined in nameser.h */ NAPTR_record *naptr_record = malloc(sizeof(NAPTR_record)); memset(naptr_record,0,sizeof(NAPTR_record)); /* ** Domain field */ naptr_record->domain = strdup(ns_rr_name(*rr)); /* ** TTL field */ naptr_record->ttl = ns_rr_ttl(*rr); /* ** Copy from rdata ** (borrowed from BIND-8.2.2 ns_print.c) */ rdata = ns_rr_rdata(*rr); edata = rdata+ns_rr_rdlen(*rr); /* ** Order & preference field */ naptr_record->order = ns_get16(rdata); rdata += NS_INT16SZ; naptr_record->preference = ns_get16(rdata); rdata += NS_INT16SZ; /* ** Flags field */ if((naptr_record->flags = get_rdata_str(rdata,edata,&rdchars))==NULL) { free_naptr_record(naptr_record); return NULL; } rdata += rdchars; /* ** Service field */ if((naptr_record->service = get_rdata_str(rdata,edata,&rdchars))==NULL) { free_naptr_record(naptr_record); return NULL; } rdata += rdchars; /* ** RegExp field */ if((naptr_record->regexp = get_rdata_str(rdata,edata,&rdchars))==NULL) { free_naptr_record(naptr_record); return NULL; } rdata += rdchars; /* ** Replacement field ** Note: dn_expand() sets the first character to '\0' for the root, ** we are going to set it back to '.' */ if(dn_expand(message,message+message_len,rdata,buf,NS_MAXDNAME)==-1) { free_naptr_record(naptr_record); return NULL; } if(buf[0]=='\0') { buf[0]='.'; buf[1]='\0'; } naptr_record->replacement = strdup(buf); return naptr_record; }
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_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_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"); }
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); } }
/* Attempt to resolve the target FQDN for a context */ const char * radiodns_resolve_target(radiodns_t *context) { int len, c; ns_msg handle; ns_rr rr; char domain[MAXDNAME + 1], dnbuf[MAXDNAME + 1]; /* reset these to help with error handling in callers */ h_errno = NETDB_INTERNAL; errno = 0; if(!context->answer) { if(NULL == (context->answer = (unsigned char *) malloc(RDNS_ANSWERBUFLEN))) { return NULL; } } free(context->target); context->target = NULL; strcpy(domain, context->domain); for(;;) { h_errno = 0; if(0 >= (len = res_query(domain, ns_c_in, ns_t_any, context->answer, RDNS_ANSWERBUFLEN))) { if(NETDB_INTERNAL == h_errno) { return NULL; } break; } if(0 > ns_initparse(context->answer, len, &handle)) { break; } if(0 > (len = ns_msg_count(handle, ns_s_an))) { break; } /* Resolvers tend towards the sane: the last result in a set of * DNAME and CNAME replies will be the one we care about. If * you're building against a resolver which for some reason * behaves differently, you'll need a workaround here. */ dnbuf[0] = 0; for(c = 0; c < len; c++) { if(ns_parserr(&handle, ns_s_an, c, &rr)) { /* Parse failed? Hmm. */ continue; } if(ns_rr_class(rr) != ns_c_in) { continue; } if(ns_rr_type(rr) == ns_t_dname || ns_rr_type(rr) == ns_t_cname) { dn_expand(ns_msg_base(handle), ns_msg_base(handle) + ns_msg_size(handle), ns_rr_rdata(rr), dnbuf, sizeof(dnbuf)); } } if(dnbuf[0]) { if(0 == strcmp(domain, dnbuf)) { break; } strcpy(domain, dnbuf); continue; } break; } /* Whatever we found last is the target, unless we found nothing at all, * in which case the target is the same as the original domain. */ if(NULL == (context->target = strdup(domain))) { return NULL; } return context->target; }
static int app_follow_ptr(radiodns_app_t *app, unsigned char *abuf, ns_msg phandle, ns_rr prr) { char dnbuf[MAXDNAME + 1], dbuf[4]; char *d, *p, *endp; ns_msg handle; ns_rr rr; int c, len, r; dn_expand(ns_msg_base(phandle), ns_msg_base(phandle) + ns_msg_size(phandle), ns_rr_rdata(prr), dnbuf, sizeof(dnbuf)); if(!(app->name = (char *) calloc(1, strlen(dnbuf)))) { return -2; } d = app->name; p = dnbuf; while(*p && *p != '.') { if(*p == '\\' && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3])) { dbuf[0] = p[1]; dbuf[1] = p[2]; dbuf[2] = p[3]; dbuf[3] = 0; c = strtol(dbuf, NULL, 10); *d = c; d++; p += 4; continue; } else if(*p == '\\' && p[1]) { /* Skip the backslash, allowing it to escape the '.' */ p++; } *d = *p; d++; p++; } *d = 0; if(0 >= (len = res_query(dnbuf, ns_c_in, ns_t_any, abuf, RDNS_ANSWERBUFLEN))) { return -1; } if(0 > ns_initparse(abuf, len, &handle)) { return -1; } if(0 > (len = ns_msg_count(handle, ns_s_an))) { return -1; } if(!(app->srv = (radiodns_srv_t *) calloc(len, sizeof(radiodns_srv_t)))) { return -2; } for(c = 0; c < len; c++) { if(ns_parserr(&handle, ns_s_an, c, &rr)) { continue; } if(ns_rr_class(rr) != ns_c_in) { continue; } if(ns_rr_type(rr) == ns_t_txt) { app_parse_txt(app, handle, rr, dnbuf); } if(ns_rr_type(rr) == ns_t_srv) { r = app_parse_srv(app, handle, rr, dnbuf, &(app->srv[app->nsrv])); if(r == 0) { app->nsrv++; } else { return r; } } } if(app->nsrv) { return 0; } return -1; }
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); }
/*! \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; };