u_long ns_get32(const u_char *src) { u_long dst; NS_GET32(dst, src); return (dst); }
uint32_t ns_get32(const u_char *src) { uint32_t dst; NS_GET32(dst, src); return (dst); }
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); }
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; }
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; }
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); }
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 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); }
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); }
u_long _getlong(const u_char *src) { u_long dst; NS_GET32(dst, src); return dst; }
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; }
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; }