1 /* $NetBSD: lwdgrbn.c,v 1.6 2014/12/10 04:37:51 christos Exp $ */
4 * Copyright (C) 2004-2007, 2009, 2013, 2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: lwdgrbn.c,v 1.22 2009/09/02 23:48:01 tbox Exp */
27 #include <isc/socket.h>
28 #include <isc/string.h> /* Required for HP/UX (and others?) */
32 #include <dns/lookup.h>
33 #include <dns/rdata.h>
34 #include <dns/rdataset.h>
35 #include <dns/rdatasetiter.h>
36 #include <dns/result.h>
39 #include <named/types.h>
40 #include <named/lwdclient.h>
41 #include <named/lwresd.h>
42 #include <named/lwsearch.h>
44 static void start_lookup(ns_lwdclient_t
*);
47 fill_array(int *pos
, dns_rdataset_t
*rdataset
,
48 int size
, unsigned char **rdatas
, lwres_uint16_t
*rdatalen
)
56 dns_rdata_init(&rdata
);
57 for (result
= dns_rdataset_first(rdataset
);
58 result
== ISC_R_SUCCESS
;
59 result
= dns_rdataset_next(rdataset
))
62 dns_rdataset_current(rdataset
, &rdata
);
63 dns_rdata_toregion(&rdata
, &r
);
64 rdatas
[*pos
] = r
.base
;
65 rdatalen
[*pos
] = r
.length
;
66 dns_rdata_reset(&rdata
);
69 if (result
== ISC_R_NOMORE
)
70 result
= ISC_R_SUCCESS
;
75 iterate_node(lwres_grbnresponse_t
*grbn
, dns_db_t
*db
, dns_dbnode_t
*node
,
79 int size
= 8, oldsize
= 0;
80 unsigned char **rdatas
= NULL
, **oldrdatas
= NULL
, **newrdatas
= NULL
;
81 lwres_uint16_t
*lens
= NULL
, *oldlens
= NULL
, *newlens
= NULL
;
82 dns_rdatasetiter_t
*iter
= NULL
;
84 dns_ttl_t ttl
= ISC_INT32_MAX
;
85 lwres_uint32_t flags
= LWRDATA_VALIDATED
;
86 isc_result_t result
= ISC_R_NOMEMORY
;
88 result
= dns_db_allrdatasets(db
, node
, NULL
, 0, &iter
);
89 if (result
!= ISC_R_SUCCESS
)
92 rdatas
= isc_mem_get(mctx
, size
* sizeof(*rdatas
));
95 lens
= isc_mem_get(mctx
, size
* sizeof(*lens
));
99 for (result
= dns_rdatasetiter_first(iter
);
100 result
== ISC_R_SUCCESS
;
101 result
= dns_rdatasetiter_next(iter
))
103 result
= ISC_R_NOMEMORY
;
104 dns_rdataset_init(&set
);
105 dns_rdatasetiter_current(iter
, &set
);
107 if (set
.type
!= dns_rdatatype_rrsig
) {
108 dns_rdataset_disassociate(&set
);
112 count
= dns_rdataset_count(&set
);
113 if (used
+ count
> size
) {
114 /* copy & reallocate */
123 rdatas
= isc_mem_get(mctx
, size
* sizeof(*rdatas
));
126 lens
= isc_mem_get(mctx
, size
* sizeof(*lens
));
129 memmove(rdatas
, oldrdatas
, used
* sizeof(*rdatas
));
130 memmove(lens
, oldlens
, used
* sizeof(*lens
));
131 isc_mem_put(mctx
, oldrdatas
,
132 oldsize
* sizeof(*oldrdatas
));
133 isc_mem_put(mctx
, oldlens
, oldsize
* sizeof(*oldlens
));
139 if (set
.trust
!= dns_trust_secure
)
140 flags
&= (~LWRDATA_VALIDATED
);
141 result
= fill_array(&used
, &set
, size
, rdatas
, lens
);
142 dns_rdataset_disassociate(&set
);
143 if (result
!= ISC_R_SUCCESS
)
146 if (result
== ISC_R_NOMORE
)
147 result
= ISC_R_SUCCESS
;
148 if (result
!= ISC_R_SUCCESS
)
150 dns_rdatasetiter_destroy(&iter
);
153 * If necessary, shrink and copy the arrays.
156 result
= ISC_R_NOMEMORY
;
157 newrdatas
= isc_mem_get(mctx
, used
* sizeof(*rdatas
));
158 if (newrdatas
== NULL
)
160 newlens
= isc_mem_get(mctx
, used
* sizeof(*lens
));
163 memmove(newrdatas
, rdatas
, used
* sizeof(*rdatas
));
164 memmove(newlens
, lens
, used
* sizeof(*lens
));
165 isc_mem_put(mctx
, rdatas
, size
* sizeof(*rdatas
));
166 isc_mem_put(mctx
, lens
, size
* sizeof(*lens
));
167 grbn
->rdatas
= newrdatas
;
168 grbn
->rdatalen
= newlens
;
170 grbn
->rdatas
= rdatas
;
171 grbn
->rdatalen
= lens
;
173 grbn
->nrdatas
= used
;
176 return (ISC_R_SUCCESS
);
179 dns_rdatasetiter_destroy(&iter
);
181 isc_mem_put(mctx
, rdatas
, size
* sizeof(*rdatas
));
183 isc_mem_put(mctx
, lens
, size
* sizeof(*lens
));
184 if (oldrdatas
!= NULL
)
185 isc_mem_put(mctx
, oldrdatas
, oldsize
* sizeof(*oldrdatas
));
187 isc_mem_put(mctx
, oldlens
, oldsize
* sizeof(*oldlens
));
188 if (newrdatas
!= NULL
)
189 isc_mem_put(mctx
, newrdatas
, used
* sizeof(*oldrdatas
));
194 lookup_done(isc_task_t
*task
, isc_event_t
*event
) {
195 ns_lwdclient_t
*client
;
196 ns_lwdclientmgr_t
*cm
;
197 dns_lookupevent_t
*levent
;
200 dns_rdataset_t
*rdataset
;
201 dns_rdataset_t
*sigrdataset
;
203 lwres_result_t lwresult
;
206 lwres_grbnresponse_t
*grbn
;
209 REQUIRE(event
!= NULL
);
214 client
= event
->ev_arg
;
215 cm
= client
->clientmgr
;
216 INSIST(client
->lookup
== (dns_lookup_t
*)event
->ev_sender
);
218 levent
= (dns_lookupevent_t
*)event
;
219 grbn
= &client
->grbn
;
221 ns_lwdclient_log(50, "lookup event result = %s",
222 isc_result_totext(levent
->result
));
224 result
= levent
->result
;
225 if (result
!= ISC_R_SUCCESS
) {
226 dns_lookup_destroy(&client
->lookup
);
227 isc_event_free(&event
);
232 case DNS_R_NCACHENXDOMAIN
:
233 result
= ns_lwsearchctx_next(&client
->searchctx
);
234 if (result
!= ISC_R_SUCCESS
)
235 lwresult
= LWRES_R_NOTFOUND
;
237 start_lookup(client
);
242 case DNS_R_NCACHENXRRSET
:
243 lwresult
= LWRES_R_TYPENOTFOUND
;
246 lwresult
= LWRES_R_FAILURE
;
248 ns_lwdclient_errorpktsend(client
, lwresult
);
253 b
= client
->recv_buffer
;
259 grbn
->rdatalen
= NULL
;
265 result
= dns_name_totext(name
, ISC_TRUE
, &client
->recv_buffer
);
266 if (result
!= ISC_R_SUCCESS
)
268 grbn
->realname
= (char *)isc_buffer_used(&b
);
269 grbn
->realnamelen
= isc_buffer_usedlength(&client
->recv_buffer
) -
270 isc_buffer_usedlength(&b
);
271 ns_lwdclient_log(50, "found name '%.*s'", grbn
->realnamelen
,
274 grbn
->rdclass
= cm
->view
->rdclass
;
275 grbn
->rdtype
= client
->rdtype
;
277 rdataset
= levent
->rdataset
;
278 if (rdataset
!= NULL
) {
279 /* The normal case */
280 grbn
->nrdatas
= dns_rdataset_count(rdataset
);
281 grbn
->rdatas
= isc_mem_get(cm
->mctx
, grbn
->nrdatas
*
282 sizeof(unsigned char *));
283 if (grbn
->rdatas
== NULL
)
285 grbn
->rdatalen
= isc_mem_get(cm
->mctx
, grbn
->nrdatas
*
286 sizeof(lwres_uint16_t
));
287 if (grbn
->rdatalen
== NULL
)
291 result
= fill_array(&i
, rdataset
, grbn
->nrdatas
, grbn
->rdatas
,
293 if (result
!= ISC_R_SUCCESS
)
295 INSIST(i
== grbn
->nrdatas
);
296 grbn
->ttl
= rdataset
->ttl
;
297 if (rdataset
->trust
== dns_trust_secure
)
298 grbn
->flags
|= LWRDATA_VALIDATED
;
300 /* The SIG query case */
301 result
= iterate_node(grbn
, levent
->db
, levent
->node
,
303 if (result
!= ISC_R_SUCCESS
)
306 ns_lwdclient_log(50, "filled in %d rdata%s", grbn
->nrdatas
,
307 (grbn
->nrdatas
== 1) ? "" : "s");
309 sigrdataset
= levent
->sigrdataset
;
310 if (sigrdataset
!= NULL
) {
311 grbn
->nsigs
= dns_rdataset_count(sigrdataset
);
312 grbn
->sigs
= isc_mem_get(cm
->mctx
, grbn
->nsigs
*
313 sizeof(unsigned char *));
314 if (grbn
->sigs
== NULL
)
316 grbn
->siglen
= isc_mem_get(cm
->mctx
, grbn
->nsigs
*
317 sizeof(lwres_uint16_t
));
318 if (grbn
->siglen
== NULL
)
322 result
= fill_array(&i
, sigrdataset
, grbn
->nsigs
, grbn
->sigs
,
324 if (result
!= ISC_R_SUCCESS
)
326 INSIST(i
== grbn
->nsigs
);
327 ns_lwdclient_log(50, "filled in %d signature%s", grbn
->nsigs
,
328 (grbn
->nsigs
== 1) ? "" : "s");
334 client
->pkt
.recvlength
= LWRES_RECVLENGTH
;
335 client
->pkt
.authtype
= 0; /* XXXMLG */
336 client
->pkt
.authlength
= 0;
337 client
->pkt
.result
= LWRES_R_SUCCESS
;
339 lwresult
= lwres_grbnresponse_render(cm
->lwctx
,
340 grbn
, &client
->pkt
, &lwb
);
341 if (lwresult
!= LWRES_R_SUCCESS
)
344 isc_mem_put(cm
->mctx
, grbn
->rdatas
,
345 grbn
->nrdatas
* sizeof(unsigned char *));
346 isc_mem_put(cm
->mctx
, grbn
->rdatalen
,
347 grbn
->nrdatas
* sizeof(lwres_uint16_t
));
349 if (grbn
->sigs
!= NULL
)
350 isc_mem_put(cm
->mctx
, grbn
->sigs
,
351 grbn
->nsigs
* sizeof(unsigned char *));
352 if (grbn
->siglen
!= NULL
)
353 isc_mem_put(cm
->mctx
, grbn
->siglen
,
354 grbn
->nsigs
* sizeof(lwres_uint16_t
));
358 client
->sendbuf
= r
.base
;
359 client
->sendlength
= r
.length
;
360 result
= ns_lwdclient_sendreply(client
, &r
);
361 if (result
!= ISC_R_SUCCESS
)
364 NS_LWDCLIENT_SETSEND(client
);
366 dns_lookup_destroy(&client
->lookup
);
367 isc_event_free(&event
);
372 if (grbn
->rdatas
!= NULL
)
373 isc_mem_put(cm
->mctx
, grbn
->rdatas
,
374 grbn
->nrdatas
* sizeof(unsigned char *));
375 if (grbn
->rdatalen
!= NULL
)
376 isc_mem_put(cm
->mctx
, grbn
->rdatalen
,
377 grbn
->nrdatas
* sizeof(lwres_uint16_t
));
379 if (grbn
->sigs
!= NULL
)
380 isc_mem_put(cm
->mctx
, grbn
->sigs
,
381 grbn
->nsigs
* sizeof(unsigned char *));
382 if (grbn
->siglen
!= NULL
)
383 isc_mem_put(cm
->mctx
, grbn
->siglen
,
384 grbn
->nsigs
* sizeof(lwres_uint16_t
));
386 if (client
->lookup
!= NULL
)
387 dns_lookup_destroy(&client
->lookup
);
388 if (lwb
.base
!= NULL
)
389 lwres_context_freemem(cm
->lwctx
, lwb
.base
, lwb
.length
);
391 isc_event_free(&event
);
393 ns_lwdclient_log(50, "error constructing getrrsetbyname response");
394 ns_lwdclient_errorpktsend(client
, LWRES_R_FAILURE
);
398 start_lookup(ns_lwdclient_t
*client
) {
400 ns_lwdclientmgr_t
*cm
;
401 dns_fixedname_t absname
;
403 cm
= client
->clientmgr
;
405 INSIST(client
->lookup
== NULL
);
407 dns_fixedname_init(&absname
);
408 result
= ns_lwsearchctx_current(&client
->searchctx
,
409 dns_fixedname_name(&absname
));
411 * This will return failure if relative name + suffix is too long.
412 * In this case, just go on to the next entry in the search path.
414 if (result
!= ISC_R_SUCCESS
)
415 start_lookup(client
);
417 result
= dns_lookup_create(cm
->mctx
,
418 dns_fixedname_name(&absname
),
419 client
->rdtype
, cm
->view
,
420 client
->options
, cm
->task
, lookup_done
,
421 client
, &client
->lookup
);
422 if (result
!= ISC_R_SUCCESS
) {
423 ns_lwdclient_errorpktsend(client
, LWRES_R_FAILURE
);
429 init_grbn(ns_lwdclient_t
*client
) {
430 client
->grbn
.rdclass
= 0;
431 client
->grbn
.rdtype
= 0;
432 client
->grbn
.ttl
= 0;
433 client
->grbn
.nrdatas
= 0;
434 client
->grbn
.realname
= NULL
;
435 client
->grbn
.realnamelen
= 0;
436 client
->grbn
.rdatas
= 0;
437 client
->grbn
.rdatalen
= 0;
438 client
->grbn
.base
= NULL
;
439 client
->grbn
.baselen
= 0;
440 isc_buffer_init(&client
->recv_buffer
, client
->buffer
, LWRES_RECVLENGTH
);
444 ns_lwdclient_processgrbn(ns_lwdclient_t
*client
, lwres_buffer_t
*b
) {
445 lwres_grbnrequest_t
*req
;
447 ns_lwdclientmgr_t
*cm
;
448 isc_buffer_t namebuf
;
450 REQUIRE(NS_LWDCLIENT_ISRECVDONE(client
));
451 INSIST(client
->byaddr
== NULL
);
453 cm
= client
->clientmgr
;
456 result
= lwres_grbnrequest_parse(cm
->lwctx
,
457 b
, &client
->pkt
, &req
);
458 if (result
!= LWRES_R_SUCCESS
)
460 if (req
->name
== NULL
)
464 if (req
->rdclass
!= cm
->view
->rdclass
)
467 if (req
->rdclass
== dns_rdataclass_any
||
468 req
->rdtype
== dns_rdatatype_any
)
471 client
->rdtype
= req
->rdtype
;
473 isc_buffer_init(&namebuf
, req
->name
, req
->namelen
);
474 isc_buffer_add(&namebuf
, req
->namelen
);
476 dns_fixedname_init(&client
->query_name
);
477 result
= dns_name_fromtext(dns_fixedname_name(&client
->query_name
),
478 &namebuf
, NULL
, 0, NULL
);
479 if (result
!= ISC_R_SUCCESS
)
481 ns_lwsearchctx_init(&client
->searchctx
,
482 cm
->listener
->manager
->search
,
483 dns_fixedname_name(&client
->query_name
),
484 cm
->listener
->manager
->ndots
);
485 ns_lwsearchctx_first(&client
->searchctx
);
487 ns_lwdclient_log(50, "client %p looking for type %d",
488 client
, client
->rdtype
);
491 * We no longer need to keep this around.
493 lwres_grbnrequest_free(cm
->lwctx
, &req
);
496 * Initialize the real name and alias arrays in the reply we're
504 start_lookup(client
);
509 * We're screwed. Return an error packet to our caller.
513 lwres_grbnrequest_free(cm
->lwctx
, &req
);
515 ns_lwdclient_errorpktsend(client
, LWRES_R_FAILURE
);