u_char * ns_find_tsig(u_char *msg, u_char *eom) { HEADER *hp = (HEADER *)msg; int n, type; u_char *cp = msg, *start; isc_result_t status; if (msg == NULL || eom == NULL || msg > eom) return (NULL); if (cp + HFIXEDSZ >= eom) return (NULL); if (hp->arcount == 0) return (NULL); cp += HFIXEDSZ; status = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount), &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; status = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount), &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; status = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount), &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; status = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1, &n); if (status != ISC_R_SUCCESS) return (NULL); cp += n; start = cp; n = dn_skipname(cp, eom); if (n < 0) return (NULL); cp += n; if (cp + INT16SZ >= eom) return (NULL); GETSHORT(type, cp); if (type != ns_t_tsig) return (NULL); return (start); }
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); }
isc_result_t ns_initparse(const u_char *msg, unsigned 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) return ISC_R_INCOMPLETE; handle->_id = getUShort (msg); msg += 2; if (msg + NS_INT16SZ > eom) return ISC_R_INCOMPLETE; handle->_flags = getUShort (msg); msg += 2; for (i = 0; i < ns_s_max; i++) { if (msg + NS_INT16SZ > eom) return ISC_R_INCOMPLETE; handle->_counts[i] = getUShort (msg); msg += 2; } for (i = 0; i < ns_s_max; i++) if (handle->_counts[i] == 0) handle->_sections[i] = NULL; else { int b; isc_result_t status = ns_skiprr(msg, eom, (ns_sect)i, handle->_counts[i], &b); if (status != ISC_R_SUCCESS) return STATUS; handle->_sections[i] = msg; msg += b; } if (msg != eom) return ISC_R_INCOMPLETE; setsection(handle, ns_s_max); return ISC_R_SUCCESS; }
isc_result_t ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) { int b; isc_result_t status; int tmp; /* XXX used to force a signed comparison below */ /* Make section right. */ if ((tmp = section) < 0 || section >= ns_s_max) return ISC_R_NOTIMPLEMENTED; if (section != handle->_sect) setsection(handle, section); /* Make rrnum right. */ if (rrnum == -1) rrnum = handle->_rrnum; if (rrnum < 0 || rrnum >= handle->_counts[(int)section]) return ISC_R_UNKNOWNATTRIBUTE; if (rrnum < handle->_rrnum) setsection(handle, section); if (rrnum > handle->_rrnum) { status = ns_skiprr(handle->_ptr, handle->_eom, section, rrnum - handle->_rrnum, &b); if (status != ISC_R_SUCCESS) return status; handle->_ptr += b; handle->_rrnum = rrnum; } /* Do the parse. */ b = dn_expand(handle->_msg, handle->_eom, handle->_ptr, rr->name, NS_MAXDNAME); if (b < 0) return ISC_R_FORMERR; handle->_ptr += b; if (handle->_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom) return ISC_R_INCOMPLETE; rr->type = getUShort (handle->_ptr); handle -> _ptr += 2; rr->rr_class = getUShort (handle->_ptr); handle -> _ptr += 2; if (section == ns_s_qd) { rr->ttl = 0; rr->rdlength = 0; rr->rdata = NULL; } else { if (handle->_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom) return ISC_R_INCOMPLETE; rr->ttl = getULong (handle->_ptr); handle -> _ptr += 4; rr->rdlength = getUShort (handle->_ptr); handle -> _ptr += 2; if (handle->_ptr + rr->rdlength > handle->_eom) return ISC_R_INCOMPLETE; rr->rdata = handle->_ptr; handle->_ptr += rr->rdlength; } if (++handle->_rrnum > handle->_counts[(int)section]) setsection(handle, (ns_sect)((int)section + 1)); /* All done. */ return ISC_R_SUCCESS; }
/* * Simplified version of srv_query() for domain auto-discovery. */ int srv_getdom(res_state state, const char *svc_name, char **rrname) { union { HEADER hdr; uchar_t buf[NS_MAXMSG]; } msg; int len, qdcount, ancount; uchar_t *ptr, *eom; char namebuf[NS_MAXDNAME]; /* query necessary resource records */ *rrname = NULL; if (DBG(DNS, 1)) { logger(LOG_DEBUG, "Looking for SRV RRs '%s.*'", svc_name); } len = res_nsearch(state, svc_name, C_IN, T_SRV, msg.buf, sizeof (msg.buf)); if (len < 0) { if (DBG(DNS, 0)) { logger(LOG_DEBUG, "DNS search for '%s' failed (%s)", svc_name, hstrerror(state->res_h_errno)); } return (-1); } if (len > sizeof (msg.buf)) { logger(LOG_WARNING, "DNS query %ib message doesn't fit into %ib buffer", len, sizeof (msg.buf)); len = sizeof (msg.buf); } /* parse the reply header */ ptr = msg.buf + sizeof (msg.hdr); eom = msg.buf + len; qdcount = ntohs(msg.hdr.qdcount); ancount = ntohs(msg.hdr.ancount); /* 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 (-1); } ptr += len; /* parse the answer section */ if (ancount < 1) { logger(LOG_ERR, "DNS query - no answers"); return (-1); } len = dn_expand(msg.buf, eom, ptr, namebuf, sizeof (namebuf)); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); return (-1); } *rrname = strdup(namebuf); if (*rrname == NULL) { logger(LOG_ERR, "Out of memory"); return (-1); } return (0); }
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); }