Look for SRV RRs if KDC address not known.
[shishi.git] / lib / resolv.c
blob5841b23aa005c59b1717dc7e8a9d3eed27ef0d75
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. */
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 strdup (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) malloc (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 /* compare two srv structures, order by priority then by randomised weight */
91 static int
92 _srv_compare (const void *a, const void *b)
94 dns_srv_t aa, bb;
96 if (a == NULL)
97 return 1;
98 if (b == NULL)
99 return -1;
101 aa = (dns_srv_t) (*((dnshost_t *) a))->rr;
102 bb = (dns_srv_t) (*((dnshost_t *) b))->rr;
104 if (aa->priority > bb->priority)
105 return 1;
106 if (aa->priority < bb->priority)
107 return -1;
109 if (aa->rweight > bb->rweight)
110 return -1;
111 if (aa->rweight < bb->rweight)
112 return 1;
114 return 0;
117 /* the actual resolver function */
118 dnshost_t
119 _shishi_resolv (const char *zone, unsigned int query_type)
121 char host[256];
122 dns_packet_t packet;
123 int len, qdcount, ancount, an, n;
124 unsigned char *eom, *scan;
125 dnshost_t *reply, first;
126 unsigned int type, class, ttl;
128 if (zone == NULL || *zone == '\0')
129 return NULL;
131 switch (query_type)
133 case T_SRV:
134 case T_A:
135 break;
137 default:
138 return NULL;
141 /* do the actual query */
142 if ((len = res_query (zone, C_IN, query_type, packet.buf, MAX_PACKET)) == -1
143 || len < sizeof (HEADER))
144 return NULL;
146 /* we got a valid result, containing two types of records - packet
147 * and answer .. we have to skip over the packet records */
149 /* no. of packets, no. of answers */
150 qdcount = ntohs (packet.hdr.qdcount);
151 ancount = ntohs (packet.hdr.ancount);
153 /* end of the returned message */
154 eom = (unsigned char *) (packet.buf + len);
156 /* our current location */
157 scan = (unsigned char *) (packet.buf + sizeof (HEADER));
159 /* skip over the packet records */
160 while (qdcount > 0 && scan < eom)
162 qdcount--;
163 if ((len = dn_expand (packet.buf, eom, scan, host, 256)) < 0)
164 return NULL;
165 scan = (unsigned char *) (scan + len + QFIXEDSZ);
168 /* create an array to store the replies in */
169 reply = (dnshost_t *) malloc (sizeof (dnshost_t) * ancount);
170 memset (reply, 0, sizeof (dnshost_t) * ancount);
172 an = 0;
173 /* loop through the answer buffer and extract SRV records */
174 while (ancount > 0 && scan < eom)
176 ancount--;
177 len = dn_expand (packet.buf, eom, scan, host, 256);
178 if (len < 0)
180 for (n = 0; n < an; n++)
181 free (reply[n]);
182 free (reply);
183 return NULL;
186 scan += len;
188 /* extract the various parts of the record */
189 GETSHORT (type, scan);
190 GETSHORT (class, scan);
191 GETLONG (ttl, scan);
192 GETSHORT (len, scan);
194 /* skip records we're not interested in */
195 if (type != query_type)
197 scan = (unsigned char *) (scan + len);
198 continue;
201 /* create a new reply structure to save it in */
202 reply[an] = (dnshost_t) malloc (sizeof (struct dnshost_st));
204 reply[an]->type = type;
205 reply[an]->class = class;
206 reply[an]->ttl = ttl;
208 reply[an]->next = NULL;
210 /* type-specific processing */
211 switch (type)
213 case T_A:
214 reply[an]->rr = _a_rr (packet, eom, &scan);
215 break;
217 case T_SRV:
218 reply[an]->rr = _srv_rr (packet, eom, &scan);
219 break;
221 default:
222 scan = (unsigned char *) (scan + len);
223 continue;
226 /* fell short, we're done */
227 if (reply[an]->rr == NULL)
229 free (reply[an]);
230 reply[an] = NULL;
231 break;
234 /* on to the next one */
235 an++;
238 /* sort srv records them */
239 if (query_type == T_SRV)
240 qsort (reply, an, sizeof (dnshost_t), _srv_compare);
242 /* build a linked list out of the array elements */
243 for (n = 0; n < an - 1; n++)
244 reply[n]->next = reply[n + 1];
246 first = reply[0];
248 free (reply);
250 return first;
253 /* free an srv structure */
254 void
255 _shishi_resolv_free (dnshost_t dns)
257 dnshost_t next;
259 while (dns != NULL)
261 next = dns->next;
262 free (dns->rr);
263 free (dns);
264 dns = next;
268 #else
270 dnshost_t
271 _shishi_resolv (const char *zone, unsigned int query_type)
273 return NULL;
276 void
277 _shishi_resolv_free (dnshost_t dns)
281 #endif