static void parse_answer_section(ns_msg *msg) { int rrnum, rrmax; ns_rr rr; uint16_t prio, weight, port, len; const unsigned char *rdata; char *tname; rrmax = ns_msg_count(*msg, ns_s_an); for (rrnum = 0; rrnum < rrmax; rrnum++) { if (ns_parserr(msg, ns_s_an, rrnum, &rr)) { perror("ns_parserr"); exit(EXIT_FAILURE); } if (ns_rr_type(rr) == ns_t_srv) { len = ns_rr_rdlen(rr); rdata = ns_rr_rdata(rr); if (len > 3U * NS_INT16SZ) { NS_GET16(prio, rdata); NS_GET16(weight, rdata); NS_GET16(port, rdata); len -= 3U * NS_INT16SZ; tname = target_name(rdata); insert_tuple(tname, prio, weight, port); } } } }
int ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { const u_char *eom = msg + msglen; int i; handle->_msg = msg; handle->_eom = eom; if (msg + NS_INT16SZ > eom) RETERR(EMSGSIZE); NS_GET16(handle->_id, msg); if (msg + NS_INT16SZ > eom) RETERR(EMSGSIZE); NS_GET16(handle->_flags, msg); for (i = 0; i < ns_s_max; i++) { if (msg + NS_INT16SZ > eom) RETERR(EMSGSIZE); NS_GET16(handle->_counts[i], msg); } for (i = 0; i < ns_s_max; i++) if (handle->_counts[i] == 0) handle->_sections[i] = NULL; else { int b = ns_skiprr(msg, eom, (ns_sect)i, handle->_counts[i]); if (b < 0) return (-1); handle->_sections[i] = msg; msg += b; } if (msg != eom) RETERR(EMSGSIZE); setsection(handle, ns_s_max); return (0); }
int ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { int b; int tmp; /* Make section right. */ tmp = section; if (tmp < 0 || section >= ns_s_max) RETERR(ENODEV); if (section != handle->_sect) setsection(handle, section); /* Make rrnum right. */ if (rrnum == -1) rrnum = handle->_rrnum; if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) RETERR(ENODEV); if (rrnum < handle->_rrnum) setsection(handle, section); if (rrnum > handle->_rrnum) { b = ns_skiprr(handle->_msg_ptr, handle->_eom, section, rrnum - handle->_rrnum); if (b < 0) return (-1); handle->_msg_ptr += b; handle->_rrnum = rrnum; } /* Do the parse. */ b = dn_expand(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME); if (b < 0) return (-1); handle->_msg_ptr += b; if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) RETERR(EMSGSIZE); NS_GET16(rr->type, handle->_msg_ptr); NS_GET16(rr->rr_class, handle->_msg_ptr); if (section == ns_s_qd) { rr->ttl = 0; rr->rdlength = 0; rr->rdata = NULL; } else { if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) RETERR(EMSGSIZE); NS_GET32(rr->ttl, handle->_msg_ptr); NS_GET16(rr->rdlength, handle->_msg_ptr); if (handle->_msg_ptr + rr->rdlength > handle->_eom) RETERR(EMSGSIZE); rr->rdata = handle->_msg_ptr; handle->_msg_ptr += rr->rdlength; } if (++handle->_rrnum > handle->_counts[(int)section]) setsection(handle, (ns_sect)((int)section + 1)); /* All done. */ return (0); }
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"); }
int local_ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle) { const unsigned char *eom = msg + msglen; int i; handle->_msg = msg; handle->_eom = eom; if (msg + NS_INT16SZ > eom) { errno = EMSGSIZE; return -1; } NS_GET16(handle->_id, msg); if (msg + NS_INT16SZ > eom) { errno = EMSGSIZE; return -1; } NS_GET16(handle->_flags, msg); for (i = 0; i < ns_s_max; i++) { if (msg + NS_INT16SZ > eom) { errno = EMSGSIZE; return -1; } NS_GET16(handle->_counts[i], msg); } for (i = 0; i < ns_s_max; i++) if (handle->_counts[i] == 0) handle->_sections[i] = NULL; else { int b = local_ns_skiprr(msg, eom, (ns_sect)i, handle->_counts[i]); if (b < 0) return -1; handle->_sections[i] = msg; msg += b; } if (msg != eom) { errno = EMSGSIZE; return -1; } local_ns_setsection(handle, ns_s_max); return 0; }
static int skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { const u_char *optr = ptr; for ((void)NULL; count > 0; count--) { int b, rdlength; b = dn_skipname(ptr, eom); if (b < 0) goto emsgsize; ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; if (section != ns_s_qd) { if (ptr + NS_INT32SZ > eom) goto emsgsize; ptr += NS_INT32SZ/*TTL*/; if (ptr + NS_INT16SZ > eom) goto emsgsize; NS_GET16(rdlength, ptr); ptr += rdlength/*RData*/; } } if (ptr > eom) goto emsgsize; return ((int)(ptr - optr)); emsgsize: errno = EMSGSIZE; return (-1); }
int ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) { const u_char *optr = ptr; for ((void) NULL; count > 0; count--) { int b, rdlength; b = dn_skipname(ptr, eom); if (b < 0) { RETERR(EMSGSIZE); } ptr += b /*Name*/ + NS_INT16SZ /*Type*/ + NS_INT16SZ /*Class*/; if (section != ns_s_qd) { if (ptr + NS_INT32SZ + NS_INT16SZ > eom) { RETERR(EMSGSIZE); } ptr += NS_INT32SZ /*TTL*/; NS_GET16(rdlength, ptr); ptr += rdlength /*RData*/; } } if (ptr > eom) { RETERR(EMSGSIZE); } return (ptr - optr); }
uint16_t ns_get16(const u_char *src) { uint16_t dst; NS_GET16(dst, src); return (dst); }
static int local_ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count) { const unsigned char *optr = ptr; for (; count > 0; count--) { int b, rdlength; b = local_ns_dn_skipname(ptr, eom); if (b < 0) { errno = EMSGSIZE; return -1; } ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/; if (section != ns_s_qd) { if (ptr + NS_INT32SZ + NS_INT16SZ > eom) { errno = EMSGSIZE; return -1; } ptr += NS_INT32SZ/*TTL*/; NS_GET16(rdlength, ptr); ptr += rdlength/*RData*/; } } if (ptr > eom) { errno = EMSGSIZE; return -1; } return ptr - optr; }
static void get_bn(BIGNUM *bn, u_char **pp) { short i; NS_GET16(i, *pp); i = ((i + 7) / 8); BN_bin2bn(*pp, i, bn); *pp += i; }
int php_getmxrr(char *hostname, char *mx_list, char *weight_list) { #ifdef PCC_MINGW return 0; #else char *mx_list_ptr = (char *)(mx_list + sprintf(mx_list, "")); char *weight_list_ptr = (char *)(weight_list + sprintf(weight_list, "")); unsigned char answer[MAXPACKET]; unsigned char expand_buffer[MAXHOSTNAMELEN]; int ans_len = res_search(hostname, C_IN, T_MX, answer, sizeof(answer)); HEADER *header_ptr = (HEADER *)&answer; unsigned char *body_ptr = (unsigned char *)&answer + NS_HFIXEDSZ; unsigned char *eom_ptr = (unsigned char *)&answer + sizeof(answer); int n, ancount, qdcount, type, weight; for (qdcount = ntohs((unsigned short)header_ptr->qdcount); qdcount--; body_ptr += (n + NS_QFIXEDSZ)) if ((n = dn_skipname(body_ptr, eom_ptr)) < 0) return -1; ancount = ntohs((unsigned short)header_ptr->ancount); while (--ancount >= 0 && body_ptr < eom_ptr) { if ((n = dn_skipname(body_ptr, eom_ptr)) < 0) return -1; body_ptr += n; NS_GET16(type, body_ptr); body_ptr += (NS_INT16SZ + NS_INT32SZ); NS_GET16(n, body_ptr); if (type != T_MX) { body_ptr += n; continue; } NS_GET16(weight, body_ptr); if ((n = dn_expand(answer, eom_ptr, body_ptr, expand_buffer, sizeof(expand_buffer) - 1)) < 0) return -1; body_ptr += n; mx_list_ptr += sprintf(mx_list_ptr - 1, " %s ", expand_buffer); weight_list_ptr += sprintf(weight_list_ptr - 1, " %d ", weight); } return 0; #endif /* PCC_MINGW */ }
int ns_initparse(const u_char *msg, int msglen, ns_msg *handle) { const u_char *eom = msg + msglen; int i; memset(handle, 0x5e, sizeof *handle); handle->_msg = msg; handle->_eom = eom; if (msg + NS_INT16SZ > eom) goto emsgsize; NS_GET16(handle->_id, msg); if (msg + NS_INT16SZ > eom) goto emsgsize; NS_GET16(handle->_flags, msg); for (i = 0; i < ns_s_max; i++) { if (msg + NS_INT16SZ > eom) goto emsgsize; NS_GET16(handle->_counts[i], msg); } for (i = 0; i < ns_s_max; i++) if (handle->_counts[i] == 0) handle->_sections[i] = NULL; else { int b = skiprr(msg, eom, (ns_sect)i, handle->_counts[i]); if (b < 0) return (-1); handle->_sections[i] = msg; msg += b; } if (msg != eom) goto emsgsize; handle->_sect = ns_s_max; handle->_rrnum = -1; handle->_msg_ptr = NULL; return (0); emsgsize: errno = EMSGSIZE; return (-1); }
void register_response(struct queries *q, int timeout, char *note) { u_char *p; int size; int rcode; int id; id = ntohs(q->send.u.h.id); if (note == NULL) note = ""; countqueries++; if (timeout >= 0) { p = q->recvbuf; NS_GET16(size, p); response_size_sum += size; response_size_sum2 += size * size; if (response_size_min == 0 || response_size_min > size) response_size_min = size; if (response_size_max == 0 || response_size_max < size) response_size_max = size; rcode = p[3] & 0x0f; countrcode[rcode]++; countanswers++; if (verbose) printf("recv response id=%d rcode=%d size=%d rtt=%d\n", id, rcode, size, timeout); } else if (timeout == ERRZEROREAD) { countzeroread++; if (verbose) printf("recv response id=%d zeroread\n", id); } else if (timeout == TIMEOUTERROR) { counttimeout++; if (verbose) printf("recv timeout id=%d %" PRId64 " usec\n", id, timediff(¤t, &q->sent)); } else { counterror++; if (verbose) { printf("recv error id=%d errno=%d at %s (%s)\n", id, ERROROFFSET - timeout, note, strerror(errno)); } } #ifdef DEBUG printf("%ld.%03ld no=%d fd=%d %d %s\n", q->sent.tv_sec, q->sent.tv_usec/1000, q->no, q->fd, timeout, note); fflush(stdout); #endif }
int local_ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { int b; int tmp; /* Make section right. */ tmp = section; if (tmp < 0 || section >= ns_s_max) { errno = ENODEV; return -1; } if (section != handle->_sect) local_ns_setsection(handle, section); /* Make rrnum right. */ if (rrnum == -1) rrnum = handle->_rrnum; if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) { errno = ENODEV; return -1; } if (rrnum < handle->_rrnum) local_ns_setsection(handle, section); if (rrnum > handle->_rrnum) { b = local_ns_skiprr(handle->LOCAL_NS_MSG_PTR, handle->_eom, section, rrnum - handle->_rrnum); if (b < 0) return (-1); handle->LOCAL_NS_MSG_PTR += b; handle->_rrnum = rrnum; } /* Do the parse. */ b = dn_expand(handle->_msg, handle->_eom, handle->LOCAL_NS_MSG_PTR, rr->name, NS_MAXDNAME); if (b < 0) return (-1); handle->LOCAL_NS_MSG_PTR += b; if (handle->LOCAL_NS_MSG_PTR + NS_INT16SZ + NS_INT16SZ > handle->_eom) { errno = EMSGSIZE; return -1; } NS_GET16(rr->type, handle->LOCAL_NS_MSG_PTR); NS_GET16(rr->rr_class, handle->LOCAL_NS_MSG_PTR); if (section == ns_s_qd) { rr->ttl = 0; rr->rdlength = 0; rr->rdata = NULL; } else { if (handle->LOCAL_NS_MSG_PTR + NS_INT32SZ + NS_INT16SZ > handle->_eom) { errno = EMSGSIZE; return -1; } NS_GET32(rr->ttl, handle->LOCAL_NS_MSG_PTR); NS_GET16(rr->rdlength, handle->LOCAL_NS_MSG_PTR); if (handle->LOCAL_NS_MSG_PTR + rr->rdlength > handle->_eom) { errno = EMSGSIZE; return -1; } rr->rdata = handle->LOCAL_NS_MSG_PTR; handle->LOCAL_NS_MSG_PTR += rr->rdlength; } if (++handle->_rrnum > handle->_counts[(int)section]) local_ns_setsection(handle, (ns_sect)((int)section + 1)); return 0; }
int eXosip_get_srv_record(struct osip_srv_record *record, char *domain, char *protocol) { querybuf answer; /* answer buffer from nameserver */ int n; char zone[1024]; int ancount, qdcount; /* answer count and query count */ HEADER *hp; /* answer buffer header */ char hostbuf[256]; unsigned char *msg, *eom, *cp; /* answer buffer positions */ int dlen, type, aclass, pref, weight, port; long ttl; int answerno; char tr[100]; memset(zone, 0, sizeof(zone)); memset(record, 0, sizeof(struct osip_srv_record)); if (domain == NULL || protocol == NULL) return OSIP_BADPARAMETER; if (eXosip.dns_capabilities <= 0) return OSIP_UNKNOWN_HOST; /* disabled */ if (strlen(domain) + strlen(protocol) > 1000) return OSIP_BADPARAMETER; if (strlen(protocol) >= 100) return OSIP_BADPARAMETER; snprintf(tr, 100, protocol); osip_tolower(tr); if (eXosip.dns_capabilities >= 2) n = eXosip_get_naptr(domain, protocol, zone, sizeof(zone) - 1); else n = -1; /* avoid NAPTR */ if (n == OSIP_SUCCESS && zone[0] == '\0') { /* protocol is not listed in NAPTR answer: not supported */ return OSIP_UNKNOWN_HOST; } if (n != OSIP_SUCCESS) { snprintf(zone, sizeof(zone) - 1, "_sip._%s.%s", tr, domain); OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "Using locally generated SRV record %s\n", zone)); } OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "About to ask for '%s IN SRV'\n", zone)); n = res_query(zone, C_IN, T_SRV, (unsigned char *) &answer, sizeof(answer)); if (n < (int) sizeof(HEADER)) { return OSIP_UNKNOWN_HOST; } /* browse message and search for DNS answers part */ hp = (HEADER *) & answer; qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); msg = (unsigned char *) (&answer); eom = (unsigned char *) (&answer) + n; cp = (unsigned char *) (&answer) + sizeof(HEADER); while (qdcount-- > 0 && cp < eom) { n = dn_expand(msg, eom, cp, (char *) hostbuf, 256); if (n < 0) { OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Invalid SRV record answer for '%s': bad format\n", zone)); return OSIP_UNDEFINED_ERROR; } cp += n + QFIXEDSZ; } /* browse DNS answers */ answerno = 0; /* loop through the answer buffer and extract SRV records */ while (ancount-- > 0 && cp < eom) { struct osip_srv_entry *srventry; n = dn_expand(msg, eom, cp, (char *) hostbuf, 256); if (n < 0) { OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Invalid SRV record answer for '%s': bad format\n", zone)); return OSIP_UNDEFINED_ERROR; } cp += n; #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) type = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(type, cp); #else NS_GET16(type, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) aclass = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(aclass, cp); #else NS_GET16(aclass, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) ttl = _get_long(cp); cp += sizeof(u_long); #elif defined(__APPLE_CC__) GETLONG(ttl, cp); #else NS_GET32(ttl, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) dlen = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(dlen, cp); #else NS_GET16(dlen, cp); #endif if (type != T_SRV) { cp += dlen; continue; } #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) pref = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(pref, cp); #else NS_GET16(pref, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) weight = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(weight, cp); #else NS_GET16(weight, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) port = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(port, cp); #else NS_GET16(port, cp); #endif n = dn_expand(msg, eom, cp, (char *) hostbuf, 256); if (n < 0) break; cp += n; srventry = &record->srventry[answerno]; snprintf(srventry->srv, sizeof(srventry->srv), "%s", hostbuf); srventry->priority = pref; srventry->weight = weight; if (weight) srventry->rweight = 1 + random() % (10000 * srventry->weight); else srventry->rweight = 0; srventry->port = port; OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "SRV record %s IN SRV -> %s:%i/%i/%i/%i\n", zone, srventry->srv, srventry->port, srventry->priority, srventry->weight, srventry->rweight)); answerno++; if (answerno == 10) break; } if (answerno == 0) return OSIP_UNKNOWN_HOST; osip_srv_record_sort(record, answerno); snprintf(record->name, sizeof(record->name), "%s", domain); return OSIP_SUCCESS; }
u_int _getshort(const u_char *src) { u_int dst; NS_GET16(dst, src); return dst; }
int getrrs(const char *label, int rrtype, void gotrec(unsigned int num, int type, const char *record)) { #ifdef _LINUX struct __res_state res; #endif unsigned char answer[8192]; HEADER *header = (HEADER *)answer; char buf[2048]; int ret, count; unsigned int i,j,k,rrnum = 0; unsigned char *startptr, *endptr, *ptr; uint16_t type = 0, class = 0; uint32_t ttl = 0; #ifdef _LINUX memset(&res, 0, sizeof(res)); res.options = RES_DEBUG; res_ninit(&res); #else res_init(); #endif memset(answer, 0, sizeof(answer)); #ifdef _LINUX ret = res_nquery(&res, label, C_IN, rrtype, answer, sizeof(answer)); #else ret = res_query(label, C_IN, rrtype, answer, sizeof(answer)); #endif if (ret < 0) return -1; /* Our start and end */ startptr = &answer[0]; endptr = &answer[ret]; /* Skip the header */ ptr = startptr + HFIXEDSZ; /* Skip Query part */ for (count = ntohs(header->qdcount); count--; ptr += ret + QFIXEDSZ) { if ((ret = dn_skipname(ptr, endptr)) < 0) return -1; } /* Only look at the Answer section */ count = ntohs(header->ancount); /* Go through all the Answer records */ while (ptr < endptr && count > 0) { rrnum++; memset(buf, 0, sizeof(buf)); ret = dn_expand (startptr, endptr, ptr, buf, sizeof(buf)); if (ret < 0) break; ptr += ret; if (ptr + INT16SZ + INT16SZ + INT32SZ >= endptr) break; /* Get the type */ NS_GET16(type, ptr); /* Get the class */ NS_GET16(class, ptr); /* Get the TTL */ NS_GET32(ttl, ptr); /* Get the RDLength */ NS_GET16(ret, ptr); memset(buf, 0, sizeof(buf)); switch (type) { case T_TXT: for (k = ret, j = 0; j < k && &ptr[j] < endptr; j += (i+1)) { i = ptr[j]; memcpy(buf, &ptr[j+1], i > sizeof(buf) ? sizeof(buf) : i); buf[i > sizeof(buf) ? sizeof(buf) : i] = '\0'; if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); } break; case T_A: inet_ntop(AF_INET, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; case T_AAAA: inet_ntop(AF_INET6, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; case T_MX: /* Get the MX preference */ NS_GET16(ttl, ptr); ret = dn_expand(startptr, endptr, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; case T_NS: ret = dn_expand(startptr, endptr, ptr, buf, sizeof(buf)); if (rrtype == type || rrtype == T_ANY) gotrec(rrnum, type, buf); break; default: /* Unhandled */ break; } ptr += ret; count--; } return 0; }
int eXosip_get_naptr(char *domain, char *protocol, char *srv_record, int max_length) { querybuf answer; /* answer buffer from nameserver */ int n; char zone[1024]; int ancount, qdcount; /* answer count and query count */ HEADER *hp; /* answer buffer header */ char hostbuf[256]; unsigned char *msg, *eom, *cp; /* answer buffer positions */ int dlen, type, aclass; long ttl; int answerno; char tr[100]; memset(srv_record, 0, max_length); if (domain == NULL || protocol == NULL) return OSIP_BADPARAMETER; if (strlen(domain) + strlen(protocol) > 1000) return OSIP_BADPARAMETER; if (strlen(protocol) >= 100) return OSIP_BADPARAMETER; snprintf(tr, 100, protocol); osip_tolower(tr); snprintf(zone, 1024, "%s", domain); OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "About to ask for '%s IN NAPTR\n", zone)); n = res_query(zone, C_IN, T_NAPTR, (unsigned char *) &answer, sizeof(answer)); if (n < (int) sizeof(HEADER)) { return OSIP_UNKNOWN_HOST; } /* browse message and search for DNS answers part */ hp = (HEADER *) & answer; qdcount = ntohs(hp->qdcount); ancount = ntohs(hp->ancount); msg = (unsigned char *) (&answer); eom = (unsigned char *) (&answer) + n; cp = (unsigned char *) (&answer) + sizeof(HEADER); while (qdcount-- > 0 && cp < eom) { n = dn_expand(msg, eom, cp, (char *) hostbuf, 256); if (n < 0) { OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Invalid SRV record answer for '%s': bad format\n", zone)); return OSIP_UNDEFINED_ERROR; } cp += n + QFIXEDSZ; } /* browse DNS answers */ answerno = 0; /* loop through the answer buffer and extract SRV records */ while (ancount-- > 0 && cp < eom) { int len; typedef struct { unsigned short order; unsigned short pref; char flag[256]; char service[1024]; char regexp[1024]; char replacement[1024]; } osip_naptr_t; osip_naptr_t anaptr; n = dn_expand(msg, eom, cp, (char *) hostbuf, 256); if (n < 0) { OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_ERROR, NULL, "Invalid NAPTR answer for '%s': bad format\n", zone)); return OSIP_UNDEFINED_ERROR; } cp += n; #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) type = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(type, cp); #else NS_GET16(type, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) aclass = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(aclass, cp); #else NS_GET16(aclass, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) ttl = _get_long(cp); cp += sizeof(u_long); #elif defined(__APPLE_CC__) GETLONG(ttl, cp); #else NS_GET32(ttl, cp); #endif #if defined(__NetBSD__) || defined(__OpenBSD__) ||\ defined(OLD_NAMESER) || defined(__FreeBSD__) dlen = _get_short(cp); cp += sizeof(u_short); #elif defined(__APPLE_CC__) GETSHORT(dlen, cp); #else NS_GET16(dlen, cp); #endif if (type != T_NAPTR) { cp += dlen; continue; } memset(&anaptr, 0, sizeof(osip_naptr_t)); memcpy((void *) &anaptr.order, cp, 2); anaptr.order = ntohs(anaptr.order); /*((unsigned short)cp[0] << 8) | ((unsigned short)cp[1]); */ cp += sizeof(unsigned short); memcpy((void *) &anaptr.pref, cp, 2); anaptr.pref = ntohs(anaptr.pref); /* ((unsigned short)cp[0] << 8) | ((unsigned short)cp[1]); */ cp += sizeof(unsigned short); len = *cp; cp++; strncpy(anaptr.flag, (char *) cp, len); anaptr.flag[len] = '\0'; cp += len; len = *cp; cp++; strncpy(anaptr.service, (char *) cp, len); anaptr.service[len] = '\0'; cp += len; len = *cp; cp++; strncpy(anaptr.regexp, (char *) cp, len); anaptr.regexp[len] = '\0'; cp += len; n = dn_expand(msg, eom, cp, anaptr.replacement, 1024 - 1); if (n < 0) break; cp += n; OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "NAPTR %s ->%i/%i/%s/%s/%s/%s\n", zone, anaptr.order, anaptr.pref, anaptr.flag, anaptr.service, anaptr.regexp, anaptr.replacement)); if (osip_strncasecmp(tr, "udp", 4) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2U", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "tcp", 4) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2T", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "udp-tls", 8) == 0 && osip_strncasecmp(anaptr.service, "SIPS+D2U", 9) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "tls", 4) == 0 && osip_strncasecmp(anaptr.service, "SIPS+D2T", 9) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } else if (osip_strncasecmp(tr, "sctp", 5) == 0 && osip_strncasecmp(anaptr.service, "SIP+D2S", 8) == 0) { snprintf(srv_record, max_length, "%s", anaptr.replacement); return OSIP_SUCCESS; } answerno++; } if (answerno == 0) return OSIP_UNKNOWN_HOST; OSIP_TRACE(osip_trace (__FILE__, __LINE__, OSIP_INFO2, NULL, "protocol: %s is not supported by domain %s\n", protocol, domain)); return OSIP_SUCCESS; }
int ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { int b; /* Make section right. */ if ((unsigned int)section >= ns_s_max) goto enodev; if ((int)section != (int)handle->_sect) { handle->_sect = section; handle->_rrnum = 0; handle->_msg_ptr = handle->_sections[(int)section]; } /* Make rrnum right. */ if (rrnum == -1) rrnum = handle->_rrnum; if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) goto enodev; if (rrnum < handle->_rrnum) { handle->_rrnum = 0; handle->_msg_ptr = handle->_sections[(int)section]; } b = skiprr(handle->_msg, handle->_eom, section, rrnum - handle->_rrnum); if (b < 0) return (-1); handle->_msg_ptr += b; handle->_rrnum = rrnum; /* Do the parse. */ b = dn_expand(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME); if (b < 0) return (-1); handle->_msg_ptr += b; if (handle->_msg_ptr + NS_INT16SZ > handle->_eom) goto emsgsize; NS_GET16(rr->type, handle->_msg_ptr); if (handle->_msg_ptr + NS_INT16SZ > handle->_eom) goto emsgsize; NS_GET16(rr->rr_class, handle->_msg_ptr); if (section == ns_s_qd) { rr->ttl = 0; rr->rdlength = 0; rr->rdata = NULL; } else { if (handle->_msg_ptr + NS_INT32SZ > handle->_eom) goto emsgsize; NS_GET32(rr->ttl, handle->_msg_ptr); if (handle->_msg_ptr + NS_INT16SZ > handle->_eom) goto emsgsize; NS_GET16(rr->rdlength, handle->_msg_ptr); if (handle->_msg_ptr + rr->rdlength > handle->_eom) goto emsgsize; rr->rdata = handle->_msg_ptr; handle->_msg_ptr += rr->rdlength; } handle->_rrnum++; /* All done. */ return (0); enodev: errno = ENODEV; return (-1); emsgsize: errno = EMSGSIZE; return (-1); }
/* * 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"); }
CAMLprim value mlresolv_query(value vdname, value vclass, value vtype) { union { HEADER hdr; /* defined in resolv.h */ u_char buf[PACKETSZ]; /* defined in arpa/nameser.h */ } response; int rc; u_char *cp, *tcp; u_char *eom; char r_name[MAXDNAME+1]; u_short r_class; u_short r_type; u_int32_t r_ttl; u_short r_len; int ancount, qdcount; value vres = Val_emptylist; if(vtype == caml_hash_variant("PTR")) { int a, b, c, d; a = b = c = d = 0; sscanf(String_val(vdname), "%u.%u.%u.%u", &a, &b, &c, &d); sprintf(r_name, "%u.%u.%u.%u.in-addr.arpa", d, c, b, a); rc = res_query(r_name, mlvariant_to_c(rr_class, vclass), mlvariant_to_c(rr_type, vtype), (u_char*)&response, sizeof(response)); } else rc = res_query(String_val(vdname), mlvariant_to_c(rr_class, vclass), mlvariant_to_c(rr_type, vtype), (u_char*)&response, sizeof(response)); if (rc < 0) { switch (h_errno) { case NETDB_INTERNAL: mlresolv_error(errno); case HOST_NOT_FOUND: /* Authoritative Answer Host not found */ raise_constant(*mlresolv_host_not_found_exn); case TRY_AGAIN: /* Non-Authoritative Host not found, or SERVERFAIL */ raise_constant(*mlresolv_try_again_exn); case NO_RECOVERY: raise_constant(*mlresolv_no_recovery_exn); case NO_DATA: /* Valid name, no data record of requested type */ raise_constant(*mlresolv_no_data_exn); case NETDB_SUCCESS: /* no problem */ defaykt: failwith("res_query: unknown error"); } } cp = (u_char *)&response.buf + sizeof(HEADER); eom = (u_char *)&response.buf + rc; ancount = ntohs(response.hdr.ancount) + ntohs(response.hdr.nscount); qdcount = ntohs(response.hdr.qdcount); for (; (qdcount > 0) && (cp < eom); qdcount--) { rc = dn_skipname(cp, eom) + QFIXEDSZ; if(rc < 0) failwith("dn_skipname failed"); cp += rc; } for (; (ancount > 0) && (cp < eom); ancount--) { value vrdata, vfields = Val_unit; rc = dn_expand(response.buf, eom, cp, (void*)r_name, MAXDNAME); if(rc < 0) failwith("dn_expand1 failed"); cp += rc; NS_GET16(r_type, cp); NS_GET16(r_class, cp); NS_GET32(r_ttl, cp); NS_GET16(r_len, cp); if(cp + r_len > eom) /* is this check necessary? */ r_len = eom - cp; tcp = cp; switch(r_type) { case ns_t_a: /* if(r_class == ns_c_in || r_class == ns_c_hs) { */ if(INADDRSZ > r_len) vfields = copy_string(""); else { struct in_addr inaddr; char *address; bcopy(tcp, (char *)&inaddr, INADDRSZ); address = (char *)inet_ntoa(inaddr); vfields = copy_string(address); } 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: case ns_t_nsap_ptr: { char r_name[MAXDNAME+1]; rc = dn_expand(response.buf, eom, cp, (void *) r_name, MAXDNAME); if(rc < 0) vfields = copy_string(""); else vfields = copy_string(r_name); break; } case ns_t_null: /* max up to 65535 */ vfields = caml_alloc_string(r_len); memmove(String_val(vfields), cp, r_len); break; case ns_t_txt: { int txtlen, rdata_len = r_len; value newcons, txt; vfields = Val_emptylist; while(tcp < eom && *tcp <= rdata_len) { txtlen = *tcp++; txt = caml_alloc_string(txtlen); memmove(String_val(txt), tcp, txtlen); tcp += txtlen; rdata_len -= txtlen+1; newcons = alloc_small(2, 0); Field(newcons, 0) = txt; Field(newcons, 1) = vfields; vfields = newcons; } break; } case ns_t_srv: if(INT16SZ * 3 <= r_len) { char r_name[MAXDNAME+1]; int prio, weight, port; NS_GET16(prio, tcp); NS_GET16(weight, tcp); NS_GET16(port, tcp); rc = dn_expand(response.buf, eom, tcp, (void *) r_name, MAXDNAME); vfields = alloc_small(4, 0); Field(vfields, 0) = Val_int(prio); Field(vfields, 1) = Val_int(weight); Field(vfields, 2) = Val_int(port); if(rc < 0) Field(vfields, 3) = copy_string(""); else Field(vfields, 3) = copy_string(r_name); } break; case ns_t_mx: case ns_t_rt: case ns_t_afsdb: if(INT16SZ <= r_len) { char r_name[MAXDNAME+1]; int prio; NS_GET16(prio, tcp); rc = dn_expand(response.buf, eom, tcp, (void *) r_name, MAXDNAME); vfields = alloc_small(2, 0); Field(vfields, 0) = Val_int(prio); if(rc < 0) Field(vfields, 1) = copy_string(""); else Field(vfields, 1) = copy_string(r_name); } break; case ns_t_soa: { char mname[MAXDNAME+1]; char rname[MAXDNAME+1]; u_int serial, minimum; int refresh, retry, expire; if((rc = dn_expand(response.buf, eom, tcp, (void *)mname, MAXDNAME)) < 0) break; tcp += rc; if((rc = dn_expand(response.buf, eom, tcp, (void *)rname, MAXDNAME)) < 0) break; tcp += rc; if (tcp - cp + INT32SZ * 5 > r_len) break; NS_GET32(serial, tcp); NS_GET32(refresh, tcp); NS_GET32(retry, tcp); NS_GET32(expire, tcp); NS_GET32(minimum, tcp); vfields = alloc_small(7, 0); Field(vfields, 0) = copy_string(mname); Field(vfields, 1) = copy_string(rname); Field(vfields, 2) = Val_int(serial); Field(vfields, 3) = Val_int(refresh); Field(vfields, 4) = Val_int(retry); Field(vfields, 5) = Val_int(expire); Field(vfields, 6) = Val_int(minimum); } break; case ns_t_minfo: { char rmailbx[MAXDNAME+1]; char emailbx[MAXDNAME+1]; if((rc = dn_expand(response.buf, eom, tcp, rmailbx, MAXDNAME)) < 0) break; tcp += rc; if((rc = dn_expand(response.buf, eom, tcp, emailbx, MAXDNAME)) < 0) break; vfields = alloc_small(2, 0); Field(vfields, 0) = copy_string(rmailbx); Field(vfields, 1) = copy_string(emailbx); } break; /* two strings */ case ns_t_hinfo: case ns_t_isdn: /* <ISDN-address> <sa> */ case ns_t_nsap: if(r_len > 0 && *tcp < r_len) { value str1; value str2; rc = *tcp++; if(r_type == ns_t_nsap) { int result = 0; for(; rc; rc--, tcp++) result += result * 10 + (*tcp - 0x38); str1 = Val_int(result); } else { str1 = caml_alloc_string(rc); memmove(String_val(str1), tcp, rc); tcp += rc; } if(rc + 1 > r_len && *tcp + rc + 2 >= r_len) { rc = *tcp++; str2 = caml_alloc_string(rc); memmove(String_val(str2), tcp, rc); } else str2 = copy_string(""); vfields = caml_alloc_small(2, 0); Field(vfields, 0) = str1; Field(vfields, 1) = str2; } break; case ns_t_wks: if(INADDRSZ + 1 <= r_len) { struct in_addr inaddr; char* address; u_short protocol; value bitmap; bcopy(tcp, (char *) &inaddr, INADDRSZ); address = (char*) inet_ntoa(inaddr); tcp += INADDRSZ; protocol = *tcp++; /* getprotobynumber(*cp) */ /* n = 0; while (cp < eom) { c = *cp++; do { if (c & 0200) { int port; port = htons((u_short)n); if (protocol != NULL) service = getservbyport(port, protocol->p_name); else service = NULL; if (service != NULL) doprintf((" %s", service->s_name)); else doprintf((" %s", dtoa(n))); } c <<= 1; } while (++n & 07); } doprintf((" )")); */ bitmap = caml_alloc_string(r_len - INADDRSZ - 1); memmove(String_val(bitmap), tcp, eom - tcp); vfields = alloc_small(4, 0); Field(vfields, 0) = copy_string(address); Field(vfields, 1) = Val_int(protocol); Field(vfields, 2) = bitmap; } break; case ns_t_rp: /* <mbox-dname> <txt-dname> */ { char rname1[MAXDNAME+1]; char rname2[MAXDNAME+1]; rc = dn_expand(response.buf, eom, tcp, rname1, MAXDNAME); if(rc < 0) break; tcp += rc; rc = dn_expand(response.buf, eom, tcp, rname2, MAXDNAME); if(rc < 0) break; vfields = alloc_small(2, 0); Field(vfields, 0) = copy_string(rname1); Field(vfields, 1) = copy_string(rname2); } break; case ns_t_x25: /* <PSDN-address> */ if(r_len > 0 && *tcp >= r_len) { rc = *tcp++; vfields = caml_alloc_string(rc); memmove(String_val(vfields), tcp, rc); } else vfields = copy_string(""); break; case ns_t_px: if(r_len > INT16SZ) { int pref; char rname1[MAXDNAME]; char rname2[MAXDNAME]; NS_GET16(pref, tcp); rc = dn_expand(response.buf, eom, tcp, rname1, MAXDNAME); if(rc < 0) break; tcp += rc; rc = dn_expand(response.buf, eom, tcp, rname2, MAXDNAME); if(rc < 0) break; tcp += rc; vfields = alloc_small(2, 0); Field(vfields, 0) = copy_string(rname1); Field(vfields, 1) = copy_string(rname2); } break; case ns_t_gpos: if(r_len > 0 && *tcp <= r_len) { float f1, f2, f3; char *tmp; rc = *tcp++; tmp = (char *) malloc(rc + 1); bcopy(tcp, tmp, rc); tmp[rc] = '\0'; f1 = atof(tmp); tcp += rc; if(tcp < eom && tcp + *tcp <= eom) { if(*tcp > rc) tmp = realloc(tmp, *tcp); rc = *tcp++; bcopy(tcp, tmp, rc); tmp[rc] = '\0'; f2 = atof(tmp); tcp += rc; } else f2 = 0.0; if(tcp < eom && tcp + *tcp <= eom) { if(*tcp > rc) tmp = realloc(tmp, *tcp); rc = *tcp++; bcopy(tcp, tmp, rc); tmp[rc] = '\0'; f3 = atof(tmp); tcp += rc; } else f3 = 0.0; free(tmp); vfields = alloc_small(3, 0); Field(vfields, 0) = copy_double((double)f1); Field(vfields, 1) = copy_double((double)f2); Field(vfields, 2) = copy_double((double)f3); } break; case ns_t_loc: failwith("LOC not implemented"); /* if(r_len > 0 && *tcp != 0) failwith("Invalid version in LOC RDATA"); if(r_len > 0) { rc = INT n = INT32SZ + 3*INT32SZ; if (check_size(rname, type, cp, msg, eor, n) < 0) break; c = _getlong(cp); cp += INT32SZ; n = _getlong(cp); doprintf(("\t%s ", pr_spherical(n, "N", "S"))); cp += INT32SZ; n = _getlong(cp); doprintf((" %s ", pr_spherical(n, "E", "W"))); cp += INT32SZ; n = _getlong(cp); doprintf((" %sm ", pr_vertical(n, "", "-"))); cp += INT32SZ; doprintf((" %sm", pr_precision((c >> 16) & 0xff))); doprintf((" %sm", pr_precision((c >> 8) & 0xff))); doprintf((" %sm", pr_precision((c >> 0) & 0xff))); break; */ /* case T_UID: case T_GID: if(INT32SZ <= r_len) NS_GET32(rc, cp); if (dlen == INT32SZ) { n = _getlong(cp); doprintf(("\t%s", dtoa(n))); cp += INT32SZ; } break; case T_UINFO: doprintf(("\t\"%s\"", stoa(cp, dlen, TRUE))); cp += dlen; break; case T_UNSPEC: cp += dlen; break; case T_AAAA: if (dlen == IPNGSIZE) { doprintf(("\t%s", ipng_ntoa(cp))); cp += IPNGSIZE; } break; case T_SIG: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); if (n >= T_FIRST && n <= T_LAST) doprintf(("\t%s", pr_type(n))); else doprintf(("\t%s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); n = 3*INT32SZ + INT16SZ; if (check_size(rname, type, cp, msg, eor, n) < 0) break; doprintf((" (")); n = _getlong(cp); doprintf(("\n\t\t\t%s", dtoa(n))); doprintf(("\t\t;original ttl")); cp += INT32SZ; n = _getlong(cp); doprintf(("\n\t\t\t%s", pr_date(n))); doprintf(("\t;signature expiration")); cp += INT32SZ; n = _getlong(cp); doprintf(("\n\t\t\t%s", pr_date(n))); doprintf(("\t;signature inception")); cp += INT32SZ; n = _getshort(cp); doprintf(("\n\t\t\t%s", dtoa(n))); doprintf(("\t\t;key tag")); cp += INT16SZ; n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf(("\n\t\t\t%s", pr_name(dname))); cp += n; if (cp < eor) { register char *buf; register int size; n = eor - cp; buf = base_ntoa(cp, n); size = strlength(buf); cp += n; while ((n = (size > 64) ? 64 : size) > 0) { doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE))); buf += n; size -= n; } } doprintf(("\n\t\t\t)")); break; case T_KEY: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t0x%s", xtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (cp < eor) { register char *buf; register int size; n = eor - cp; buf = base_ntoa(cp, n); size = strlength(buf); cp += n; doprintf((" (")); while ((n = (size > 64) ? 64 : size) > 0) { doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE))); buf += n; size -= n; } doprintf(("\n\t\t\t)")); } break; case T_NXT: n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf(("\t%s", pr_name(dname))); cp += n; n = 0; while (cp < eor) { c = *cp++; do { if (c & 0200) { if (n >= T_FIRST && n <= T_LAST) doprintf((" %s", pr_type(n))); else doprintf((" %s", dtoa(n))); } c <<= 1; } while (++n & 07); } break; case T_NAPTR: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t%s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf((" %s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" \"%s\"", stoa(cp, n, TRUE))); cp += n; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" \"%s\"", stoa(cp, n, TRUE))); cp += n; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" \"%s\"", stoa(cp, n, TRUE))); cp += n; n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf((" %s", pr_name(dname))); cp += n; break; case T_KX: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t%s", dtoa(n))); cp += INT16SZ; n = expand_name(rname, type, cp, msg, eom, dname); if (n < 0) break; doprintf((" %s", pr_name(dname))); cp += n; break; case T_CERT: if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf(("\t%s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, INT16SZ) < 0) break; n = _getshort(cp); doprintf((" %s", dtoa(n))); cp += INT16SZ; if (check_size(rname, type, cp, msg, eor, 1) < 0) break; n = *cp++; doprintf((" %s", dtoa(n))); if (cp < eor) { register char *buf; register int size; n = eor - cp; buf = base_ntoa(cp, n); size = strlength(buf); cp += n; doprintf((" (")); while ((n = (size > 64) ? 64 : size) > 0) { doprintf(("\n\t%s", stoa((u_char *)buf, n, FALSE))); buf += n; size -= n; } doprintf(("\n\t\t\t)")); } break; case T_EID: failwith("EID not implemented"); break; case T_NIMLOC: failwith("NIMLOC not implemented"); break; case T_ATMA: failwith("ATMA not implemented"); */ default: failwith("unknown RDATA type"); } if(vfields != Val_unit) { value vrecord, vrdata, newcons; Begin_root(vres); vrecord = alloc_small(5, 0); Field(vrecord, 0) = copy_string(r_name); Field(vrecord, 1) = c_to_mlvariant(rr_type, r_type); Field(vrecord, 2) = c_to_mlvariant(rr_class, r_class); Field(vrecord, 3) = Val_int(r_ttl); vrdata = alloc_small(2, 0); Field(vrdata, 0) = c_to_mlvariant(rr_type, r_type); Field(vrdata, 1) = vfields; Field(vrecord, 4) = vrdata; newcons = alloc_small(2, 0); Field(newcons, 0) = vrecord; Field(newcons, 1) = vres; vres = newcons; End_roots(); vrdata = Val_unit; } cp += r_len; } return vres; }
static ad_disc_cds_t * srv_parse(uchar_t *msg, int len, int *scnt, int *maxcnt) { ad_disc_cds_t *cds; ad_disc_cds_t *cds_res = NULL; HEADER *hdr; int i, qdcount, ancount, nscount, arcount; uchar_t *ptr, *eom; uchar_t *end; uint16_t type; /* LINTED E_FUNC_SET_NOT_USED */ uint16_t class __unused; uint32_t rttl; uint16_t size; char namebuf[NS_MAXDNAME]; eom = msg + len; hdr = (void *)msg; ptr = msg + sizeof (HEADER); qdcount = ntohs(hdr->qdcount); ancount = ntohs(hdr->ancount); nscount = ntohs(hdr->nscount); arcount = ntohs(hdr->arcount); /* skip the question section */ len = ns_skiprr(ptr, eom, ns_s_qd, qdcount); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); return (NULL); } ptr += len; /* * Walk through the answer section, building the result array. * The array size is +2 because we (possibly) add the preferred * DC if it was not there, and an empty one (null termination). */ *maxcnt = ancount + 2; cds_res = calloc(*maxcnt, sizeof (*cds_res)); if (cds_res == NULL) { logger(LOG_ERR, "Out of memory"); return (NULL); } cds = cds_res; for (i = 0; i < ancount; i++) { len = dn_expand(msg, eom, ptr, namebuf, sizeof (namebuf)); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } ptr += len; NS_GET16(type, ptr); NS_GET16(class, ptr); NS_GET32(rttl, ptr); NS_GET16(size, ptr); if ((end = ptr + size) > eom) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } if (type != T_SRV) { ptr = end; continue; } NS_GET16(cds->cds_ds.priority, ptr); NS_GET16(cds->cds_ds.weight, ptr); NS_GET16(cds->cds_ds.port, ptr); len = dn_expand(msg, eom, ptr, cds->cds_ds.host, sizeof (cds->cds_ds.host)); if (len < 0) { logger(LOG_ERR, "DNS query invalid SRV record"); goto err; } cds->cds_ds.ttl = rttl; if (DBG(DNS, 2)) { logger(LOG_DEBUG, " %s", namebuf); logger(LOG_DEBUG, " ttl=%d pri=%d weight=%d %s:%d", rttl, cds->cds_ds.priority, cds->cds_ds.weight, cds->cds_ds.host, cds->cds_ds.port); } cds++; /* move ptr to the end of current record */ ptr = end; } *scnt = (cds - cds_res); /* skip the nameservers section (if any) */ len = ns_skiprr(ptr, eom, ns_s_ns, nscount); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } ptr += len; /* walk through the additional records */ for (i = 0; i < arcount; i++) { sa_family_t af; len = dn_expand(msg, eom, ptr, namebuf, sizeof (namebuf)); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } ptr += len; NS_GET16(type, ptr); NS_GET16(class, ptr); NS_GET32(rttl, ptr); NS_GET16(size, ptr); if ((end = ptr + size) > eom) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } switch (type) { case ns_t_a: af = AF_INET; break; case ns_t_aaaa: af = AF_INET6; break; default: continue; } if (DBG(DNS, 2)) { char abuf[INET6_ADDRSTRLEN]; const char *ap; ap = inet_ntop(af, ptr, abuf, sizeof (abuf)); logger(LOG_DEBUG, " %s %s %s", (af == AF_INET) ? "A " : "AAAA", (ap) ? ap : "?", namebuf); } /* Find the server, add to its address list. */ for (cds = cds_res; cds->cds_ds.host[0] != '\0'; cds++) if (0 == strcmp(namebuf, cds->cds_ds.host)) save_addr(cds, af, ptr, size); /* move ptr to the end of current record */ ptr = end; } return (cds_res); err: free(cds_res); return (NULL); }