/* Copyright 1998 by the Massachusetts Institute of Technology. * * Permission to use, copy, modify, and distribute this * software and its documentation for any purpose and without * fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * M.I.T. makes no representations about the suitability of * this software for any purpose. It is provided "as is" * without express or implied warranty. */#include "ares_setup.h"#ifdef HAVE_SYS_SOCKET_H# include <sys/socket.h>#endif#ifdef HAVE_NETINET_IN_H# include <netinet/in.h>#endif#ifdef HAVE_NETDB_H# include <netdb.h>#endif#ifdef HAVE_ARPA_NAMESER_H# include <arpa/nameser.h>#else# include "nameser.h"#endif#ifdef HAVE_ARPA_NAMESER_COMPAT_H# include <arpa/nameser_compat.h>#endif#ifdef HAVE_STRINGS_H# include <strings.h>#endif#include <stdlib.h>#include <string.h>#include "ares.h"#include "ares_dns.h"#include "ares_private.h"intares_parse_ptr_reply(constunsignedchar*abuf,intalen,constvoid*addr,intaddrlen,intfamily,structhostent**host){unsignedintqdcount,ancount;intstatus,i,rr_type,rr_class,rr_len;longlen;constunsignedchar*aptr;char*ptrname,*hostname,*rr_name,*rr_data;structhostent*hostent;intaliascnt=0;intalias_alloc=8;char**aliases;/* Set *host to NULL for all failure cases. */*host=NULL;/* Give up if abuf doesn't have room for a header. */if(alen<HFIXEDSZ)returnARES_EBADRESP;/* Fetch the question and answer count from the header. */qdcount=DNS_HEADER_QDCOUNT(abuf);ancount=DNS_HEADER_ANCOUNT(abuf);if(qdcount!=1)returnARES_EBADRESP;/* Expand the name from the question, and skip past the question. */aptr=abuf+HFIXEDSZ;status=ares__expand_name_for_response(aptr,abuf,alen,&ptrname,&len);if(status!=ARES_SUCCESS)returnstatus;if(aptr+len+QFIXEDSZ>abuf+alen){free(ptrname);returnARES_EBADRESP;}aptr+=len+QFIXEDSZ;/* Examine each answer resource record (RR) in turn. */hostname=NULL;aliases=malloc(alias_alloc*sizeof(char*));if(!aliases){free(ptrname);returnARES_ENOMEM;}for(i=0;i<(int)ancount;i++){/* Decode the RR up to the data field. */status=ares__expand_name_for_response(aptr,abuf,alen,&rr_name,&len);if(status!=ARES_SUCCESS)break;aptr+=len;if(aptr+RRFIXEDSZ>abuf+alen){free(rr_name);status=ARES_EBADRESP;break;}rr_type=DNS_RR_TYPE(aptr);rr_class=DNS_RR_CLASS(aptr);rr_len=DNS_RR_LEN(aptr);aptr+=RRFIXEDSZ;if(rr_class==C_IN&&rr_type==T_PTR&&strcasecmp(rr_name,ptrname)==0){/* Decode the RR data and set hostname to it. */status=ares__expand_name_for_response(aptr,abuf,alen,&rr_data,&len);if(status!=ARES_SUCCESS){free(rr_name);break;}if(hostname)free(hostname);hostname=rr_data;aliases[aliascnt]=malloc((strlen(rr_data)+1)*sizeof(char));if(!aliases[aliascnt]){free(rr_name);status=ARES_ENOMEM;break;}strncpy(aliases[aliascnt],rr_data,strlen(rr_data)+1);aliascnt++;if(aliascnt>=alias_alloc){char**ptr;alias_alloc*=2;ptr=realloc(aliases,alias_alloc*sizeof(char*));if(!ptr){free(rr_name);status=ARES_ENOMEM;break;}aliases=ptr;}}if(rr_class==C_IN&&rr_type==T_CNAME){/* Decode the RR data and replace ptrname with it. */status=ares__expand_name_for_response(aptr,abuf,alen,&rr_data,&len);if(status!=ARES_SUCCESS){free(rr_name);break;}free(ptrname);ptrname=rr_data;}free(rr_name);aptr+=rr_len;if(aptr>abuf+alen){status=ARES_EBADRESP;break;}}if(status==ARES_SUCCESS&&!hostname)status=ARES_ENODATA;if(status==ARES_SUCCESS){/* We got our answer. Allocate memory to build the host entry. */hostent=malloc(sizeof(structhostent));if(hostent){hostent->h_addr_list=malloc(2*sizeof(char*));if(hostent->h_addr_list){hostent->h_addr_list[0]=malloc(addrlen);if(hostent->h_addr_list[0]){hostent->h_aliases=malloc((aliascnt+1)*sizeof(char*));if(hostent->h_aliases){/* Fill in the hostent and return successfully. */hostent->h_name=hostname;for(i=0;i<aliascnt;i++)hostent->h_aliases[i]=aliases[i];hostent->h_aliases[aliascnt]=NULL;hostent->h_addrtype=family;hostent->h_length=addrlen;memcpy(hostent->h_addr_list[0],addr,addrlen);hostent->h_addr_list[1]=NULL;*host=hostent;free(aliases);free(ptrname);returnARES_SUCCESS;}free(hostent->h_addr_list[0]);}free(hostent->h_addr_list);}free(hostent);}status=ARES_ENOMEM;}for(i=0;i<aliascnt;i++)if(aliases[i])free(aliases[i]);free(aliases);if(hostname)free(hostname);free(ptrname);returnstatus;}