#include "ares_private.h"
#include "ares_data.h"
int
ares_parse_soa_reply(
const
unsigned
char
*abuf,
int
alen_int,
struct
ares_soa_reply **soa_out)
{
ares_status_t status;
size_t
alen;
struct
ares_soa_reply *soa = NULL;
ares_dns_record_t *dnsrec = NULL;
size_t
i;
*soa_out = NULL;
if
(alen_int < 0) {
return
ARES_EBADRESP;
}
alen = (
size_t
)alen_int;
status = ares_dns_parse(abuf, alen, 0, &dnsrec);
if
(status != ARES_SUCCESS) {
goto
done;
}
if
(ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER) == 0) {
status = ARES_EBADRESP;
goto
done;
}
for
(i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) {
const
ares_dns_rr_t *rr =
ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i);
if
(rr == NULL) {
status = ARES_EBADRESP;
goto
done;
}
if
(ares_dns_rr_get_class(rr) != ARES_CLASS_IN ||
ares_dns_rr_get_type(rr) != ARES_REC_TYPE_SOA) {
continue
;
}
soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY);
if
(soa == NULL) {
status = ARES_ENOMEM;
goto
done;
}
soa->serial = ares_dns_rr_get_u32(rr, ARES_RR_SOA_SERIAL);
soa->refresh = ares_dns_rr_get_u32(rr, ARES_RR_SOA_REFRESH);
soa->retry = ares_dns_rr_get_u32(rr, ARES_RR_SOA_RETRY);
soa->expire = ares_dns_rr_get_u32(rr, ARES_RR_SOA_EXPIRE);
soa->minttl = ares_dns_rr_get_u32(rr, ARES_RR_SOA_MINIMUM);
soa->nsname = ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_SOA_MNAME));
if
(soa->nsname == NULL) {
status = ARES_ENOMEM;
goto
done;
}
soa->hostmaster = ares_strdup(ares_dns_rr_get_str(rr, ARES_RR_SOA_RNAME));
if
(soa->hostmaster == NULL) {
status = ARES_ENOMEM;
goto
done;
}
break
;
}
if
(soa == NULL) {
status = ARES_EBADRESP;
}
done:
if
(status != ARES_SUCCESS) {
ares_free_data(soa);
if
(status == ARES_EBADNAME) {
status = ARES_EBADRESP;
}
}
else
{
*soa_out = soa;
}
ares_dns_record_destroy(dnsrec);
return
(
int
)status;
}