1 /* resolv.c --- Resolver glue.
2 * Copyright (C) 2003, 2004, 2007 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 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.
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.
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
25 /* This file is based on resolver.h from jabberd - Jabber Open Source
26 * Server, licensed under GPL. See:
28 * http://www.jabberstudio.org/cgi-bin/viewcvs.cgi/jabberd2/resolver/
35 /* the largest packet we'll send and receive */
37 # define MAX_PACKET PACKETSZ
39 # define MAX_PACKET (1024)
45 unsigned char buf
[MAX_PACKET
];
49 txt_rr (dns_packet_t packet
, unsigned char *eom
, unsigned char **scan
)
51 size_t len
= (size_t) ** scan
;
54 p
= xmalloc (len
+ 1);
55 memcpy (p
, *scan
+ 1, len
);
57 *scan
+= (unsigned char) (len
+ 1);
63 srv_rr (dns_packet_t packet
, unsigned char *eom
, unsigned char **scan
)
65 unsigned int priority
, weight
, port
;
70 GETSHORT (priority
, *scan
);
71 GETSHORT (weight
, *scan
);
72 GETSHORT (port
, *scan
);
74 len
= dn_expand (packet
.buf
, eom
, *scan
, host
, 256);
77 *scan
= (unsigned char *) (*scan
+ len
);
79 srv
= xmalloc (sizeof (*srv
));
81 srv
->priority
= priority
;
85 strcpy (srv
->name
, host
);
90 /* compare two srv structures, order by priority then by randomised weight */
92 srv_compare (const void *a
, const void *b
)
94 Shishi_dns_srv aa
, bb
;
101 aa
= (*((Shishi_dns
*) a
))->rr
;
102 bb
= (*((Shishi_dns
*) b
))->rr
;
104 if (aa
->priority
> bb
->priority
)
106 if (aa
->priority
< bb
->priority
)
109 if (aa
->weight
> bb
->weight
)
111 if (aa
->weight
< bb
->weight
)
119 * @zone: owner name of data, e.g. "EXAMPLE.ORG"
120 * @querytype: type of data to query for, e.g., SHISHI_DNS_TXT.
122 * Query DNS resolver for data of type @querytype at owner name @zone.
123 * Currently TXT and SRV types are supported.
125 * Return value: Returns linked list of DNS records, or NULL if query
129 shishi_resolv (const char *zone
, uint16_t querytype
)
133 int len
, qdcount
, ancount
, an
, n
;
134 unsigned char *eom
, *scan
;
135 Shishi_dns
*reply
, first
;
136 uint16_t type
, class, ttl
;
138 if (zone
== NULL
|| *zone
== '\0')
151 /* do the actual query */
152 if ((len
= res_query (zone
, C_IN
, querytype
, packet
.buf
, MAX_PACKET
)) < 0
153 || len
< (int) sizeof (HEADER
))
156 /* we got a valid result, containing two types of records - packet
157 * and answer .. we have to skip over the packet records */
159 /* no. of packets, no. of answers */
160 qdcount
= ntohs (packet
.hdr
.qdcount
);
161 ancount
= ntohs (packet
.hdr
.ancount
);
163 /* end of the returned message */
164 eom
= (unsigned char *) (packet
.buf
+ len
);
166 /* our current location */
167 scan
= (unsigned char *) (packet
.buf
+ sizeof (HEADER
));
169 /* skip over the packet records */
170 while (qdcount
> 0 && scan
< eom
)
173 if ((len
= dn_expand (packet
.buf
, eom
, scan
, host
, 256)) < 0)
175 scan
= (unsigned char *) (scan
+ len
+ QFIXEDSZ
);
178 /* create an array to store the replies in */
179 reply
= xcalloc (ancount
, sizeof (Shishi_dns
));
182 /* loop through the answer buffer and extract SRV records */
183 while (ancount
> 0 && scan
< eom
)
186 len
= dn_expand (packet
.buf
, eom
, scan
, host
, 256);
189 for (n
= 0; n
< an
; n
++)
197 /* extract the various parts of the record */
198 GETSHORT (type
, scan
);
199 GETSHORT (class, scan
);
201 GETSHORT (len
, scan
);
203 /* skip records we're not interested in */
204 if (type
!= querytype
)
206 scan
= (unsigned char *) (scan
+ len
);
210 /* create a new reply structure to save it in */
211 reply
[an
] = xmalloc (sizeof (*reply
[0]));
213 reply
[an
]->type
= type
;
214 reply
[an
]->class = class;
215 reply
[an
]->ttl
= ttl
;
217 reply
[an
]->next
= NULL
;
219 /* type-specific processing */
223 reply
[an
]->rr
= txt_rr (packet
, eom
, &scan
);
227 reply
[an
]->rr
= srv_rr (packet
, eom
, &scan
);
231 scan
= (unsigned char *) (scan
+ len
);
235 /* fell short, we're done */
236 if (reply
[an
]->rr
== NULL
)
243 /* on to the next one */
247 /* sort srv records them */
248 if (querytype
== T_SRV
)
249 qsort (reply
, an
, sizeof (Shishi_dns
), srv_compare
);
251 /* build a linked list out of the array elements */
252 for (n
= 0; n
< an
- 1; n
++)
253 reply
[n
]->next
= reply
[n
+ 1];
265 shishi_resolv (const char *zone
, uint16_t querytype
)
273 * shishi_resolv_free:
274 * @rrs: list of DNS RR as returned by shishi_resolv().
276 * Deallocate list of DNS RR as returned by shishi_resolv().
279 shishi_resolv_free (Shishi_dns rrs
)