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/ */
31 /* the largest packet we'll send and receive */
33 # define MAX_PACKET PACKETSZ
35 # define MAX_PACKET (1024)
41 unsigned char buf
[MAX_PACKET
];
45 _a_rr (dns_packet_t packet
, unsigned char *eom
, unsigned char **scan
)
49 GETLONG (in
.s_addr
, *scan
);
50 in
.s_addr
= ntohl (in
.s_addr
);
52 return xstrdup (inet_ntoa (in
));
56 _srv_rr (dns_packet_t packet
, unsigned char *eom
, unsigned char **scan
)
58 unsigned int priority
, weight
, port
;
63 GETSHORT (priority
, *scan
);
64 GETSHORT (weight
, *scan
);
65 GETSHORT (port
, *scan
);
67 len
= dn_expand (packet
.buf
, eom
, *scan
, host
, 256);
70 *scan
= (unsigned char *) (*scan
+ len
);
72 srv
= (dns_srv_t
) xmalloc (sizeof (struct dns_srv_st
));
74 srv
->priority
= priority
;
78 /* figure out the randomised weight */
79 /* !!! this seems wrong, but I don't have the RFC on hand */
81 srv
->rweight
= 1 + random () % (10000 * weight
);
85 strcpy (srv
->name
, host
);
91 _txt_rr (dns_packet_t packet
, unsigned char *eom
, unsigned char **scan
)
93 size_t len
= (size_t) ** scan
;
96 p
= xmalloc (len
+ 1);
97 memcpy (p
, *scan
+ 1, len
);
99 *scan
+= (unsigned char) (len
+ 1);
104 /* compare two srv structures, order by priority then by randomised weight */
106 _srv_compare (const void *a
, const void *b
)
115 aa
= (dns_srv_t
) (*((dnshost_t
*) a
))->rr
;
116 bb
= (dns_srv_t
) (*((dnshost_t
*) b
))->rr
;
118 if (aa
->priority
> bb
->priority
)
120 if (aa
->priority
< bb
->priority
)
123 if (aa
->rweight
> bb
->rweight
)
125 if (aa
->rweight
< bb
->rweight
)
131 /* the actual resolver function */
133 _shishi_resolv (const char *zone
, unsigned int query_type
)
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')
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
))
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
)
178 if ((len
= dn_expand (packet
.buf
, eom
, scan
, host
, 256)) < 0)
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
);
188 /* loop through the answer buffer and extract SRV records */
189 while (ancount
> 0 && scan
< eom
)
192 len
= dn_expand (packet
.buf
, eom
, scan
, host
, 256);
195 for (n
= 0; n
< an
; n
++)
203 /* extract the various parts of the record */
204 GETSHORT (type
, scan
);
205 GETSHORT (class, scan
);
207 GETSHORT (len
, scan
);
209 /* skip records we're not interested in */
210 if (type
!= query_type
)
212 scan
= (unsigned char *) (scan
+ len
);
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 */
229 reply
[an
]->rr
= _a_rr (packet
, eom
, &scan
);
233 reply
[an
]->rr
= _txt_rr (packet
, eom
, &scan
);
237 reply
[an
]->rr
= _srv_rr (packet
, eom
, &scan
);
241 scan
= (unsigned char *) (scan
+ len
);
245 /* fell short, we're done */
246 if (reply
[an
]->rr
== NULL
)
253 /* on to the next one */
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];
272 /* free an srv structure */
274 _shishi_resolv_free (dnshost_t dns
)
290 _shishi_resolv (const char *zone
, unsigned int query_type
)
296 _shishi_resolv_free (dnshost_t dns
)