1
2 /* Copyright 1998 by the Massachusetts Institute of Technology.
3 * Copyright (C) 2009 by Jakub Hrozek <jhrozek@redhat.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 /* AIX portability check */
38 #ifndef T_URI
39 # define T_URI 256 /* uri selection */
40 #endif
41
42 int
ares_parse_uri_reply(const unsigned char * abuf,int alen,struct ares_uri_reply ** uri_out)43 ares_parse_uri_reply (const unsigned char *abuf, int alen,
44 struct ares_uri_reply **uri_out)
45 {
46 unsigned int qdcount, ancount, i;
47 const unsigned char *aptr, *vptr;
48 int status, rr_type, rr_class, rr_len, rr_ttl;
49 long len;
50 char *uri_str = NULL, *rr_name = NULL;
51 struct ares_uri_reply *uri_head = NULL;
52 struct ares_uri_reply *uri_last = NULL;
53 struct ares_uri_reply *uri_curr;
54
55 /* Set *uri_out to NULL for all failure cases. */
56 *uri_out = NULL;
57
58 /* Give up if abuf doesn't have room for a header. */
59 if (alen < HFIXEDSZ){
60 return ARES_EBADRESP;
61 }
62
63 /* Fetch the question and answer count from the header. */
64 qdcount = DNS_HEADER_QDCOUNT (abuf);
65 ancount = DNS_HEADER_ANCOUNT (abuf);
66 if (qdcount != 1) {
67 return ARES_EBADRESP;
68 }
69 if (ancount == 0) {
70 return ARES_ENODATA;
71 }
72 /* Expand the name from the question, and skip past the question. */
73 aptr = abuf + HFIXEDSZ;
74
75 status = ares_expand_name (aptr, abuf, alen, &uri_str, &len);
76 if (status != ARES_SUCCESS){
77 return status;
78 }
79 if (aptr + len + QFIXEDSZ > abuf + alen)
80 {
81 ares_free (uri_str);
82 return ARES_EBADRESP;
83 }
84 aptr += len + QFIXEDSZ;
85
86 /* Examine each answer resource record (RR) in turn. */
87 for (i = 0; i < ancount; i++)
88 {
89 /* Decode the RR up to the data field. */
90 status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
91 if (status != ARES_SUCCESS)
92 {
93 break;
94 }
95 aptr += len;
96 if (aptr + RRFIXEDSZ > abuf + alen)
97 {
98 status = ARES_EBADRESP;
99 break;
100 }
101
102 rr_type = DNS_RR_TYPE (aptr);
103 rr_class = DNS_RR_CLASS (aptr);
104 rr_ttl = DNS_RR_TTL(aptr);
105 rr_len = DNS_RR_LEN (aptr);
106 aptr += RRFIXEDSZ;
107
108 if (aptr + rr_len > abuf + alen)
109 {
110 status = ARES_EBADRESP;
111 break;
112 }
113
114 /* Check if we are really looking at a URI record */
115 if (rr_class == C_IN && rr_type == T_URI)
116 {
117 /* parse the URI record itself */
118 if (rr_len < 5)
119 {
120 status = ARES_EBADRESP;
121 break;
122 }
123 /* Allocate storage for this URI answer appending it to the list */
124 uri_curr = ares_malloc_data(ARES_DATATYPE_URI_REPLY);
125 if (!uri_curr)
126 {
127 status = ARES_ENOMEM;
128 break;
129 }
130 if (uri_last)
131 {
132 uri_last->next = uri_curr;
133 }
134 else
135 {
136 uri_head = uri_curr;
137 }
138 uri_last = uri_curr;
139
140 vptr = aptr;
141 uri_curr->priority = DNS__16BIT(vptr);
142 vptr += sizeof(unsigned short);
143 uri_curr->weight = DNS__16BIT(vptr);
144 vptr += sizeof(unsigned short);
145 uri_curr->uri = (char *)ares_malloc(rr_len-3);
146 if (!uri_curr->uri)
147 {
148 status = ARES_ENOMEM;
149 break;
150 }
151 uri_curr->uri = strncpy(uri_curr->uri, (const char *)vptr, rr_len-4);
152 uri_curr->uri[rr_len-4]='\0';
153 uri_curr->ttl = rr_ttl;
154
155 if (status != ARES_SUCCESS)
156 break;
157 }
158
159 /* Don't lose memory in the next iteration */
160 ares_free (rr_name);
161 rr_name = NULL;
162
163 /* Move on to the next record */
164 aptr += rr_len;
165 }
166
167 if (uri_str)
168 ares_free (uri_str);
169 if (rr_name)
170 ares_free (rr_name);
171
172 /* clean up on error */
173 if (status != ARES_SUCCESS)
174 {
175 if (uri_head)
176 ares_free_data (uri_head);
177 return status;
178 }
179
180 /* everything looks fine, return the data */
181 *uri_out = uri_head;
182
183 return ARES_SUCCESS;
184 }
185