Branch data Line data Source code
1 : : /* resolv.c --- Resolver glue.
2 : : * Copyright (C) 2003, 2004, 2007, 2008 Simon Josefsson
3 : : * Copyright (C) 2002 Jeremie Miller, Thomas Muldowney,
4 : : * Ryan Eatmon, Robert Norris
5 : : *
6 : : * This file is part of Shishi.
7 : : *
8 : : * Shishi is free software; you can redistribute it and/or modify it
9 : : * under the terms of the GNU General Public License as published by
10 : : * the Free Software Foundation; either version 3 of the License, or
11 : : * (at your option) any later version.
12 : : *
13 : : * Shishi is distributed in the hope that it will be useful, but
14 : : * WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : : * GNU General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU General Public License
19 : : * along with Shishi; if not, see http://www.gnu.org/licenses or write
20 : : * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 : : * Floor, Boston, MA 02110-1301, USA
22 : : *
23 : : */
24 : :
25 : : /* This file is based on resolver.h from jabberd - Jabber Open Source
26 : : * Server, licensed under GPL. See:
27 : : *
28 : : * http://www.jabberstudio.org/cgi-bin/viewcvs.cgi/jabberd2/resolver/
29 : : */
30 : :
31 : : #include "internal.h"
32 : :
33 : : #ifdef HAVE_LIBRESOLV
34 : :
35 : : /* the largest packet we'll send and receive */
36 : : #if PACKETSZ > 1024
37 : : # define MAX_PACKET PACKETSZ
38 : : #else
39 : : # define MAX_PACKET (1024)
40 : : #endif
41 : :
42 : : typedef union
43 : : {
44 : : HEADER hdr;
45 : : unsigned char buf[MAX_PACKET];
46 : : } dns_packet_t;
47 : :
48 : : static void *
49 : 0 : txt_rr (dns_packet_t packet, unsigned char *eom, unsigned char **scan)
50 : : {
51 : 0 : size_t len = (size_t) ** scan;
52 : : char *p;
53 : :
54 : 0 : p = xmalloc (len + 1);
55 : 0 : memcpy (p, *scan + 1, len);
56 : 0 : p[len] = '\0';
57 : 0 : *scan += (unsigned char) (len + 1);
58 : :
59 : 0 : return p;
60 : : }
61 : :
62 : : static void *
63 : 0 : srv_rr (dns_packet_t packet, unsigned char *eom, unsigned char **scan)
64 : : {
65 : : unsigned int priority, weight, port;
66 : : int len;
67 : : char host[256];
68 : : Shishi_dns_srv srv;
69 : :
70 : 0 : GETSHORT (priority, *scan);
71 : 0 : GETSHORT (weight, *scan);
72 : 0 : GETSHORT (port, *scan);
73 : :
74 : 0 : len = dn_expand (packet.buf, eom, *scan, host, 256);
75 [ # # ]: 0 : if (len < 0)
76 : 0 : return NULL;
77 : 0 : *scan = (unsigned char *) (*scan + len);
78 : :
79 : 0 : srv = xmalloc (sizeof (*srv));
80 : :
81 : 0 : srv->priority = priority;
82 : 0 : srv->weight = weight;
83 : 0 : srv->port = port;
84 : :
85 : 0 : strcpy (srv->name, host);
86 : :
87 : 0 : return (void *) srv;
88 : : }
89 : :
90 : : /* compare two srv structures, order by priority then by randomised weight */
91 : : static int
92 : 0 : srv_compare (const void *a, const void *b)
93 : : {
94 : : Shishi_dns_srv aa, bb;
95 : :
96 [ # # ]: 0 : if (a == NULL)
97 : 0 : return 1;
98 [ # # ]: 0 : if (b == NULL)
99 : 0 : return -1;
100 : :
101 : 0 : aa = (*((Shishi_dns *) a))->rr;
102 : 0 : bb = (*((Shishi_dns *) b))->rr;
103 : :
104 [ # # ]: 0 : if (aa->priority > bb->priority)
105 : 0 : return 1;
106 [ # # ]: 0 : if (aa->priority < bb->priority)
107 : 0 : return -1;
108 : :
109 [ # # ]: 0 : if (aa->weight > bb->weight)
110 : 0 : return -1;
111 [ # # ]: 0 : if (aa->weight < bb->weight)
112 : 0 : return 1;
113 : :
114 : 0 : return 0;
115 : : }
116 : :
117 : : /**
118 : : * shishi_resolv:
119 : : * @zone: owner name of data, e.g. "EXAMPLE.ORG"
120 : : * @querytype: type of data to query for, e.g., SHISHI_DNS_TXT.
121 : : *
122 : : * Query DNS resolver for data of type @querytype at owner name @zone.
123 : : * Currently TXT and SRV types are supported.
124 : : *
125 : : * Return value: Returns linked list of DNS records, or NULL if query
126 : : * failed.
127 : : **/
128 : : Shishi_dns
129 : 0 : shishi_resolv (const char *zone, uint16_t querytype)
130 : : {
131 : : char host[256];
132 : : dns_packet_t packet;
133 : : int len, qdcount, ancount, an, n;
134 : : unsigned char *eom, *scan;
135 : : Shishi_dns *reply, first;
136 : : uint16_t type, class, ttl;
137 : :
138 [ # # ][ # # ]: 0 : if (zone == NULL || *zone == '\0')
139 : 0 : return NULL;
140 : :
141 [ # # ]: 0 : switch (querytype)
142 : : {
143 : : case SHISHI_DNS_TXT:
144 : : case SHISHI_DNS_SRV:
145 : : break;
146 : :
147 : : default:
148 : 0 : return NULL;
149 : : }
150 : :
151 : : /* do the actual query */
152 [ # # ][ # # ]: 0 : if ((len = res_query (zone, C_IN, querytype, packet.buf, MAX_PACKET)) < 0
153 : : || len < (int) sizeof (HEADER))
154 : 0 : return NULL;
155 : :
156 : : /* we got a valid result, containing two types of records - packet
157 : : * and answer .. we have to skip over the packet records */
158 : :
159 : : /* no. of packets, no. of answers */
160 : 0 : qdcount = ntohs (packet.hdr.qdcount);
161 : 0 : ancount = ntohs (packet.hdr.ancount);
162 : :
163 : : /* end of the returned message */
164 : 0 : eom = (unsigned char *) (packet.buf + len);
165 : :
166 : : /* our current location */
167 : 0 : scan = (unsigned char *) (packet.buf + sizeof (HEADER));
168 : :
169 : : /* skip over the packet records */
170 [ # # ][ # # ]: 0 : while (qdcount > 0 && scan < eom)
171 : : {
172 : 0 : qdcount--;
173 [ # # ]: 0 : if ((len = dn_expand (packet.buf, eom, scan, host, 256)) < 0)
174 : 0 : return NULL;
175 : 0 : scan = (unsigned char *) (scan + len + QFIXEDSZ);
176 : : }
177 : :
178 : : /* create an array to store the replies in */
179 : 0 : reply = xcalloc (ancount, sizeof (Shishi_dns));
180 : :
181 : 0 : an = 0;
182 : : /* loop through the answer buffer and extract SRV records */
183 [ # # ][ # # ]: 0 : while (ancount > 0 && scan < eom)
184 : : {
185 : 0 : ancount--;
186 : 0 : len = dn_expand (packet.buf, eom, scan, host, 256);
187 [ # # ]: 0 : if (len < 0)
188 : : {
189 [ # # ]: 0 : for (n = 0; n < an; n++)
190 : 0 : free (reply[n]);
191 : 0 : free (reply);
192 : 0 : return NULL;
193 : : }
194 : :
195 : 0 : scan += len;
196 : :
197 : : /* extract the various parts of the record */
198 : 0 : GETSHORT (type, scan);
199 : 0 : GETSHORT (class, scan);
200 : 0 : GETLONG (ttl, scan);
201 : 0 : GETSHORT (len, scan);
202 : :
203 : : /* skip records we're not interested in */
204 [ # # ]: 0 : if (type != querytype)
205 : : {
206 : 0 : scan = (unsigned char *) (scan + len);
207 : 0 : continue;
208 : : }
209 : :
210 : : /* create a new reply structure to save it in */
211 : 0 : reply[an] = xmalloc (sizeof (*reply[0]));
212 : :
213 : 0 : reply[an]->type = type;
214 : 0 : reply[an]->class = class;
215 : 0 : reply[an]->ttl = ttl;
216 : :
217 : 0 : reply[an]->next = NULL;
218 : :
219 : : /* type-specific processing */
220 [ # # # ]: 0 : switch (type)
221 : : {
222 : : case SHISHI_DNS_TXT:
223 : 0 : reply[an]->rr = txt_rr (packet, eom, &scan);
224 : 0 : break;
225 : :
226 : : case SHISHI_DNS_SRV:
227 : 0 : reply[an]->rr = srv_rr (packet, eom, &scan);
228 : 0 : break;
229 : :
230 : : default:
231 : 0 : scan = (unsigned char *) (scan + len);
232 : 0 : continue;
233 : : }
234 : :
235 : : /* fell short, we're done */
236 [ # # ]: 0 : if (reply[an]->rr == NULL)
237 : : {
238 : 0 : free (reply[an]);
239 : 0 : reply[an] = NULL;
240 : 0 : break;
241 : : }
242 : :
243 : : /* on to the next one */
244 : 0 : an++;
245 : : }
246 : :
247 : : /* sort srv records them */
248 [ # # ]: 0 : if (querytype == SHISHI_DNS_SRV)
249 : 0 : qsort (reply, an, sizeof (Shishi_dns), srv_compare);
250 : :
251 : : /* build a linked list out of the array elements */
252 [ # # ]: 0 : for (n = 0; n < an - 1; n++)
253 : 0 : reply[n]->next = reply[n + 1];
254 : :
255 : 0 : first = reply[0];
256 : :
257 : 0 : free (reply);
258 : :
259 : 0 : return first;
260 : : }
261 : :
262 : : #else
263 : :
264 : : Shishi_dns
265 : : shishi_resolv (const char *zone, uint16_t querytype)
266 : : {
267 : : return NULL;
268 : : }
269 : :
270 : : #endif
271 : :
272 : : /**
273 : : * shishi_resolv_free:
274 : : * @rrs: list of DNS RR as returned by shishi_resolv().
275 : : *
276 : : * Deallocate list of DNS RR as returned by shishi_resolv().
277 : : **/
278 : : void
279 : 0 : shishi_resolv_free (Shishi_dns rrs)
280 : : {
281 : : Shishi_dns next;
282 : :
283 [ # # ]: 0 : while (rrs != NULL)
284 : : {
285 : 0 : next = rrs->next;
286 : 0 : free (rrs->rr);
287 : 0 : free (rrs);
288 : 0 : rrs = next;
289 : : }
290 : 0 : }
|