summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libc/net/Makefile.inc11
-rw-r--r--src/lib/libc/net/getrrsetbyname.3149
-rw-r--r--src/lib/libc/net/getrrsetbyname.c506
3 files changed, 661 insertions, 5 deletions
diff --git a/src/lib/libc/net/Makefile.inc b/src/lib/libc/net/Makefile.inc
index 641d612105..805ae5d224 100644
--- a/src/lib/libc/net/Makefile.inc
+++ b/src/lib/libc/net/Makefile.inc
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile.inc,v 1.30 2000/02/23 15:39:53 itojun Exp $ 1# $OpenBSD: Makefile.inc,v 1.31 2001/08/06 14:40:47 jakob Exp $
2 2
3# net sources 3# net sources
4.PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/net ${LIBCSRCDIR}/net 4.PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/net ${LIBCSRCDIR}/net
@@ -8,8 +8,8 @@ CFLAGS+=-DRESOLVSORT
8SRCS+= base64.c freeaddrinfo.c gai_strerror.c getaddrinfo.c gethostnamadr.c \ 8SRCS+= base64.c freeaddrinfo.c gai_strerror.c getaddrinfo.c gethostnamadr.c \
9 getifaddrs.c getnameinfo.c getnetbyaddr.c getnetbyname.c getnetent.c \ 9 getifaddrs.c getnameinfo.c getnetbyaddr.c getnetbyname.c getnetent.c \
10 getnetnamadr.c getproto.c getprotoent.c getprotoname.c \ 10 getnetnamadr.c getproto.c getprotoent.c getprotoname.c \
11 getservbyname.c getservbyport.c getservent.c herror.c \ 11 getservbyname.c getservbyport.c getservent.c getrrsetbyname.c \
12 if_indextoname.c if_nameindex.c if_nametoindex.c inet_addr.c \ 12 herror.c if_indextoname.c if_nameindex.c if_nametoindex.c inet_addr.c \
13 inet_lnaof.c inet_makeaddr.c inet_neta.c inet_netof.c inet_network.c \ 13 inet_lnaof.c inet_makeaddr.c inet_neta.c inet_netof.c inet_network.c \
14 inet_net_ntop.c inet_net_pton.c inet_ntoa.c inet_ntop.c inet_pton.c \ 14 inet_net_ntop.c inet_net_pton.c inet_ntoa.c inet_ntop.c inet_pton.c \
15 ipx_addr.c ipx_ntoa.c iso_addr.c linkaddr.c ns_addr.c ns_ntoa.c \ 15 ipx_addr.c ipx_ntoa.c iso_addr.c linkaddr.c ns_addr.c ns_ntoa.c \
@@ -32,8 +32,8 @@ MAN+= byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 getifaddrs.3 \
32 getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 inet.3 \ 32 getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 inet.3 \
33 if_indextoname.3 inet_net.3 iso_addr.3 link_addr.3 ns.3 ipx.3 \ 33 if_indextoname.3 inet_net.3 iso_addr.3 link_addr.3 ns.3 ipx.3 \
34 rcmd.3 rcmdsh.3 resolver.3 net_addrcmp.3 \ 34 rcmd.3 rcmdsh.3 resolver.3 net_addrcmp.3 \
35 inet6_option_space.3 inet6_rthdr_space.3 35 inet6_option_space.3 inet6_rthdr_space.3 \
36 36 getrrsetbyname.3
37 37
38MLINKS+=byteorder.3 htonl.3 byteorder.3 htons.3 byteorder.3 ntohl.3 \ 38MLINKS+=byteorder.3 htonl.3 byteorder.3 htons.3 byteorder.3 ntohl.3 \
39 byteorder.3 ntohs.3 byteorder.3 htobe16.3 byteorder.3 htobe32.3 \ 39 byteorder.3 ntohs.3 byteorder.3 htobe16.3 byteorder.3 htobe32.3 \
@@ -82,3 +82,4 @@ MLINKS+=inet6_rthdr_space.3 inet6_rthdr_init.3 \
82 inet6_rthdr_space.3 inet6_rthdr_segments.3 \ 82 inet6_rthdr_space.3 inet6_rthdr_segments.3 \
83 inet6_rthdr_space.3 inet6_rthdr_getaddr.3 \ 83 inet6_rthdr_space.3 inet6_rthdr_getaddr.3 \
84 inet6_rthdr_space.3 inet6_rthdr_getflags.3 84 inet6_rthdr_space.3 inet6_rthdr_getflags.3
85MLINKS+=getrrsetbyname.3 freerrset.3
diff --git a/src/lib/libc/net/getrrsetbyname.3 b/src/lib/libc/net/getrrsetbyname.3
new file mode 100644
index 0000000000..3b8c06999e
--- /dev/null
+++ b/src/lib/libc/net/getrrsetbyname.3
@@ -0,0 +1,149 @@
1.\" $Id: getrrsetbyname.3,v 1.1 2001/08/06 14:40:47 jakob Exp $
2.\"
3.\" Copyright (C) 2000, 2001 Internet Software Consortium.
4.\"
5.\" Permission to use, copy, modify, and distribute this software for any
6.\" purpose with or without fee is hereby granted, provided that the above
7.\" copyright notice and this permission notice appear in all copies.
8.\"
9.\" THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
10.\" DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
11.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
12.\" INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
13.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
14.\" FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15.\" NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
16.\" WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17.\"
18.Dd Oct 18, 2000
19.Dt GETRRSETBYNAME 3
20.Os
21.Sh NAME
22.Nm getrrsetbyname
23.Nd retrieve DNS records
24.Sh SYNOPSIS
25.Fd #include <netdb.h>
26.Ft int
27.Fn getrrsetbyname "const char *hostname" "unsigned int rdclass" \
28"unsigned int rdtype" "unsigned int flags" "struct rrsetinfo **res"
29.Ft int
30.Fn freerrset "struct rrsetinfo **rrset"
31.Sh DESCRIPTION
32.Fn getrrsetbyname
33gets a set of resource records associated with a
34.Fa hostname ,
35.Fa class
36and
37.Fa type .
38.Fa hostname
39is a pointer a to null-terminated string.
40The
41.Fa flags
42field is currently unused and must be zero.
43.Pp
44After a successful call to
45.Fn getrrsetbyname ,
46.Fa *res
47is a pointer to an
48.Li rrsetinfo
49structure, containing a list of one or more
50.Li rdatainfo
51structures containing resource records and potentially another list of
52.Li rdatainfo
53structures containing SIG resource records associated with those records.
54The members
55.Li rri_rdclass
56and
57.Li rri_rdtype
58are copied from the parameters.
59.Li rri_ttl
60and
61.Li rri_name
62are properties of the obtained rrset.
63The resource records contained in
64.Li rri_rdatas
65and
66.Li rri_sigs
67are in uncompressed DNS wire format.
68Properties of the rdataset are represented in the
69.Li rri_flags
70bitfield. If the
71.Dv RRSET_VALIDATED
72bit is set, the data has been DNSSEC
73validated and the signatures verified.
74.Pp
75The following structures are used:
76.Bd -literal -offset
77struct rdatainfo {
78 unsigned int rdi_length; /* length of data */
79 unsigned char *rdi_data; /* record data */
80};
81
82struct rrsetinfo {
83 unsigned int rri_flags; /* RRSET_VALIDATED ... */
84 unsigned int rri_rdclass; /* class number */
85 unsigned int rri_rdtype; /* RR type number */
86 unsigned int rri_ttl; /* time to live */
87 unsigned int rri_nrdatas; /* size of rdatas array */
88 unsigned int rri_nsigs; /* size of sigs array */
89 char *rri_name; /* canonical name */
90 struct rdatainfo *rri_rdatas; /* individual records */
91 struct rdatainfo *rri_sigs; /* individual signatures */
92};
93.Ed
94.Pp
95All of the information returned by
96.Fn getrrsetbyname
97is dynamically allocated: the
98.Li rrsetinfo
99and
100.Li rdatainfo
101structures,
102and the canonical host name strings pointed to by the
103.Li rrsetinfostructure.
104Memory allocated for the dynamically allocated structures created by
105a successful call to
106.Fn getrrsetbyname
107is released by
108.Fn freerrset .
109.Li rrset
110is a pointer to a
111.Li struct rrset
112created by a call to
113.Fn getrrsetbyname .
114.Pp
115If the EDNS0 option is activated in
116.Xr resolv.conf 3 ,
117.Fn getrrsetbyname
118will request DNSSEC authentication using the EDNS0 DNSSEC OK (DO) bit.
119.Sh "RETURN VALUES"
120.Fn getrrsetbyname
121returns zero on success, and one of the following error
122codes if an error occurred:
123.Pp
124.Bl -tag -width ERRSET_NOMEMORY -compact
125.It Dv ERRSET_NONAME
126the name does not exist
127.It Dv ERRSET_NODATA
128the name exists, but does not have data of the desired type
129.It Dv ERRSET_NOMEMORY
130memory could not be allocated
131.It Dv ERRSET_INVAL
132a parameter is invalid
133.It Dv ERRSET_FAIL
134other failure
135.El
136.Sh SEE ALSO
137.Xr resolver 3 ,
138.Xr resolv.conf 5 ,
139.Xr named 8
140.Sh HISTORY
141.Nm
142first appeared in
143.Ox 3.0 .
144.Sh BUGS
145The data in
146.Li *rdi_data
147should be returned in uncompressed wire format.
148Currently, the data is in compressed format and the caller can't
149uncompress since it doesn't have the full message.
diff --git a/src/lib/libc/net/getrrsetbyname.c b/src/lib/libc/net/getrrsetbyname.c
new file mode 100644
index 0000000000..cacf9157e7
--- /dev/null
+++ b/src/lib/libc/net/getrrsetbyname.c
@@ -0,0 +1,506 @@
1/* $Id: getrrsetbyname.c,v 1.1 2001/08/06 14:40:47 jakob Exp $ */
2
3/*
4 * Copyright (c) 2001 Jakob Schlyter. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Portions Copyright (c) 1999-2001 Internet Software Consortium.
31 *
32 * Permission to use, copy, modify, and distribute this software for any
33 * purpose with or without fee is hereby granted, provided that the above
34 * copyright notice and this permission notice appear in all copies.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
37 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
39 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
40 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
41 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
42 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
43 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
44 */
45
46
47#include <sys/types.h>
48#include <netinet/in.h>
49#include <arpa/nameser.h>
50#include <netdb.h>
51#include <resolv.h>
52#include <stdlib.h>
53#include <string.h>
54
55#define ANSWER_BUFFER_SIZE 1024*64
56
57
58struct dns_query {
59 char *name;
60 u_int16_t type;
61 u_int16_t class;
62 struct dns_query *next;
63};
64
65struct dns_rr {
66 char *name;
67 u_int16_t type;
68 u_int16_t class;
69 u_int16_t ttl;
70 u_int16_t size;
71 void *rdata;
72 struct dns_rr *next;
73};
74
75struct dns_response {
76 HEADER header;
77 struct dns_query *query;
78 struct dns_rr *answer;
79 struct dns_rr *authority;
80 struct dns_rr *additional;
81};
82
83static struct dns_response *parse_dns_response(const char *, int);
84static struct dns_query *parse_dns_qsection(const char *, int, const char **,
85 int);
86static struct dns_rr *parse_dns_rrsection(const char *, int, const char **,
87 int);
88
89static void free_dns_query(struct dns_query *);
90static void free_dns_rr(struct dns_rr *);
91static void free_dns_response(struct dns_response *);
92
93static int count_dns_rr(struct dns_rr *, u_int16_t, u_int16_t);
94
95int
96getrrsetbyname(const char *hostname, unsigned int rdclass,
97 unsigned int rdtype, unsigned int flags,
98 struct rrsetinfo **res)
99{
100 int result;
101 struct rrsetinfo *rrset = NULL;
102 struct dns_response *response;
103 struct dns_rr *rr;
104 struct rdatainfo *rdata;
105 unsigned length, index_ans, index_sig;
106 char answer[ANSWER_BUFFER_SIZE];
107
108 /* check for invalid class and type */
109 if (rdclass > 0xffff || rdtype > 0xffff) {
110 result = ERRSET_INVAL;
111 goto fail;
112 }
113
114 /* don't allow queries of class or type ANY */
115 if (rdclass == 0xff || rdtype == 0xff) {
116 result = ERRSET_INVAL;
117 goto fail;
118 }
119
120 /* don't allow flags yet, unimplemented */
121 if (flags) {
122 result = ERRSET_INVAL;
123 goto fail;
124 }
125
126 /* initialize resolver */
127 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
128 result = ERRSET_FAIL;
129 goto fail;
130 }
131
132#ifdef DEBUG
133 _res.options |= RES_DEBUG;
134#endif /* DEBUG */
135
136#ifdef RES_USE_DNSSEC
137 /* turn on DNSSEC if EDNS0 is configured */
138 if (_res.options & RES_USE_EDNS0)
139 _res.options |= RES_USE_DNSSEC;
140#endif /* RES_USE_DNSEC */
141
142 /* make query */
143 length = res_query(hostname, rdclass, rdtype, answer, sizeof(answer));
144 if (length < 0) {
145 switch(h_errno) {
146 case HOST_NOT_FOUND:
147 result = ERRSET_NONAME;
148 goto fail;
149 case NO_DATA:
150 result = ERRSET_NODATA;
151 goto fail;
152 default:
153 result = ERRSET_FAIL;
154 goto fail;
155 }
156 }
157
158 /* parse result */
159 response = parse_dns_response(answer, length);
160 if (response == NULL) {
161 result = ERRSET_FAIL;
162 goto fail;
163 }
164
165 if (response->header.qdcount != 1 ) {
166 result = ERRSET_FAIL;
167 goto fail;
168 }
169
170 /* initialize rrset */
171 rrset = calloc(1, sizeof(struct rrsetinfo));
172 if (rrset == NULL) {
173 result = ERRSET_NOMEMORY;
174 goto fail;
175 }
176 rrset->rri_rdclass = response->query->class;
177 rrset->rri_rdtype = response->query->type;
178 rrset->rri_ttl = response->answer->ttl;
179 rrset->rri_nrdatas = response->header.ancount;
180
181 /* check for authenticated data */
182 if (response->header.ad == 1)
183 rrset->rri_flags |= RRSET_VALIDATED;
184
185 /* copy name from answer section */
186 length = strlen(response->answer->name);
187 rrset->rri_name = malloc(length + 1);
188 if (rrset->rri_name == NULL) {
189 result = ERRSET_NOMEMORY;
190 goto fail;
191 }
192 strlcpy(rrset->rri_name, response->answer->name, length + 1);
193
194 /* count answers */
195 rrset->rri_nrdatas = count_dns_rr(response->answer, rrset->rri_rdclass,
196 rrset->rri_rdtype);
197 rrset->rri_nsigs = count_dns_rr(response->answer, rrset->rri_rdclass,
198 T_SIG);
199
200 /* allocate memory for answers */
201 rrset->rri_rdatas = calloc(rrset->rri_nrdatas,
202 sizeof(struct rdatainfo));
203 if (rrset->rri_rdatas == NULL) {
204 result = ERRSET_NOMEMORY;
205 goto fail;
206 }
207
208 /* allocate memory for signatures */
209 rrset->rri_sigs = calloc(rrset->rri_nsigs, sizeof(struct rdatainfo));
210 if (rrset->rri_sigs == NULL) {
211 result = ERRSET_NOMEMORY;
212 goto fail;
213 }
214
215 /* copy answers & signatures */
216 for (rr = response->answer, index_ans = 0, index_sig = 0;
217 rr; rr = rr->next) {
218
219 rdata = NULL;
220
221 if (rr->class == rrset->rri_rdclass &&
222 rr->type == rrset->rri_rdtype)
223 rdata = &rrset->rri_rdatas[index_ans++];
224
225 if (rr->class == rrset->rri_rdclass &&
226 rr->type == T_SIG)
227 rdata = &rrset->rri_sigs[index_sig++];
228
229 if (rdata) {
230 rdata->rdi_length = rr->size;
231 rdata->rdi_data = malloc(rr->size);
232
233 if (rdata->rdi_data == NULL) {
234 result = ERRSET_NOMEMORY;
235 goto fail;
236 }
237 memcpy(rdata->rdi_data, rr->rdata, rr->size);
238 }
239 }
240
241 *res = rrset;
242 return (ERRSET_SUCCESS);
243
244fail:
245 if (rrset != NULL)
246 freerrset(rrset);
247 return (result);
248}
249
250void
251freerrset(struct rrsetinfo *rrset)
252{
253 u_int16_t i;
254
255 if (rrset == NULL) {
256 return;
257 }
258
259 for (i = 0; i < rrset->rri_nrdatas; i++) {
260 if (rrset->rri_rdatas[i].rdi_data == NULL)
261 break;
262 free(rrset->rri_rdatas[i].rdi_data);
263 }
264 free(rrset->rri_rdatas);
265
266 for (i = 0; i < rrset->rri_nsigs; i++) {
267 if (rrset->rri_sigs[i].rdi_data == NULL)
268 break;
269 free(rrset->rri_sigs[i].rdi_data);
270 }
271 free(rrset->rri_sigs);
272
273 free(rrset->rri_name);
274
275 free(rrset);
276}
277
278
279/*
280 * DNS response parsing routines
281 */
282
283static struct dns_response *
284parse_dns_response(const char *answer, int size)
285{
286 struct dns_response *resp;
287 const char *cp;
288
289 /* allocate memory for the response */
290 resp = malloc(sizeof(*resp));
291 if (resp == NULL)
292 return (NULL);
293
294 /* initialize current pointer */
295 cp = answer;
296
297 /* copy header */
298 memcpy(&resp->header, cp, HFIXEDSZ);
299 cp += HFIXEDSZ;
300
301 /* fix header byte order */
302 resp->header.qdcount = ntohs(resp->header.qdcount);
303 resp->header.ancount = ntohs(resp->header.ancount);
304 resp->header.nscount = ntohs(resp->header.nscount);
305 resp->header.arcount = ntohs(resp->header.arcount);
306
307 /* there must be at least one query */
308 if (resp->header.qdcount < 1) {
309 free_dns_response(resp);
310 return (NULL);
311 }
312
313 /* parse query section */
314 resp->query = parse_dns_qsection(answer, size, &cp,
315 resp->header.qdcount);
316 if (resp->header.qdcount && resp->query == NULL) {
317 free_dns_response(resp);
318 return (NULL);
319 }
320
321 /* parse answer section */
322 resp->answer = parse_dns_rrsection(answer, size, &cp,
323 resp->header.ancount);
324 if (resp->header.ancount && resp->answer == NULL) {
325 free_dns_response(resp);
326 return (NULL);
327 }
328
329 /* parse authority section */
330 resp->authority = parse_dns_rrsection(answer, size, &cp,
331 resp->header.nscount);
332 if (resp->header.nscount && resp->authority == NULL) {
333 free_dns_response(resp);
334 return (NULL);
335 }
336
337 /* parse additional section */
338 resp->additional = parse_dns_rrsection(answer, size, &cp,
339 resp->header.arcount);
340 if (resp->header.arcount && resp->additional == NULL) {
341 free_dns_response(resp);
342 return (NULL);
343 }
344
345 return (resp);
346}
347
348static struct dns_query *
349parse_dns_qsection(const char *answer, int size, const char **cp, int count)
350{
351 struct dns_query *head, *curr, *prev;
352 int i, length;
353 char name[MAXDNAME];
354
355 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
356
357 /* allocate and initialize struct */
358 curr = calloc(1, sizeof(struct dns_query));
359 if (curr == NULL) {
360 free_dns_query(head);
361 return (NULL);
362 }
363 if (head == NULL)
364 head = curr;
365 if (prev != NULL)
366 prev->next = curr;
367
368 /* name */
369 length = dn_expand(answer, answer + size, *cp, name,
370 sizeof(name));
371 if (length < 0) {
372 free_dns_query(head);
373 return (NULL);
374 }
375 curr->name = strdup(name);
376 if (curr->name == NULL) {
377 free_dns_query(head);
378 return (NULL);
379 }
380 *cp += length;
381
382 /* type */
383 curr->type = _getshort(*cp);
384 *cp += INT16SZ;
385
386 /* class */
387 curr->class = _getshort(*cp);
388 *cp += INT16SZ;
389 }
390
391 return (head);
392}
393
394static struct dns_rr *
395parse_dns_rrsection(const char *answer, int size, const char **cp, int count)
396{
397 struct dns_rr *head, *curr, *prev;
398 int i, length;
399 char name[MAXDNAME];
400
401 for (i = 1, head = NULL, prev = NULL; i <= count; i++, prev = curr) {
402
403 /* allocate and initialize struct */
404 curr = calloc(1, sizeof(struct dns_rr));
405 if (curr == NULL) {
406 free_dns_rr(head);
407 return (NULL);
408 }
409 if (head == NULL)
410 head = curr;
411 if (prev != NULL)
412 prev->next = curr;
413
414 /* name */
415 length = dn_expand(answer, answer + size, *cp, name,
416 sizeof(name));
417 if (length < 0) {
418 free_dns_rr(head);
419 return (NULL);
420 }
421 curr->name = strdup(name);
422 if (curr->name == NULL) {
423 free_dns_rr(head);
424 return (NULL);
425 }
426 *cp += length;
427
428 /* type */
429 curr->type = _getshort(*cp);
430 *cp += INT16SZ;
431
432 /* class */
433 curr->class = _getshort(*cp);
434 *cp += INT16SZ;
435
436 /* ttl */
437 curr->ttl = _getlong(*cp);
438 *cp += INT32SZ;
439
440 /* rdata size */
441 curr->size = _getshort(*cp);
442 *cp += INT16SZ;
443
444 /* rdata itself */
445 curr->rdata = malloc(curr->size);
446 if (curr->rdata == NULL) {
447 free_dns_rr(head);
448 return (NULL);
449 }
450 memcpy(curr->rdata, *cp, curr->size);
451 *cp += curr->size;
452 }
453
454 return (head);
455}
456
457
458static void
459free_dns_query(struct dns_query *p)
460{
461 if (p == NULL)
462 return;
463
464 free(p->name);
465 free_dns_query(p->next);
466 free(p);
467}
468
469static void
470free_dns_rr(struct dns_rr *p)
471{
472 if (p == NULL)
473 return;
474
475 free(p->name);
476 free(p->rdata);
477 free_dns_rr(p->next);
478 free(p);
479}
480
481static void
482free_dns_response(struct dns_response *p)
483{
484 if (p == NULL)
485 return;
486
487 free_dns_query(p->query);
488 free_dns_rr(p->answer);
489 free_dns_rr(p->authority);
490 free_dns_rr(p->additional);
491 free(p);
492}
493
494static int
495count_dns_rr(struct dns_rr *p, u_int16_t class, u_int16_t type)
496{
497 int n = 0;
498
499 while(p) {
500 if (p->class == class && p->type == type)
501 n++;
502 p = p->next;
503 };
504
505 return (n);
506}