/** parses a PTR record into a ptr_rdata structure */ struct ptr_rdata* dns_ptr_parser( unsigned char* msg, unsigned char* end, unsigned char* rdata) { struct ptr_rdata* pname; int len; char name[MAX_DNS_NAME]; pname=0; if (dn_expand(msg, end, rdata, name, MAX_DNS_NAME-1)==-1) goto error; len=strlen(name); if (len>255) goto error; /* alloc sizeof struct + space for the null terminated name */ pname=local_malloc(sizeof(struct ptr_rdata)-1+len+1); if(pname==0){ LM_ERR("out of memory\n"); goto error; } pname->ptrdname_len=len; memcpy(pname->ptrdname, name, pname->ptrdname_len); pname->ptrdname[pname->ptrdname_len]=0; return pname; error: if (pname) local_free(pname); return 0; }
static int parse_answer(querybuf_t *ans, int len, struct in_addr *addr) { char buf[MAXPACKET]; HEADER *ahp; u_char *cp, *eoa; int type, n; ahp = &ans->hdr; eoa = ans->buf + len; cp = ans->buf + sizeof(HEADER); while (ahp->qdcount > 0) { ahp->qdcount--; cp += dn_skipname(cp, eoa) + QFIXEDSZ; } while (ahp->ancount > 0 && cp < eoa) { ahp->ancount--; if ((n = dn_expand(ans->buf, eoa, cp, buf, sizeof(buf))) < 0) break; cp += n; type = _getshort(cp); cp += 8; n = _getshort(cp); cp += 2; if (type == T_CNAME) { cp += n; continue; } memcpy(addr, cp, n); return 0; } h_errno = TRY_AGAIN; return -1; }
// ccured wrappers int dn_expand_wrapper(const u_char *msg, const u_char *eomorig, const u_char *comp_dn, char *exp_dn, int length) { __write_at_least(exp_dn, length); __verify_nul(comp_dn); return ( dn_expand(__ptrof(msg), __ptrof(eomorig), __ptrof(comp_dn), __ptrof(exp_dn), length) ); }
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 bool GetDN(const unsigned char * reply, const unsigned char * replyEnd, unsigned char * & cp, char * buff) { int len = dn_expand(reply, replyEnd, cp, buff, MAXDNAME); if (len < 0) return false; cp += len; return true; }
static int rrextract(u_char *msg, int msglen, u_char *rrp, u_char *dname, int namelen) { /* cp is used to read data from rrp[] (the Resource Record) * cp1 is used to write data into data[] * However, we sometimes abuse cp1 and use it for reading too. :-/ */ u_char *eom, *cp, *cp1, *rdatap; u_int class, type, dlen; int n; long origTTL; u_char data[MAXDATA*2+SPACE_FOR_VARS]; data [(MAXDATA*2)-1+SPACE_FOR_VARS] = EOS; cp = rrp; eom = msg + msglen; GETSHORT(dlen, cp); BOUNDS_CHECK(cp, dlen); /* Begin case T_SIG: */ /* Just read one variable --- the original reads several. */ BOUNDS_CHECK(cp, SPACE_FOR_VARS); cp1 = cp; GETLONG(origTTL, cp1); /* Skip checks on times which are present in the original. */ /* Copy over initial fields, which we read above. */ cp1 = (u_char *)data; BOUNDS_CHECK(cp, SPACE_FOR_VARS); memcpy(cp1, cp, SPACE_FOR_VARS); cp += SPACE_FOR_VARS; cp1 += SPACE_FOR_VARS; /* Expand the domain name, set cp1 past the end of the uncompressed * domain name. */ n = dn_expand(msg, eom, cp, (char *)cp1, (sizeof data)); if (n < 0) { return (-1); } cp += n; cp1 += strlen((char*)cp1)+1; /* Figure out the length of the "signature" to copy over and copy it. */ n = dlen - (SPACE_FOR_VARS + n); if (n > (sizeof data) - (cp1 - (u_char *)data)) { return (-1); /* out of room! */ } /* OK */ r_memcpy(cp1, cp, n); return 0; }
static GVariant * parse_res_ns (guchar *answer, guchar *end, guchar **p) { gchar namebuf[1024]; *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf)); return g_variant_new ("(s)", namebuf); }
static char *get_name(unsigned char *msg, unsigned char *msg_end, unsigned char **msg_ptr) { int res; static char buffer[MAX_STRING_LEN]; if (-1 == (res = dn_expand(msg, msg_end, *msg_ptr, buffer, sizeof(buffer)))) return NULL; *msg_ptr += res; return buffer; }
bool dnsparse::qparse (const u_char **cpp, question *qp) { const u_char *cp = *cpp; int n = dn_expand (buf, eom, cp, qp->q_name, sizeof (qp->q_name)); if (n < 0 || n >= MAXDNAME || cp + n + 4 > eom) return false; cp += n; GETSHORT (qp->q_type, cp); GETSHORT (qp->q_class, cp); *cpp = cp; return true; }
const u_char * p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) { char name[MAXDNAME]; int n; if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0) return (NULL); if (name[0] == '\0') putc('.', file); else fputs(name, file); return (cp + n); }
/* * krb5int_dns_nextans() - get next answer record * * Sets pp to NULL if no more records. */ int krb5int_dns_nextans(struct krb5int_dns_state *ds, const unsigned char **pp, int *lenp) { int len; unsigned char *p; unsigned short ntype, nclass, rdlen; #if !HAVE_DN_SKIPNAME char host[MAXDNAME]; #endif *pp = NULL; *lenp = 0; p = ds->ptr; while (ds->nanswers--) { #if HAVE_DN_SKIPNAME len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen); #else len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, p, host, sizeof(host)); #endif if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len)) return -1; p += len; SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, ntype, out); /* Also skip 4 bytes of TTL */ SAFE_GETUINT16(ds->ansp, ds->anslen, p, 6, nclass, out); SAFE_GETUINT16(ds->ansp, ds->anslen, p, 2, rdlen, out); if (!INCR_OK(ds->ansp, ds->anslen, p, rdlen)) return -1; /* Solaris Kerberos - resync */ #if 0 if (rdlen > INT_MAX) return -1; #endif if (nclass == ds->nclass && ntype == ds->ntype) { *pp = p; *lenp = rdlen; ds->ptr = p + rdlen; return 0; } p += rdlen; } return 0; out: return -1; }
/* * krb5int_dns_expand - wrapper for dn_expand() */ int krb5int_dns_expand(struct krb5int_dns_state *ds, const unsigned char *p, char *buf, int len) { #if HAVE_NS_NAME_UNCOMPRESS return ns_name_uncompress(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, p, buf, (size_t)len); #else return dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, p, buf, len); #endif }
char * p_cdname(char *cp, char *msg, FILE *file) { char name[MAXDNAME]; int n; if ((n = dn_expand(msg, msg + 512, cp, name, sizeof(name))) < 0) return (NULL); if (name[0] == '\0') { name[0] = '.'; name[1] = '\0'; } fputs(name, file); return (cp + n); }
static GVariant * parse_res_mx (guchar *answer, guchar *end, guchar **p) { gchar namebuf[1024]; guint16 preference; GETSHORT (preference, *p); *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf)); return g_variant_new ("(qs)", preference, namebuf); }
const u_char * p_fqnname (const u_char *cp, const u_char *msg, int msglen, char *name, int namelen) { int n, newlen; if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0) return (NULL); newlen = strlen(name); if (newlen == 0 || name[newlen - 1] != '.') { if (newlen + 1 >= namelen) /* Lack space for final dot */ return (NULL); else strcpy(name + newlen, "."); } return (cp + n); }
static void fqdn_to_env(const char *name, const uint8_t *fqdn, size_t len) { size_t buf_len = strlen(name); size_t buf_size = len + buf_len + 2; const uint8_t *fqdn_end = fqdn + len; char *buf = realloc(NULL, len + buf_len + 2); memcpy(buf, name, buf_len); buf[buf_len++] = '='; int l = 1; while (l > 0 && fqdn < fqdn_end) { l = dn_expand(fqdn, fqdn_end, fqdn, &buf[buf_len], buf_size - buf_len); fqdn += l; buf_len += strlen(&buf[buf_len]); buf[buf_len++] = ' '; } buf[buf_len - 1] = '\0'; putenv(buf); }
static GVariant * parse_res_srv (guchar *answer, guchar *end, guchar **p) { gchar namebuf[1024]; guint16 priority, weight, port; GETSHORT (priority, *p); GETSHORT (weight, *p); GETSHORT (port, *p); *p += dn_expand (answer, end, *p, namebuf, sizeof (namebuf)); return g_variant_new ("(qqqs)", priority, weight, port, namebuf); }
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; }
/* SRV rdata format: * 111111 * 0123456789012345 * +----------------+ * | priority | * |----------------| * | weight | * |----------------| * | port number | * |----------------| * | | * ~ name ~ * | | * +----------------+ */ struct srv_rdata* dns_srv_parser( unsigned char* msg, unsigned char* end, unsigned char* eor, unsigned char* rdata) { struct srv_rdata* srv; unsigned short priority; unsigned short weight; unsigned short port; int len; char name[MAX_DNS_NAME]; srv=0; if ((rdata+6+1)>eor) goto error; memcpy((void*)&priority, rdata, 2); memcpy((void*)&weight, rdata+2, 2); memcpy((void*)&port, rdata+4, 2); rdata+=6; if (dn_expand(msg, end, rdata, name, MAX_DNS_NAME-1)<0) goto error; len=strlen(name); if (len>255) goto error; /* alloc enought space for the struct + null terminated name */ srv=local_malloc(sizeof(struct srv_rdata)-1+len+1); if (srv==0){ LOG(L_ERR, "ERROR: dns_srv_parser: out of memory\n"); goto error; } srv->priority=ntohs(priority); srv->weight=ntohs(weight); srv->port=ntohs(port); srv->name_len=len; memcpy(srv->name, name, srv->name_len); srv->name[srv->name_len]=0; return srv; error: if (srv) local_free(srv); return 0; }
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 */ }
/* EBL rdata format: * (see http://tools.ietf.org/html/draft-ietf-enum-branch-location-record-03) * one or several character strings: * 01234567 * +--------+ * | postion| * +-----------+ * / separator / * +-----------+ * / apex / * +----------+ * * where separator is a character string ( 8 bit len, followed by len chars) * and apex is a domain-name. */ static struct ebl_rdata* dns_ebl_parser(unsigned char* msg, unsigned char* end, unsigned char* eor, unsigned char* rdata) { struct ebl_rdata* ebl; int sep_len; int apex_len; char apex[MAX_DNS_NAME]; ebl=0; /* check if len is at least 4 chars (minimum possible): pos (1 byte) + sep. (min 1 byte) + apex (min. 2 bytes) and also check if rdata+1 (pos) + 1 (sep. len) + sep_len + 1 is ok*/ if (unlikely(((rdata+4)>eor)||((rdata+1+1+rdata[1]+2)>eor))) goto error; sep_len=rdata[1]; if (unlikely(dn_expand(msg, end, rdata+1+1+sep_len, apex, MAX_DNS_NAME-1)==-1)) goto error; apex_len=strlen(apex); /* alloc sizeof struct + space for the 2 null-terminated strings */ ebl=local_malloc(sizeof(struct ebl_rdata)-1+sep_len+1+apex_len+1); if (ebl==0){ LOG(L_ERR, "ERROR: dns_ebl_parser: out of memory\n"); goto error; } ebl->position=rdata[0]; ebl->separator=&ebl->str_table[0]; ebl->apex=ebl->separator+sep_len+1; ebl->separator_len=sep_len; ebl->apex_len=apex_len; memcpy(ebl->separator, rdata+2, sep_len); ebl->separator[sep_len]=0; memcpy(ebl->apex, apex, apex_len); ebl->apex[apex_len]=0; return ebl; error: if (ebl) local_free(ebl); return 0; }
/* * initparse * * Skip header and question section of reply. Set a pointer to the * beginning of the answer section, and prepare to iterate over * answer records. */ static int initparse(struct krb5int_dns_state *ds) { HEADER *hdr; unsigned char *p; unsigned short nqueries, nanswers; int len; #if !HAVE_DN_SKIPNAME char host[MAXDNAME]; #endif if ((size_t) ds->anslen < sizeof(HEADER)) return -1; hdr = (HEADER *)ds->ansp; p = ds->ansp; nqueries = ntohs((unsigned short)hdr->qdcount); nanswers = ntohs((unsigned short)hdr->ancount); p += sizeof(HEADER); /* * Skip query records. */ while (nqueries--) { #if HAVE_DN_SKIPNAME len = dn_skipname(p, (unsigned char *)ds->ansp + ds->anslen); #else len = dn_expand(ds->ansp, (unsigned char *)ds->ansp + ds->anslen, p, host, sizeof(host)); #endif if (len < 0 || !INCR_OK(ds->ansp, ds->anslen, p, len + 4)) return -1; p += len + 4; } ds->ptr = p; ds->nanswers = nanswers; return 0; }
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 int rrextract(u_char *msg, int msglen, u_char *rrp, u_char *dname, int namelen) { u_char *eom, *cp, *cp1, *rdatap; u_int class, type, dlen; int n; u_char data[MAXDATA*2 + SPACE_FOR_VARS]; data [(MAXDATA*2 + SPACE_FOR_VARS)-1] = EOS; cp = rrp; eom = msg + msglen; GETSHORT(dlen, cp); BOUNDS_CHECK(cp, dlen); /* Cut a bunch of stuff which we can reintroduce later. */ n = dn_expand(msg, eom, cp, (char *)data, sizeof data); if (n < 0 || n >= dlen) { return (-1); } if (nondet_int()) { return (-1); } cp += n; cp1 = data + strlen((char *)data) + 1; /* von mir eingefügt*/ assert(dlen - n <= sizeof data - (strlen((char *)data) + 1)); /* BAD */ r_memcpy(cp1, cp, dlen - n); return 0; }
/* * int res_nameinquery(name, type, class, buf, eom) * look for (name,type,class) in the query section of packet (buf,eom) * returns: * -1 : format error * 0 : not found * >0 : found * author: * paul vixie, 29may94 */ int res_nameinquery (const char *name, int type, int Class, const u_char *buf, const u_char *eom) { const u_char *cp = buf + HFIXEDSZ; int qdcount = ntohs (((HEADER*)buf)->qdcount); while (qdcount-- > 0) { char tname[MAXDNAME+1]; int n, ttype, tclass; n = dn_expand (buf, eom, cp, tname, sizeof(tname)); if (n < 0) return (-1); cp += n; ttype = _getshort (cp); cp += INT16SZ; tclass = _getshort (cp); cp += INT16SZ; if (ttype == type && tclass == Class && !stricmp(tname,name)) return (1); } return (0); }
int getsrv(const char *name,struct srventry **list) { unsigned char answer[2048]; int r,srvcount=0; unsigned char *pt,*emsg; u16 count,dlen; HEADER *header=(HEADER *)answer; *list=NULL; r=res_query(name,C_IN,T_SRV,answer,2048); if(r<sizeof(HEADER) || r>2048) return -1; if(header->rcode==NOERROR && (count=ntohs(header->ancount))) { int i,rc; emsg=&answer[r]; pt=&answer[sizeof(HEADER)]; /* Skip over the query */ rc=dn_skipname(pt,emsg); if(rc==-1) goto fail; pt+=rc+QFIXEDSZ; while(count-->0 && pt<emsg) { struct srventry *srv=NULL; u16 type,class; srv=realloc(*list,(srvcount+1)*sizeof(struct srventry)); if(!srv) goto fail; *list=srv; memset(&(*list)[srvcount],0,sizeof(struct srventry)); srv=&(*list)[srvcount]; srvcount++; rc=dn_skipname(pt,emsg); /* the name we just queried for */ if(rc==-1) goto fail; pt+=rc; /* Truncated message? */ if((emsg-pt)<16) goto fail; type=*pt++ << 8; type|=*pt++; /* We asked for SRV and got something else !? */ if(type!=T_SRV) goto fail; class=*pt++ << 8; class|=*pt++; /* We asked for IN and got something else !? */ if(class!=C_IN) goto fail; pt+=4; /* ttl */ dlen=*pt++ << 8; dlen|=*pt++; srv->priority=*pt++ << 8; srv->priority|=*pt++; srv->weight=*pt++ << 8; srv->weight|=*pt++; srv->port=*pt++ << 8; srv->port|=*pt++; /* Get the name. 2782 doesn't allow name compression, but dn_expand still works to pull the name out of the packet. */ rc=dn_expand(answer,emsg,pt,srv->target,MAXDNAME); if(rc==1 && srv->target[0]==0) /* "." */ goto noanswer; if(rc==-1) goto fail; pt+=rc; /* Corrupt packet? */ if(dlen!=rc+6) goto fail; #if 0 printf("count=%d\n",srvcount); printf("priority=%d\n",srv->priority); printf("weight=%d\n",srv->weight); printf("port=%d\n",srv->port); printf("target=%s\n",srv->target); #endif } /* Now we have an array of all the srv records. */ /* Order by priority */ qsort(*list,srvcount,sizeof(struct srventry),priosort); /* For each priority, move the zero-weighted items first. */ for(i=0; i<srvcount; i++) { int j; for(j=i; j<srvcount && (*list)[i].priority==(*list)[j].priority; j++) { if((*list)[j].weight==0) { /* Swap j with i */ if(j!=i) { struct srventry temp; memcpy(&temp,&(*list)[j],sizeof(struct srventry)); memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry)); memcpy(&(*list)[i],&temp,sizeof(struct srventry)); } break; } } } /* Run the RFC-2782 weighting algorithm. We don't need very high quality randomness for this, so regular libc srand/rand is sufficient. */ srand(time(NULL)*getpid()); for(i=0; i<srvcount; i++) { int j; float prio_count=0,chose; for(j=i; j<srvcount && (*list)[i].priority==(*list)[j].priority; j++) { prio_count+=(*list)[j].weight; (*list)[j].run_count=prio_count; } chose=prio_count*rand()/RAND_MAX; for(j=i; j<srvcount && (*list)[i].priority==(*list)[j].priority; j++) { if(chose<=(*list)[j].run_count) { /* Swap j with i */ if(j!=i) { struct srventry temp; memcpy(&temp,&(*list)[j],sizeof(struct srventry)); memcpy(&(*list)[j],&(*list)[i],sizeof(struct srventry)); memcpy(&(*list)[i],&temp,sizeof(struct srventry)); } break; } } } }
int afsconf_LookupServer(const char *service, const char *protocol, const char *cellName, unsigned short afsdbPort, afs_uint32 *cellHostAddrs, char cellHostNames[][MAXHOSTCHARS], unsigned short ports[], unsigned short ipRanks[], int *numServers, int *ttl, char **arealCellName) { int code = 0; int r; int len; unsigned char answer[4096]; unsigned char *p; char *dotcellname = NULL; char *realCellName; char host[256]; int server_num = 0; int minttl = 0; int try_init = 0; int dnstype = 0; int pass = 0; char *IANAname = (char *) afsconf_FindIANAName(service); int tservice = afsconf_FindService(service); realCellName = NULL; *numServers = 0; *ttl = 0; if (tservice <= 0 || !IANAname) return AFSCONF_NOTFOUND; /* service not found */ if (strchr(cellName,'.')) pass += 2; #ifdef HAVE_RES_RETRANSRETRY if ((_res.options & RES_INIT) == 0 && res_init() == -1) return (0); /* * Rx timeout is typically 56 seconds; limit user experience to * similar timeout */ _res.retrans = 18; _res.retry = 3; #endif retryafsdb: r = -1; switch (pass) { case 0: dnstype = T_SRV; r = asprintf(&dotcellname, "_%s._%s.%s.", IANAname, protocol, cellName); break; case 1: dnstype = T_AFSDB; r = asprintf(&dotcellname, "%s.", cellName); break; case 2: dnstype = T_SRV; r = asprintf(&dotcellname, "_%s._%s.%s", IANAname, protocol, cellName); break; case 3: dnstype = T_AFSDB; r = asprintf(&dotcellname, "%s", cellName); break; } if (r < 0 || dotcellname == NULL) goto findservererror; LOCK_GLOBAL_MUTEX; len = res_search(dotcellname, C_IN, dnstype, answer, sizeof(answer)); UNLOCK_GLOBAL_MUTEX; if (dotcellname != NULL) { free(dotcellname); dotcellname = NULL; } if (len < 0) { if (try_init < 1) { try_init++; res_init(); goto retryafsdb; } if (pass < 3) { pass++; goto retryafsdb; } else { code = AFSCONF_NOTFOUND; goto findservererror; } } p = answer + sizeof(HEADER); /* Skip header */ code = dn_expand(answer, answer + len, p, host, sizeof(host)); if (code < 0) { code = AFSCONF_NOTFOUND; goto findservererror; } p += code + QFIXEDSZ; /* Skip name */ while (p < answer + len) { int type, ttl, size; code = dn_expand(answer, answer + len, p, host, sizeof(host)); if (code < 0) { code = AFSCONF_NOTFOUND; goto findservererror; } p += code; /* Skip the name */ type = (p[0] << 8) | p[1]; p += 4; /* Skip type and class */ ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; p += 4; /* Skip the TTL */ size = (p[0] << 8) | p[1]; p += 2; /* Skip the size */ if (type == T_AFSDB) { struct hostent *he; short afsdb_type; afsdb_type = (p[0] << 8) | p[1]; if (afsdb_type == 1) { /* * We know this is an AFSDB record for our cell, of the * right AFSDB type. Write down the true cell name that * the resolver gave us above. */ if (!realCellName) realCellName = strdup(host); } code = dn_expand(answer, answer + len, p + 2, host, sizeof(host)); if (code < 0) { code = AFSCONF_NOTFOUND; goto findservererror; } if ((afsdb_type == 1) && (server_num < MAXHOSTSPERCELL) && /* Do we want to get TTL data for the A record as well? */ (he = gethostbyname(host))) { if (he->h_addrtype == AF_INET) { afs_uint32 ipaddr; memcpy(&ipaddr, he->h_addr, sizeof(ipaddr)); cellHostAddrs[server_num] = ipaddr; ports[server_num] = afsdbPort; ipRanks[server_num] = 0; strncpy(cellHostNames[server_num], host, sizeof(cellHostNames[server_num])); server_num++; if (!minttl || ttl < minttl) minttl = ttl; } } } if (type == T_SRV) { struct hostent *he; /* math here: _ is 1, _ ._ is 3, _ ._ . is 4. then the domain. */ if ((strncmp(host + 1, IANAname, strlen(IANAname)) == 0) && (strncmp(host + strlen(IANAname) + 3, protocol, strlen(protocol)) == 0)) { if (!realCellName) realCellName = strdup(host + strlen(IANAname) + strlen(protocol) + 4); } code = dn_expand(answer, answer + len, p + 6, host, sizeof(host)); if (code < 0) { code = AFSCONF_NOTFOUND; goto findservererror; } if ((server_num < MAXHOSTSPERCELL) && /* Do we want to get TTL data for the A record as well? */ (he = gethostbyname(host))) { if (he->h_addrtype == AF_INET) { afs_uint32 ipaddr; memcpy(&ipaddr, he->h_addr, sizeof(ipaddr)); cellHostAddrs[server_num] = ipaddr; ipRanks[server_num] = (p[0] << 8) | p[1]; ports[server_num] = htons((p[4] << 8) | p[5]); /* weight = (p[2] << 8) | p[3]; */ strncpy(cellHostNames[server_num], host, sizeof(cellHostNames[server_num])); server_num++; if (!minttl || ttl < minttl) minttl = ttl; } } } p += size; } if (server_num == 0) { /* No AFSDB or SRV records */ code = AFSCONF_NOTFOUND; goto findservererror; } if (realCellName) { /* Convert the real cell name to lowercase */ for (p = (unsigned char *)realCellName; *p; p++) *p = tolower(*p); } *numServers = server_num; *ttl = minttl ? (time(0) + minttl) : 0; if ( *numServers > 0 ) { code = 0; *arealCellName = realCellName; } else code = AFSCONF_NOTFOUND; findservererror: if (code && realCellName) free(realCellName); return code; }
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; }
bool HHVM_FUNCTION(getmxrr, const String& hostname, VRefParam mxhostsRef, VRefParam weightsRef /* = null */) { IOStatusHelper io("dns_get_mx", hostname.data()); int count, qdc; unsigned short type, weight; unsigned char ans[MAXPACKET]; char buf[MAXHOSTNAMELEN]; unsigned char *cp, *end; Array mxhosts; Array weights; SCOPE_EXIT { mxhostsRef = mxhosts; weightsRef = weights; }; /* Go! */ struct __res_state *res; res = ResolverInit::s_res.get()->getResolver(); if (res == NULL) { return false; } int i = res_nsearch(res, hostname.data(), C_IN, DNS_T_MX, (unsigned char*)&ans, sizeof(ans)); if (i < 0) { res_nclose(res); php_dns_free_res(res); return false; } if (i > (int)sizeof(ans)) { i = sizeof(ans); } HEADER *hp = (HEADER *)&ans; cp = (unsigned char *)&ans + HFIXEDSZ; end = (unsigned char *)&ans +i; for (qdc = ntohs((unsigned short)hp->qdcount); qdc--; cp += i + QFIXEDSZ) { if ((i = dn_skipname(cp, end)) < 0 ) { res_nclose(res); php_dns_free_res(res); return false; } } count = ntohs((unsigned short)hp->ancount); while (--count >= 0 && cp < end) { if ((i = dn_skipname(cp, end)) < 0 ) { res_nclose(res); php_dns_free_res(res); return false; } cp += i; GETSHORT(type, cp); cp += INT16SZ + INT32SZ; GETSHORT(i, cp); if (type != DNS_T_MX) { cp += i; continue; } GETSHORT(weight, cp); if ((i = dn_expand(ans, end, cp, buf, sizeof(buf)-1)) < 0) { res_nclose(res); php_dns_free_res(res); return false; } cp += i; mxhosts.append(String(buf, CopyString)); weights.append(weight); } res_nclose(res); php_dns_free_res(res); return true; }
static unsigned char *php_parserr(unsigned char *cp, unsigned char* end, querybuf *answer, int type_to_fetch, bool store, Array &subarray) { unsigned short type, cls ATTRIBUTE_UNUSED, dlen; unsigned long ttl; int64_t n, i; unsigned short s; unsigned char *tp, *p; char name[MAXHOSTNAMELEN]; int have_v6_break = 0, in_v6_break = 0; n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, sizeof(name) - 2); if (n < 0) { return NULL; } cp += n; CHECKCP(10); GETSHORT(type, cp); GETSHORT(cls, cp); GETLONG(ttl, cp); GETSHORT(dlen, cp); CHECKCP(dlen); if (type_to_fetch != T_ANY && type != type_to_fetch) { cp += dlen; return cp; } if (!store) { cp += dlen; return cp; } subarray.set(s_host, String(name, CopyString)); switch (type) { case DNS_T_A: CHECKCP(4); subarray.set(s_type, s_A); snprintf(name, sizeof(name), "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]); subarray.set(s_ip, String(name, CopyString)); cp += dlen; break; case DNS_T_MX: CHECKCP(2); subarray.set(s_type, s_MX); GETSHORT(n, cp); subarray.set(s_pri, n); /* no break; */ case DNS_T_CNAME: if (type == DNS_T_CNAME) { subarray.set(s_type, s_CNAME); } /* no break; */ case DNS_T_NS: if (type == DNS_T_NS) { subarray.set(s_type, s_NS); } /* no break; */ case DNS_T_PTR: if (type == DNS_T_PTR) { subarray.set(s_type, s_PTR); } n = dn_expand(answer->qb2, answer->qb2+65536, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_target, String(name, CopyString)); break; case DNS_T_HINFO: /* See RFC 1010 for values */ subarray.set(s_type, s_HINFO); CHECKCP(1); n = *cp & 0xFF; cp++; CHECKCP(n); subarray.set(s_cpu, String((const char *)cp, n, CopyString)); cp += n; CHECKCP(1); n = *cp & 0xFF; cp++; CHECKCP(n); subarray.set(s_os, String((const char *)cp, n, CopyString)); cp += n; break; case DNS_T_TXT: { int l1 = 0, l2 = 0; String s = String(dlen, ReserveString); tp = (unsigned char *)s.bufferSlice().ptr; while (l1 < dlen) { n = cp[l1]; if ((n + l1) > dlen) { // bad record, don't set anything break; } memcpy(tp + l1 , cp + l1 + 1, n); l1 = l1 + n + 1; l2 = l2 + n; } s.setSize(l2); cp += dlen; subarray.set(s_type, s_TXT); subarray.set(s_txt, s); break; } case DNS_T_SOA: subarray.set(s_type, s_SOA); n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2); if (n < 0) { return NULL; } cp += n; subarray.set(s_mname, String(name, CopyString)); n = dn_expand(answer->qb2, end, cp, name, (sizeof name) -2); if (n < 0) { return NULL; } cp += n; subarray.set(s_rname, String(name, CopyString)); CHECKCP(5*4); GETLONG(n, cp); subarray.set(s_serial, n); GETLONG(n, cp); subarray.set(s_refresh, n); GETLONG(n, cp); subarray.set(s_retry, n); GETLONG(n, cp); subarray.set(s_expire, n); GETLONG(n, cp); subarray.set(s_minimum_ttl, n); break; case DNS_T_AAAA: tp = (unsigned char *)name; CHECKCP(8*2); for (i = 0; i < 8; i++) { GETSHORT(s, cp); if (s != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } tp += sprintf((char *)tp, "%x", s); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } } if (have_v6_break && in_v6_break) { tp[0] = ':'; tp++; } tp[0] = '\0'; subarray.set(s_type, s_AAAA); subarray.set(s_ipv6, String(name, CopyString)); break; case DNS_T_A6: p = cp; subarray.set(s_type, s_A6); CHECKCP(1); n = ((int)cp[0]) & 0xFF; cp++; subarray.set(s_masklen, n); tp = (unsigned char *)name; if (n > 15) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } if (n % 16 > 8) { /* Partial short */ if (cp[0] != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } sprintf((char *)tp, "%x", cp[0] & 0xFF); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } cp++; } for (i = (n + 8)/16; i < 8; i++) { CHECKCP(2); GETSHORT(s, cp); if (s != 0) { if (tp > (u_char *)name) { in_v6_break = 0; tp[0] = ':'; tp++; } tp += sprintf((char*)tp,"%x",s); } else { if (!have_v6_break) { have_v6_break = 1; in_v6_break = 1; tp[0] = ':'; tp++; } else if (!in_v6_break) { tp[0] = ':'; tp++; tp[0] = '0'; tp++; } } } if (have_v6_break && in_v6_break) { tp[0] = ':'; tp++; } tp[0] = '\0'; subarray.set(s_ipv6, String(name, CopyString)); if (cp < p + dlen) { n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_chain, String(name, CopyString)); } break; case DNS_T_SRV: CHECKCP(3*2); subarray.set(s_type, s_SRV); GETSHORT(n, cp); subarray.set(s_pri, n); GETSHORT(n, cp); subarray.set(s_weight, n); GETSHORT(n, cp); subarray.set(s_port, n); n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_target, String(name, CopyString)); break; case DNS_T_NAPTR: CHECKCP(2*2); subarray.set(s_type, s_NAPTR); GETSHORT(n, cp); subarray.set(s_order, n); GETSHORT(n, cp); subarray.set(s_pref, n); CHECKCP(1); n = (cp[0] & 0xFF); ++cp; CHECKCP(n); subarray.set(s_flags, String((const char *)cp, n, CopyString)); cp += n; CHECKCP(1); n = (cp[0] & 0xFF); ++cp; CHECKCP(n); subarray.set(s_services, String((const char *)cp, n, CopyString)); cp += n; CHECKCP(1); n = (cp[0] & 0xFF); ++cp; CHECKCP(n); subarray.set(s_regex, String((const char *)cp, n, CopyString)); cp += n; n = dn_expand(answer->qb2, end, cp, name, (sizeof name) - 2); if (n < 0) { return NULL; } cp += n; subarray.set(s_replacement, String(name, CopyString)); break; default: cp += dlen; } subarray.set(s_class, s_IN); subarray.set(s_ttl, (int)ttl); return cp; }