Fix.
[shishi.git] / lib / resolv.c
blob6727e267af62628c1aa10403231bd5c61f528354
1 /* resolv.c resolver glue.
2 * Copyright (C) 2003 Simon Josefsson
3 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4 * Ryan Eatmon, Robert Norris
6 * This file is part of Shishi.
8 * Shishi is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * Shishi is distributed in the hope that it will be useful,
14 * but 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.
18 * You should have received a copy of the GNU General Public License
19 * along with Shishi; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 /* This file comes from jabberd - Jabber Open Source Server, licensed
25 under GPL. http://www.jabberstudio.org/cgi-bin/viewcvs.cgi/jabberd2/ */
27 #include "internal.h"
29 #ifdef HAVE_LIBRESOLV
31 /* the largest packet we'll send and receive */
32 #if PACKETSZ > 1024
33 # define MAX_PACKET PACKETSZ
34 #else
35 # define MAX_PACKET (1024)
36 #endif
38 typedef union
40 HEADER hdr;
41 unsigned char buf[MAX_PACKET];
42 } dns_packet_t;
44 static void *
45 _a_rr (dns_packet_t packet, unsigned char *eom, unsigned char **scan)
47 struct in_addr in;
49 GETLONG (in.s_addr, *scan);
50 in.s_addr = ntohl (in.s_addr);
52 return xstrdup (inet_ntoa (in));
55 static void *
56 _srv_rr (dns_packet_t packet, unsigned char *eom, unsigned char **scan)
58 unsigned int priority, weight, port;
59 int len;
60 char host[256];
61 dns_srv_t srv;
63 GETSHORT (priority, *scan);
64 GETSHORT (weight, *scan);
65 GETSHORT (port, *scan);
67 len = dn_expand (packet.buf, eom, *scan, host, 256);
68 if (len < 0)
69 return NULL;
70 *scan = (unsigned char *) (*scan + len);
72 srv = (dns_srv_t) xmalloc (sizeof (struct dns_srv_st));
74 srv->priority = priority;
75 srv->weight = weight;
76 srv->port = port;
78 /* figure out the randomised weight */
79 /* !!! this seems wrong, but I don't have the RFC on hand */
80 if (weight != 0)
81 srv->rweight = 1 + random () % (10000 * weight);
82 else
83 srv->rweight = 0;
85 strcpy (srv->name, host);
87 return (void *) srv;
90 static void *
91 _txt_rr (dns_packet_t packet, unsigned char *eom, unsigned char **scan)
93 size_t len = (size_t) ** scan;
94 char *p;
96 p = xmalloc (len + 1);
97 memcpy (p, *scan + 1, len);
98 p[len] = '\0';
99 *scan += (unsigned char) (len + 1);
101 return p;
104 /* compare two srv structures, order by priority then by randomised weight */
105 static int
106 _srv_compare (const void *a, const void *b)
108 dns_srv_t aa, bb;
110 if (a == NULL)
111 return 1;
112 if (b == NULL)
113 return -1;
115 aa = (dns_srv_t) (*((dnshost_t *) a))->rr;
116 bb = (dns_srv_t) (*((dnshost_t *) b))->rr;
118 if (aa->priority > bb->priority)
119 return 1;
120 if (aa->priority < bb->priority)
121 return -1;
123 if (aa->rweight > bb->rweight)
124 return -1;
125 if (aa->rweight < bb->rweight)
126 return 1;
128 return 0;
131 /* the actual resolver function */
132 dnshost_t
133 _shishi_resolv (const char *zone, unsigned int query_type)
135 char host[256];
136 dns_packet_t packet;
137 int len, qdcount, ancount, an, n;
138 unsigned char *eom, *scan;
139 dnshost_t *reply, first;
140 unsigned int type, class, ttl;
142 if (zone == NULL || *zone == '\0')
143 return NULL;
145 switch (query_type)
147 case T_A:
148 case T_TXT:
149 case T_SRV:
150 break;
152 default:
153 return NULL;
156 /* do the actual query */
157 if ((len = res_query (zone, C_IN, query_type, packet.buf, MAX_PACKET)) < 0
158 || len < (int) sizeof (HEADER))
159 return NULL;
161 /* we got a valid result, containing two types of records - packet
162 * and answer .. we have to skip over the packet records */
164 /* no. of packets, no. of answers */
165 qdcount = ntohs (packet.hdr.qdcount);
166 ancount = ntohs (packet.hdr.ancount);
168 /* end of the returned message */
169 eom = (unsigned char *) (packet.buf + len);
171 /* our current location */
172 scan = (unsigned char *) (packet.buf + sizeof (HEADER));
174 /* skip over the packet records */
175 while (qdcount > 0 && scan < eom)
177 qdcount--;
178 if ((len = dn_expand (packet.buf, eom, scan, host, 256)) < 0)
179 return NULL;
180 scan = (unsigned char *) (scan + len + QFIXEDSZ);
183 /* create an array to store the replies in */
184 reply = (dnshost_t *) xmalloc (sizeof (dnshost_t) * ancount);
185 memset (reply, 0, sizeof (dnshost_t) * ancount);
187 an = 0;
188 /* loop through the answer buffer and extract SRV records */
189 while (ancount > 0 && scan < eom)
191 ancount--;
192 len = dn_expand (packet.buf, eom, scan, host, 256);
193 if (len < 0)
195 for (n = 0; n < an; n++)
196 free (reply[n]);
197 free (reply);
198 return NULL;
201 scan += len;
203 /* extract the various parts of the record */
204 GETSHORT (type, scan);
205 GETSHORT (class, scan);
206 GETLONG (ttl, scan);
207 GETSHORT (len, scan);
209 /* skip records we're not interested in */
210 if (type != query_type)
212 scan = (unsigned char *) (scan + len);
213 continue;
216 /* create a new reply structure to save it in */
217 reply[an] = (dnshost_t) xmalloc (sizeof (struct dnshost_st));
219 reply[an]->type = type;
220 reply[an]->class = class;
221 reply[an]->ttl = ttl;
223 reply[an]->next = NULL;
225 /* type-specific processing */
226 switch (type)
228 case T_A:
229 reply[an]->rr = _a_rr (packet, eom, &scan);
230 break;
232 case T_TXT:
233 reply[an]->rr = _txt_rr (packet, eom, &scan);
234 break;
236 case T_SRV:
237 reply[an]->rr = _srv_rr (packet, eom, &scan);
238 break;
240 default:
241 scan = (unsigned char *) (scan + len);
242 continue;
245 /* fell short, we're done */
246 if (reply[an]->rr == NULL)
248 free (reply[an]);
249 reply[an] = NULL;
250 break;
253 /* on to the next one */
254 an++;
257 /* sort srv records them */
258 if (query_type == T_SRV)
259 qsort (reply, an, sizeof (dnshost_t), _srv_compare);
261 /* build a linked list out of the array elements */
262 for (n = 0; n < an - 1; n++)
263 reply[n]->next = reply[n + 1];
265 first = reply[0];
267 free (reply);
269 return first;
272 /* free an srv structure */
273 void
274 _shishi_resolv_free (dnshost_t dns)
276 dnshost_t next;
278 while (dns != NULL)
280 next = dns->next;
281 free (dns->rr);
282 free (dns);
283 dns = next;
287 #else
289 dnshost_t
290 _shishi_resolv (const char *zone, unsigned int query_type)
292 return NULL;
295 void
296 _shishi_resolv_free (dnshost_t dns)
300 #endif