• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* Copyright 1998 by the Massachusetts Institute of Technology.
3  * Copyright (C) 2012 Marko Kreen <markokr@gmail.com>
4  *
5  * Permission to use, copy, modify, and distribute this
6  * software and its documentation for any purpose and without
7  * fee is hereby granted, provided that the above copyright
8  * notice appear in all copies and that both that copyright
9  * notice and this permission notice appear in supporting
10  * documentation, and that the name of M.I.T. not be used in
11  * advertising or publicity pertaining to distribution of the
12  * software without specific, written prior permission.
13  * M.I.T. makes no representations about the suitability of
14  * this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  */
17 
18 #include "ares_setup.h"
19 
20 #ifdef HAVE_NETINET_IN_H
21 #  include <netinet/in.h>
22 #endif
23 #ifdef HAVE_NETDB_H
24 #  include <netdb.h>
25 #endif
26 #ifdef HAVE_ARPA_INET_H
27 #  include <arpa/inet.h>
28 #endif
29 
30 #include "ares_nameser.h"
31 
32 #include "ares.h"
33 #include "ares_dns.h"
34 #include "ares_data.h"
35 #include "ares_private.h"
36 
37 int
ares_parse_soa_reply(const unsigned char * abuf,int alen,struct ares_soa_reply ** soa_out)38 ares_parse_soa_reply(const unsigned char *abuf, int alen,
39 		     struct ares_soa_reply **soa_out)
40 {
41   const unsigned char *aptr;
42   long len;
43   char *qname = NULL, *rr_name = NULL;
44   struct ares_soa_reply *soa = NULL;
45   int qdcount, ancount, qclass;
46   int status, i, rr_type, rr_class, rr_len;
47 
48   if (alen < HFIXEDSZ)
49     return ARES_EBADRESP;
50 
51   /* parse message header */
52   qdcount = DNS_HEADER_QDCOUNT(abuf);
53   ancount = DNS_HEADER_ANCOUNT(abuf);
54 
55   if (qdcount != 1)
56     return ARES_EBADRESP;
57   if (ancount == 0)
58     return ARES_EBADRESP;
59 
60   aptr = abuf + HFIXEDSZ;
61 
62   /* query name */
63   status = ares__expand_name_for_response(aptr, abuf, alen, &qname, &len, 0);
64   if (status != ARES_SUCCESS)
65     goto failed_stat;
66 
67   if (alen <= len + HFIXEDSZ + 1)
68     goto failed;
69   aptr += len;
70 
71   qclass = DNS_QUESTION_TYPE(aptr);
72 
73   /* skip qtype & qclass */
74   if (aptr + QFIXEDSZ > abuf + alen)
75     goto failed;
76   aptr += QFIXEDSZ;
77 
78   /* qclass of SOA with multiple answers */
79   if (qclass == T_SOA && ancount > 1)
80     goto failed;
81 
82   /* examine all the records, break and return if found soa */
83   for (i = 0; i < ancount; i++)
84   {
85     rr_name = NULL;
86     status  = ares__expand_name_for_response (aptr, abuf, alen, &rr_name, &len, 0);
87     if (status != ARES_SUCCESS)
88      {
89       ares_free(rr_name);
90       goto failed_stat;
91      }
92 
93     aptr += len;
94     if ( aptr + RRFIXEDSZ > abuf + alen )
95     {
96       ares_free(rr_name);
97       status = ARES_EBADRESP;
98       goto failed_stat;
99     }
100     rr_type = DNS_RR_TYPE( aptr );
101     rr_class = DNS_RR_CLASS( aptr );
102     rr_len = DNS_RR_LEN( aptr );
103     aptr += RRFIXEDSZ;
104     if (aptr + rr_len > abuf + alen)
105       {
106         ares_free(rr_name);
107         status = ARES_EBADRESP;
108         goto failed_stat;
109       }
110     if ( rr_class == C_IN && rr_type == T_SOA )
111     {
112       /* allocate result struct */
113       soa = ares_malloc_data(ARES_DATATYPE_SOA_REPLY);
114       if (!soa)
115         {
116           ares_free(rr_name);
117           status = ARES_ENOMEM;
118           goto failed_stat;
119         }
120 
121       /* nsname */
122       status = ares__expand_name_for_response(aptr, abuf, alen, &soa->nsname,
123                                                &len, 0);
124       if (status != ARES_SUCCESS)
125        {
126         ares_free(rr_name);
127         goto failed_stat;
128        }
129       aptr += len;
130 
131       /* hostmaster */
132       status = ares__expand_name_for_response(aptr, abuf, alen,
133                                                &soa->hostmaster, &len, 0);
134       if (status != ARES_SUCCESS)
135        {
136         ares_free(rr_name);
137         goto failed_stat;
138        }
139       aptr += len;
140 
141       /* integer fields */
142       if (aptr + 5 * 4 > abuf + alen)
143        {
144         ares_free(rr_name);
145         goto failed;
146        }
147       soa->serial = DNS__32BIT(aptr + 0 * 4);
148       soa->refresh = DNS__32BIT(aptr + 1 * 4);
149       soa->retry = DNS__32BIT(aptr + 2 * 4);
150       soa->expire = DNS__32BIT(aptr + 3 * 4);
151       soa->minttl = DNS__32BIT(aptr + 4 * 4);
152 
153       ares_free(qname);
154       ares_free(rr_name);
155 
156       *soa_out = soa;
157 
158       return ARES_SUCCESS;
159     }
160     aptr += rr_len;
161 
162     ares_free(rr_name);
163 
164     if (aptr > abuf + alen)
165       goto failed_stat;
166   }
167   /* no SOA record found */
168   status = ARES_EBADRESP;
169   goto failed_stat;
170 failed:
171   status = ARES_EBADRESP;
172 
173 failed_stat:
174   if (soa)
175     ares_free_data(soa);
176   if (qname)
177     ares_free(qname);
178   return status;
179 }
180