2 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: lwdgrbn.c,v 1.20 2007/06/19 23:46:59 tbox Exp $ */
25 #include <isc/socket.h>
26 #include <isc/string.h> /* Required for HP/UX (and others?) */
30 #include <dns/lookup.h>
31 #include <dns/rdata.h>
32 #include <dns/rdataset.h>
33 #include <dns/rdatasetiter.h>
34 #include <dns/result.h>
37 #include <named/types.h>
38 #include <named/lwdclient.h>
39 #include <named/lwresd.h>
40 #include <named/lwsearch.h>
42 static void start_lookup(ns_lwdclient_t
*);
45 fill_array(int *pos
, dns_rdataset_t
*rdataset
,
46 int size
, unsigned char **rdatas
, lwres_uint16_t
*rdatalen
)
54 dns_rdata_init(&rdata
);
55 for (result
= dns_rdataset_first(rdataset
);
56 result
== ISC_R_SUCCESS
;
57 result
= dns_rdataset_next(rdataset
))
60 dns_rdataset_current(rdataset
, &rdata
);
61 dns_rdata_toregion(&rdata
, &r
);
62 rdatas
[*pos
] = r
.base
;
63 rdatalen
[*pos
] = r
.length
;
64 dns_rdata_reset(&rdata
);
67 if (result
== ISC_R_NOMORE
)
68 result
= ISC_R_SUCCESS
;
73 iterate_node(lwres_grbnresponse_t
*grbn
, dns_db_t
*db
, dns_dbnode_t
*node
,
77 int size
= 8, oldsize
= 0;
78 unsigned char **rdatas
= NULL
, **oldrdatas
= NULL
, **newrdatas
= NULL
;
79 lwres_uint16_t
*lens
= NULL
, *oldlens
= NULL
, *newlens
= NULL
;
80 dns_rdatasetiter_t
*iter
= NULL
;
82 dns_ttl_t ttl
= ISC_INT32_MAX
;
83 lwres_uint32_t flags
= LWRDATA_VALIDATED
;
84 isc_result_t result
= ISC_R_NOMEMORY
;
86 result
= dns_db_allrdatasets(db
, node
, NULL
, 0, &iter
);
87 if (result
!= ISC_R_SUCCESS
)
90 rdatas
= isc_mem_get(mctx
, size
* sizeof(*rdatas
));
93 lens
= isc_mem_get(mctx
, size
* sizeof(*lens
));
97 for (result
= dns_rdatasetiter_first(iter
);
98 result
== ISC_R_SUCCESS
;
99 result
= dns_rdatasetiter_next(iter
))
101 result
= ISC_R_NOMEMORY
;
102 dns_rdataset_init(&set
);
103 dns_rdatasetiter_current(iter
, &set
);
105 if (set
.type
!= dns_rdatatype_rrsig
) {
106 dns_rdataset_disassociate(&set
);
110 count
= dns_rdataset_count(&set
);
111 if (used
+ count
> size
) {
112 /* copy & reallocate */
121 rdatas
= isc_mem_get(mctx
, size
* sizeof(*rdatas
));
124 lens
= isc_mem_get(mctx
, size
* sizeof(*lens
));
127 memcpy(rdatas
, oldrdatas
, used
* sizeof(*rdatas
));
128 memcpy(lens
, oldlens
, used
* sizeof(*lens
));
129 isc_mem_put(mctx
, oldrdatas
,
130 oldsize
* sizeof(*oldrdatas
));
131 isc_mem_put(mctx
, oldlens
, oldsize
* sizeof(*oldlens
));
137 if (set
.trust
!= dns_trust_secure
)
138 flags
&= (~LWRDATA_VALIDATED
);
139 result
= fill_array(&used
, &set
, size
, rdatas
, lens
);
140 dns_rdataset_disassociate(&set
);
141 if (result
!= ISC_R_SUCCESS
)
144 if (result
== ISC_R_NOMORE
)
145 result
= ISC_R_SUCCESS
;
146 if (result
!= ISC_R_SUCCESS
)
148 dns_rdatasetiter_destroy(&iter
);
151 * If necessary, shrink and copy the arrays.
154 result
= ISC_R_NOMEMORY
;
155 newrdatas
= isc_mem_get(mctx
, used
* sizeof(*rdatas
));
156 if (newrdatas
== NULL
)
158 newlens
= isc_mem_get(mctx
, used
* sizeof(*lens
));
161 memcpy(newrdatas
, rdatas
, used
* sizeof(*rdatas
));
162 memcpy(newlens
, lens
, used
* sizeof(*lens
));
163 isc_mem_put(mctx
, rdatas
, size
* sizeof(*rdatas
));
164 isc_mem_put(mctx
, lens
, size
* sizeof(*lens
));
165 grbn
->rdatas
= newrdatas
;
166 grbn
->rdatalen
= newlens
;
168 grbn
->rdatas
= rdatas
;
169 grbn
->rdatalen
= lens
;
171 grbn
->nrdatas
= used
;
174 return (ISC_R_SUCCESS
);
177 dns_rdatasetiter_destroy(&iter
);
179 isc_mem_put(mctx
, rdatas
, size
* sizeof(*rdatas
));
181 isc_mem_put(mctx
, lens
, size
* sizeof(*lens
));
182 if (oldrdatas
!= NULL
)
183 isc_mem_put(mctx
, oldrdatas
, oldsize
* sizeof(*oldrdatas
));
185 isc_mem_put(mctx
, oldlens
, oldsize
* sizeof(*oldlens
));
186 if (newrdatas
!= NULL
)
187 isc_mem_put(mctx
, newrdatas
, used
* sizeof(*oldrdatas
));
192 lookup_done(isc_task_t
*task
, isc_event_t
*event
) {
193 ns_lwdclient_t
*client
;
194 ns_lwdclientmgr_t
*cm
;
195 dns_lookupevent_t
*levent
;
198 dns_rdataset_t
*rdataset
;
199 dns_rdataset_t
*sigrdataset
;
201 lwres_result_t lwresult
;
204 lwres_grbnresponse_t
*grbn
;
210 client
= event
->ev_arg
;
211 cm
= client
->clientmgr
;
212 INSIST(client
->lookup
== (dns_lookup_t
*)event
->ev_sender
);
214 levent
= (dns_lookupevent_t
*)event
;
215 grbn
= &client
->grbn
;
217 ns_lwdclient_log(50, "lookup event result = %s",
218 isc_result_totext(levent
->result
));
220 result
= levent
->result
;
221 if (result
!= ISC_R_SUCCESS
) {
222 dns_lookup_destroy(&client
->lookup
);
223 isc_event_free(&event
);
228 case DNS_R_NCACHENXDOMAIN
:
229 result
= ns_lwsearchctx_next(&client
->searchctx
);
230 if (result
!= ISC_R_SUCCESS
)
231 lwresult
= LWRES_R_NOTFOUND
;
233 start_lookup(client
);
238 case DNS_R_NCACHENXRRSET
:
239 lwresult
= LWRES_R_TYPENOTFOUND
;
242 lwresult
= LWRES_R_FAILURE
;
244 ns_lwdclient_errorpktsend(client
, lwresult
);
249 b
= client
->recv_buffer
;
255 grbn
->rdatalen
= NULL
;
261 result
= dns_name_totext(name
, ISC_TRUE
, &client
->recv_buffer
);
262 if (result
!= ISC_R_SUCCESS
)
264 grbn
->realname
= (char *)isc_buffer_used(&b
);
265 grbn
->realnamelen
= isc_buffer_usedlength(&client
->recv_buffer
) -
266 isc_buffer_usedlength(&b
);
267 ns_lwdclient_log(50, "found name '%.*s'", grbn
->realnamelen
,
270 grbn
->rdclass
= cm
->view
->rdclass
;
271 grbn
->rdtype
= client
->rdtype
;
273 rdataset
= levent
->rdataset
;
274 if (rdataset
!= NULL
) {
275 /* The normal case */
276 grbn
->nrdatas
= dns_rdataset_count(rdataset
);
277 grbn
->rdatas
= isc_mem_get(cm
->mctx
, grbn
->nrdatas
*
278 sizeof(unsigned char *));
279 if (grbn
->rdatas
== NULL
)
281 grbn
->rdatalen
= isc_mem_get(cm
->mctx
, grbn
->nrdatas
*
282 sizeof(lwres_uint16_t
));
283 if (grbn
->rdatalen
== NULL
)
287 result
= fill_array(&i
, rdataset
, grbn
->nrdatas
, grbn
->rdatas
,
289 if (result
!= ISC_R_SUCCESS
)
291 INSIST(i
== grbn
->nrdatas
);
292 grbn
->ttl
= rdataset
->ttl
;
293 if (rdataset
->trust
== dns_trust_secure
)
294 grbn
->flags
|= LWRDATA_VALIDATED
;
296 /* The SIG query case */
297 result
= iterate_node(grbn
, levent
->db
, levent
->node
,
299 if (result
!= ISC_R_SUCCESS
)
302 ns_lwdclient_log(50, "filled in %d rdata%s", grbn
->nrdatas
,
303 (grbn
->nrdatas
== 1) ? "" : "s");
305 sigrdataset
= levent
->sigrdataset
;
306 if (sigrdataset
!= NULL
) {
307 grbn
->nsigs
= dns_rdataset_count(sigrdataset
);
308 grbn
->sigs
= isc_mem_get(cm
->mctx
, grbn
->nsigs
*
309 sizeof(unsigned char *));
310 if (grbn
->sigs
== NULL
)
312 grbn
->siglen
= isc_mem_get(cm
->mctx
, grbn
->nsigs
*
313 sizeof(lwres_uint16_t
));
314 if (grbn
->siglen
== NULL
)
318 result
= fill_array(&i
, sigrdataset
, grbn
->nsigs
, grbn
->sigs
,
320 if (result
!= ISC_R_SUCCESS
)
322 INSIST(i
== grbn
->nsigs
);
323 ns_lwdclient_log(50, "filled in %d signature%s", grbn
->nsigs
,
324 (grbn
->nsigs
== 1) ? "" : "s");
327 dns_lookup_destroy(&client
->lookup
);
328 isc_event_free(&event
);
333 client
->pkt
.recvlength
= LWRES_RECVLENGTH
;
334 client
->pkt
.authtype
= 0; /* XXXMLG */
335 client
->pkt
.authlength
= 0;
336 client
->pkt
.result
= LWRES_R_SUCCESS
;
338 lwresult
= lwres_grbnresponse_render(cm
->lwctx
,
339 grbn
, &client
->pkt
, &lwb
);
340 if (lwresult
!= LWRES_R_SUCCESS
)
343 isc_mem_put(cm
->mctx
, grbn
->rdatas
,
344 grbn
->nrdatas
* sizeof(unsigned char *));
345 isc_mem_put(cm
->mctx
, grbn
->rdatalen
,
346 grbn
->nrdatas
* sizeof(lwres_uint16_t
));
348 if (grbn
->sigs
!= NULL
)
349 isc_mem_put(cm
->mctx
, grbn
->sigs
,
350 grbn
->nsigs
* sizeof(unsigned char *));
351 if (grbn
->siglen
!= NULL
)
352 isc_mem_put(cm
->mctx
, grbn
->siglen
,
353 grbn
->nsigs
* sizeof(lwres_uint16_t
));
357 client
->sendbuf
= r
.base
;
358 client
->sendlength
= r
.length
;
359 result
= ns_lwdclient_sendreply(client
, &r
);
360 if (result
!= ISC_R_SUCCESS
)
363 NS_LWDCLIENT_SETSEND(client
);
368 if (grbn
->rdatas
!= NULL
)
369 isc_mem_put(cm
->mctx
, grbn
->rdatas
,
370 grbn
->nrdatas
* sizeof(unsigned char *));
371 if (grbn
->rdatalen
!= NULL
)
372 isc_mem_put(cm
->mctx
, grbn
->rdatalen
,
373 grbn
->nrdatas
* sizeof(lwres_uint16_t
));
375 if (grbn
->sigs
!= NULL
)
376 isc_mem_put(cm
->mctx
, grbn
->sigs
,
377 grbn
->nsigs
* sizeof(unsigned char *));
378 if (grbn
->siglen
!= NULL
)
379 isc_mem_put(cm
->mctx
, grbn
->siglen
,
380 grbn
->nsigs
* sizeof(lwres_uint16_t
));
382 if (client
->lookup
!= NULL
)
383 dns_lookup_destroy(&client
->lookup
);
384 if (lwb
.base
!= NULL
)
385 lwres_context_freemem(cm
->lwctx
, lwb
.base
, lwb
.length
);
388 isc_event_free(&event
);
390 ns_lwdclient_log(50, "error constructing getrrsetbyname response");
391 ns_lwdclient_errorpktsend(client
, LWRES_R_FAILURE
);
395 start_lookup(ns_lwdclient_t
*client
) {
397 ns_lwdclientmgr_t
*cm
;
398 dns_fixedname_t absname
;
400 cm
= client
->clientmgr
;
402 INSIST(client
->lookup
== NULL
);
404 dns_fixedname_init(&absname
);
405 result
= ns_lwsearchctx_current(&client
->searchctx
,
406 dns_fixedname_name(&absname
));
408 * This will return failure if relative name + suffix is too long.
409 * In this case, just go on to the next entry in the search path.
411 if (result
!= ISC_R_SUCCESS
)
412 start_lookup(client
);
414 result
= dns_lookup_create(cm
->mctx
,
415 dns_fixedname_name(&absname
),
416 client
->rdtype
, cm
->view
,
417 client
->options
, cm
->task
, lookup_done
,
418 client
, &client
->lookup
);
419 if (result
!= ISC_R_SUCCESS
) {
420 ns_lwdclient_errorpktsend(client
, LWRES_R_FAILURE
);
426 init_grbn(ns_lwdclient_t
*client
) {
427 client
->grbn
.rdclass
= 0;
428 client
->grbn
.rdtype
= 0;
429 client
->grbn
.ttl
= 0;
430 client
->grbn
.nrdatas
= 0;
431 client
->grbn
.realname
= NULL
;
432 client
->grbn
.realnamelen
= 0;
433 client
->grbn
.rdatas
= 0;
434 client
->grbn
.rdatalen
= 0;
435 client
->grbn
.base
= NULL
;
436 client
->grbn
.baselen
= 0;
437 isc_buffer_init(&client
->recv_buffer
, client
->buffer
, LWRES_RECVLENGTH
);
441 ns_lwdclient_processgrbn(ns_lwdclient_t
*client
, lwres_buffer_t
*b
) {
442 lwres_grbnrequest_t
*req
;
444 ns_lwdclientmgr_t
*cm
;
445 isc_buffer_t namebuf
;
447 REQUIRE(NS_LWDCLIENT_ISRECVDONE(client
));
448 INSIST(client
->byaddr
== NULL
);
450 cm
= client
->clientmgr
;
453 result
= lwres_grbnrequest_parse(cm
->lwctx
,
454 b
, &client
->pkt
, &req
);
455 if (result
!= LWRES_R_SUCCESS
)
457 if (req
->name
== NULL
)
461 if (req
->rdclass
!= cm
->view
->rdclass
)
464 if (req
->rdclass
== dns_rdataclass_any
||
465 req
->rdtype
== dns_rdatatype_any
)
468 client
->rdtype
= req
->rdtype
;
470 isc_buffer_init(&namebuf
, req
->name
, req
->namelen
);
471 isc_buffer_add(&namebuf
, req
->namelen
);
473 dns_fixedname_init(&client
->query_name
);
474 result
= dns_name_fromtext(dns_fixedname_name(&client
->query_name
),
475 &namebuf
, NULL
, ISC_FALSE
, NULL
);
476 if (result
!= ISC_R_SUCCESS
)
478 ns_lwsearchctx_init(&client
->searchctx
,
479 cm
->listener
->manager
->search
,
480 dns_fixedname_name(&client
->query_name
),
481 cm
->listener
->manager
->ndots
);
482 ns_lwsearchctx_first(&client
->searchctx
);
484 ns_lwdclient_log(50, "client %p looking for type %d",
485 client
, client
->rdtype
);
488 * We no longer need to keep this around.
490 lwres_grbnrequest_free(cm
->lwctx
, &req
);
493 * Initialize the real name and alias arrays in the reply we're
501 start_lookup(client
);
506 * We're screwed. Return an error packet to our caller.
510 lwres_grbnrequest_free(cm
->lwctx
, &req
);
512 ns_lwdclient_errorpktsend(client
, LWRES_R_FAILURE
);