123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- #include "ares_setup.h"
- #ifdef HAVE_NETINET_IN_H
- # include <netinet/in.h>
- #endif
- #ifdef HAVE_NETDB_H
- # include <netdb.h>
- #endif
- #ifdef HAVE_ARPA_INET_H
- # include <arpa/inet.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
- #include "ares.h"
- #include "ares_dns.h"
- #include "ares_data.h"
- #include "ares_private.h"
- int
- ares_parse_mx_reply (const unsigned char *abuf, int alen,
- struct ares_mx_reply **mx_out)
- {
- unsigned int qdcount, ancount, i;
- const unsigned char *aptr, *vptr;
- int status, rr_type, rr_class, rr_len, rr_ttl;
- long len;
- char *hostname = NULL, *rr_name = NULL;
- struct ares_mx_reply *mx_head = NULL;
- struct ares_mx_reply *mx_last = NULL;
- struct ares_mx_reply *mx_curr;
-
- *mx_out = NULL;
-
- if (alen < HFIXEDSZ)
- return ARES_EBADRESP;
-
- qdcount = DNS_HEADER_QDCOUNT (abuf);
- ancount = DNS_HEADER_ANCOUNT (abuf);
- if (qdcount != 1)
- return ARES_EBADRESP;
- if (ancount == 0)
- return ARES_ENODATA;
-
- aptr = abuf + HFIXEDSZ;
- status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
- if (status != ARES_SUCCESS)
- return status;
- if (aptr + len + QFIXEDSZ > abuf + alen)
- {
- ares_free (hostname);
- return ARES_EBADRESP;
- }
- aptr += len + QFIXEDSZ;
-
- for (i = 0; i < ancount; i++)
- {
-
- status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
- if (status != ARES_SUCCESS)
- {
- break;
- }
- aptr += len;
- if (aptr + RRFIXEDSZ > abuf + alen)
- {
- status = ARES_EBADRESP;
- break;
- }
- rr_type = DNS_RR_TYPE (aptr);
- rr_class = DNS_RR_CLASS (aptr);
- rr_len = DNS_RR_LEN (aptr);
- rr_ttl = DNS_RR_TTL (aptr);
- aptr += RRFIXEDSZ;
- if (aptr + rr_len > abuf + alen)
- {
- status = ARES_EBADRESP;
- break;
- }
-
- if (rr_class == C_IN && rr_type == T_MX)
- {
-
- if (rr_len < 2)
- {
- status = ARES_EBADRESP;
- break;
- }
-
- mx_curr = ares_malloc_data(ARES_DATATYPE_MX_REPLY);
- if (!mx_curr)
- {
- status = ARES_ENOMEM;
- break;
- }
- if (mx_last)
- {
- mx_last->next = mx_curr;
- }
- else
- {
- mx_head = mx_curr;
- }
- mx_last = mx_curr;
- vptr = aptr;
- mx_curr->priority = DNS__16BIT(vptr);
- mx_curr->ttl = rr_ttl;
- vptr += sizeof(unsigned short);
- status = ares_expand_name (vptr, abuf, alen, &mx_curr->host, &len);
- if (status != ARES_SUCCESS)
- break;
- }
-
- ares_free (rr_name);
- rr_name = NULL;
-
- aptr += rr_len;
- }
- if (hostname)
- ares_free (hostname);
- if (rr_name)
- ares_free (rr_name);
-
- if (status != ARES_SUCCESS)
- {
- if (mx_head)
- ares_free_data (mx_head);
- return status;
- }
-
- *mx_out = mx_head;
- return ARES_SUCCESS;
- }
|