1/* 2 * Copyright (C) 2004-2007, 2009, 2013, 2014 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium. 4 * 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. 8 * 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. 16 */ 17 18/* $Id: lwdgrbn.c,v 1.22 2009/09/02 23:48:01 tbox Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23 24#include <isc/mem.h> 25#include <isc/socket.h> 26#include <isc/string.h> /* Required for HP/UX (and others?) */ 27#include <isc/util.h> 28 29#include <dns/db.h> 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> 35#include <dns/view.h> 36 37#include <named/types.h> 38#include <named/lwdclient.h> 39#include <named/lwresd.h> 40#include <named/lwsearch.h> 41 42static void start_lookup(ns_lwdclient_t *); 43 44static isc_result_t 45fill_array(int *pos, dns_rdataset_t *rdataset, 46 int size, unsigned char **rdatas, lwres_uint16_t *rdatalen) 47{ 48 dns_rdata_t rdata; 49 isc_result_t result; 50 isc_region_t r; 51 52 UNUSED(size); 53 54 dns_rdata_init(&rdata); 55 for (result = dns_rdataset_first(rdataset); 56 result == ISC_R_SUCCESS; 57 result = dns_rdataset_next(rdataset)) 58 { 59 INSIST(*pos < size); 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); 65 (*pos)++; 66 } 67 if (result == ISC_R_NOMORE) 68 result = ISC_R_SUCCESS; 69 return (result); 70} 71 72static isc_result_t 73iterate_node(lwres_grbnresponse_t *grbn, dns_db_t *db, dns_dbnode_t *node, 74 isc_mem_t *mctx) 75{ 76 int used = 0, count; 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; 81 dns_rdataset_t set; 82 dns_ttl_t ttl = ISC_INT32_MAX; 83 lwres_uint32_t flags = LWRDATA_VALIDATED; 84 isc_result_t result = ISC_R_NOMEMORY; 85 86 result = dns_db_allrdatasets(db, node, NULL, 0, &iter); 87 if (result != ISC_R_SUCCESS) 88 goto out; 89 90 rdatas = isc_mem_get(mctx, size * sizeof(*rdatas)); 91 if (rdatas == NULL) 92 goto out; 93 lens = isc_mem_get(mctx, size * sizeof(*lens)); 94 if (lens == NULL) 95 goto out; 96 97 for (result = dns_rdatasetiter_first(iter); 98 result == ISC_R_SUCCESS; 99 result = dns_rdatasetiter_next(iter)) 100 { 101 result = ISC_R_NOMEMORY; 102 dns_rdataset_init(&set); 103 dns_rdatasetiter_current(iter, &set); 104 105 if (set.type != dns_rdatatype_rrsig) { 106 dns_rdataset_disassociate(&set); 107 continue; 108 } 109 110 count = dns_rdataset_count(&set); 111 if (used + count > size) { 112 /* copy & reallocate */ 113 oldsize = size; 114 oldrdatas = rdatas; 115 oldlens = lens; 116 rdatas = NULL; 117 lens = NULL; 118 119 size *= 2; 120 121 rdatas = isc_mem_get(mctx, size * sizeof(*rdatas)); 122 if (rdatas == NULL) 123 goto out; 124 lens = isc_mem_get(mctx, size * sizeof(*lens)); 125 if (lens == NULL) 126 goto out; 127 memmove(rdatas, oldrdatas, used * sizeof(*rdatas)); 128 memmove(lens, oldlens, used * sizeof(*lens)); 129 isc_mem_put(mctx, oldrdatas, 130 oldsize * sizeof(*oldrdatas)); 131 isc_mem_put(mctx, oldlens, oldsize * sizeof(*oldlens)); 132 oldrdatas = NULL; 133 oldlens = NULL; 134 } 135 if (set.ttl < ttl) 136 ttl = set.ttl; 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) 142 goto out; 143 } 144 if (result == ISC_R_NOMORE) 145 result = ISC_R_SUCCESS; 146 if (result != ISC_R_SUCCESS) 147 goto out; 148 dns_rdatasetiter_destroy(&iter); 149 150 /* 151 * If necessary, shrink and copy the arrays. 152 */ 153 if (size != used) { 154 result = ISC_R_NOMEMORY; 155 newrdatas = isc_mem_get(mctx, used * sizeof(*rdatas)); 156 if (newrdatas == NULL) 157 goto out; 158 newlens = isc_mem_get(mctx, used * sizeof(*lens)); 159 if (newlens == NULL) 160 goto out; 161 memmove(newrdatas, rdatas, used * sizeof(*rdatas)); 162 memmove(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; 167 } else { 168 grbn->rdatas = rdatas; 169 grbn->rdatalen = lens; 170 } 171 grbn->nrdatas = used; 172 grbn->ttl = ttl; 173 grbn->flags = flags; 174 return (ISC_R_SUCCESS); 175 176 out: 177 dns_rdatasetiter_destroy(&iter); 178 if (rdatas != NULL) 179 isc_mem_put(mctx, rdatas, size * sizeof(*rdatas)); 180 if (lens != NULL) 181 isc_mem_put(mctx, lens, size * sizeof(*lens)); 182 if (oldrdatas != NULL) 183 isc_mem_put(mctx, oldrdatas, oldsize * sizeof(*oldrdatas)); 184 if (oldlens != NULL) 185 isc_mem_put(mctx, oldlens, oldsize * sizeof(*oldlens)); 186 if (newrdatas != NULL) 187 isc_mem_put(mctx, newrdatas, used * sizeof(*oldrdatas)); 188 return (result); 189} 190 191static void 192lookup_done(isc_task_t *task, isc_event_t *event) { 193 ns_lwdclient_t *client; 194 ns_lwdclientmgr_t *cm; 195 dns_lookupevent_t *levent; 196 lwres_buffer_t lwb; 197 dns_name_t *name; 198 dns_rdataset_t *rdataset; 199 dns_rdataset_t *sigrdataset; 200 isc_result_t result; 201 lwres_result_t lwresult; 202 isc_region_t r; 203 isc_buffer_t b; 204 lwres_grbnresponse_t *grbn; 205 int i; 206 207 REQUIRE(event != NULL); 208 209 UNUSED(task); 210 211 lwb.base = NULL; 212 client = event->ev_arg; 213 cm = client->clientmgr; 214 INSIST(client->lookup == (dns_lookup_t *)event->ev_sender); 215 216 levent = (dns_lookupevent_t *)event; 217 grbn = &client->grbn; 218 219 ns_lwdclient_log(50, "lookup event result = %s", 220 isc_result_totext(levent->result)); 221 222 result = levent->result; 223 if (result != ISC_R_SUCCESS) { 224 dns_lookup_destroy(&client->lookup); 225 isc_event_free(&event); 226 levent = NULL; 227 228 switch (result) { 229 case DNS_R_NXDOMAIN: 230 case DNS_R_NCACHENXDOMAIN: 231 result = ns_lwsearchctx_next(&client->searchctx); 232 if (result != ISC_R_SUCCESS) 233 lwresult = LWRES_R_NOTFOUND; 234 else { 235 start_lookup(client); 236 return; 237 } 238 break; 239 case DNS_R_NXRRSET: 240 case DNS_R_NCACHENXRRSET: 241 lwresult = LWRES_R_TYPENOTFOUND; 242 break; 243 default: 244 lwresult = LWRES_R_FAILURE; 245 } 246 ns_lwdclient_errorpktsend(client, lwresult); 247 return; 248 } 249 250 name = levent->name; 251 b = client->recv_buffer; 252 253 grbn->flags = 0; 254 255 grbn->nrdatas = 0; 256 grbn->rdatas = NULL; 257 grbn->rdatalen = NULL; 258 259 grbn->nsigs = 0; 260 grbn->sigs = NULL; 261 grbn->siglen = NULL; 262 263 result = dns_name_totext(name, ISC_TRUE, &client->recv_buffer); 264 if (result != ISC_R_SUCCESS) 265 goto out; 266 grbn->realname = (char *)isc_buffer_used(&b); 267 grbn->realnamelen = isc_buffer_usedlength(&client->recv_buffer) - 268 isc_buffer_usedlength(&b); 269 ns_lwdclient_log(50, "found name '%.*s'", grbn->realnamelen, 270 grbn->realname); 271 272 grbn->rdclass = cm->view->rdclass; 273 grbn->rdtype = client->rdtype; 274 275 rdataset = levent->rdataset; 276 if (rdataset != NULL) { 277 /* The normal case */ 278 grbn->nrdatas = dns_rdataset_count(rdataset); 279 grbn->rdatas = isc_mem_get(cm->mctx, grbn->nrdatas * 280 sizeof(unsigned char *)); 281 if (grbn->rdatas == NULL) 282 goto out; 283 grbn->rdatalen = isc_mem_get(cm->mctx, grbn->nrdatas * 284 sizeof(lwres_uint16_t)); 285 if (grbn->rdatalen == NULL) 286 goto out; 287 288 i = 0; 289 result = fill_array(&i, rdataset, grbn->nrdatas, grbn->rdatas, 290 grbn->rdatalen); 291 if (result != ISC_R_SUCCESS) 292 goto out; 293 INSIST(i == grbn->nrdatas); 294 grbn->ttl = rdataset->ttl; 295 if (rdataset->trust == dns_trust_secure) 296 grbn->flags |= LWRDATA_VALIDATED; 297 } else { 298 /* The SIG query case */ 299 result = iterate_node(grbn, levent->db, levent->node, 300 cm->mctx); 301 if (result != ISC_R_SUCCESS) 302 goto out; 303 } 304 ns_lwdclient_log(50, "filled in %d rdata%s", grbn->nrdatas, 305 (grbn->nrdatas == 1) ? "" : "s"); 306 307 sigrdataset = levent->sigrdataset; 308 if (sigrdataset != NULL) { 309 grbn->nsigs = dns_rdataset_count(sigrdataset); 310 grbn->sigs = isc_mem_get(cm->mctx, grbn->nsigs * 311 sizeof(unsigned char *)); 312 if (grbn->sigs == NULL) 313 goto out; 314 grbn->siglen = isc_mem_get(cm->mctx, grbn->nsigs * 315 sizeof(lwres_uint16_t)); 316 if (grbn->siglen == NULL) 317 goto out; 318 319 i = 0; 320 result = fill_array(&i, sigrdataset, grbn->nsigs, grbn->sigs, 321 grbn->siglen); 322 if (result != ISC_R_SUCCESS) 323 goto out; 324 INSIST(i == grbn->nsigs); 325 ns_lwdclient_log(50, "filled in %d signature%s", grbn->nsigs, 326 (grbn->nsigs == 1) ? "" : "s"); 327 } 328 329 /* 330 * Render the packet. 331 */ 332 client->pkt.recvlength = LWRES_RECVLENGTH; 333 client->pkt.authtype = 0; /* XXXMLG */ 334 client->pkt.authlength = 0; 335 client->pkt.result = LWRES_R_SUCCESS; 336 337 lwresult = lwres_grbnresponse_render(cm->lwctx, 338 grbn, &client->pkt, &lwb); 339 if (lwresult != LWRES_R_SUCCESS) 340 goto out; 341 342 isc_mem_put(cm->mctx, grbn->rdatas, 343 grbn->nrdatas * sizeof(unsigned char *)); 344 isc_mem_put(cm->mctx, grbn->rdatalen, 345 grbn->nrdatas * sizeof(lwres_uint16_t)); 346 347 if (grbn->sigs != NULL) 348 isc_mem_put(cm->mctx, grbn->sigs, 349 grbn->nsigs * sizeof(unsigned char *)); 350 if (grbn->siglen != NULL) 351 isc_mem_put(cm->mctx, grbn->siglen, 352 grbn->nsigs * sizeof(lwres_uint16_t)); 353 354 r.base = lwb.base; 355 r.length = lwb.used; 356 client->sendbuf = r.base; 357 client->sendlength = r.length; 358 result = ns_lwdclient_sendreply(client, &r); 359 if (result != ISC_R_SUCCESS) 360 goto out2; 361 362 NS_LWDCLIENT_SETSEND(client); 363 364 dns_lookup_destroy(&client->lookup); 365 isc_event_free(&event); 366 367 return; 368 369 out: 370 if (grbn->rdatas != NULL) 371 isc_mem_put(cm->mctx, grbn->rdatas, 372 grbn->nrdatas * sizeof(unsigned char *)); 373 if (grbn->rdatalen != NULL) 374 isc_mem_put(cm->mctx, grbn->rdatalen, 375 grbn->nrdatas * sizeof(lwres_uint16_t)); 376 377 if (grbn->sigs != NULL) 378 isc_mem_put(cm->mctx, grbn->sigs, 379 grbn->nsigs * sizeof(unsigned char *)); 380 if (grbn->siglen != NULL) 381 isc_mem_put(cm->mctx, grbn->siglen, 382 grbn->nsigs * sizeof(lwres_uint16_t)); 383 out2: 384 if (client->lookup != NULL) 385 dns_lookup_destroy(&client->lookup); 386 if (lwb.base != NULL) 387 lwres_context_freemem(cm->lwctx, lwb.base, lwb.length); 388 389 isc_event_free(&event); 390 391 ns_lwdclient_log(50, "error constructing getrrsetbyname response"); 392 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 393} 394 395static void 396start_lookup(ns_lwdclient_t *client) { 397 isc_result_t result; 398 ns_lwdclientmgr_t *cm; 399 dns_fixedname_t absname; 400 401 cm = client->clientmgr; 402 403 INSIST(client->lookup == NULL); 404 405 dns_fixedname_init(&absname); 406 result = ns_lwsearchctx_current(&client->searchctx, 407 dns_fixedname_name(&absname)); 408 /* 409 * This will return failure if relative name + suffix is too long. 410 * In this case, just go on to the next entry in the search path. 411 */ 412 if (result != ISC_R_SUCCESS) 413 start_lookup(client); 414 415 result = dns_lookup_create(cm->mctx, 416 dns_fixedname_name(&absname), 417 client->rdtype, cm->view, 418 client->options, cm->task, lookup_done, 419 client, &client->lookup); 420 if (result != ISC_R_SUCCESS) { 421 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 422 return; 423 } 424} 425 426static void 427init_grbn(ns_lwdclient_t *client) { 428 client->grbn.rdclass = 0; 429 client->grbn.rdtype = 0; 430 client->grbn.ttl = 0; 431 client->grbn.nrdatas = 0; 432 client->grbn.realname = NULL; 433 client->grbn.realnamelen = 0; 434 client->grbn.rdatas = 0; 435 client->grbn.rdatalen = 0; 436 client->grbn.base = NULL; 437 client->grbn.baselen = 0; 438 isc_buffer_init(&client->recv_buffer, client->buffer, LWRES_RECVLENGTH); 439} 440 441void 442ns_lwdclient_processgrbn(ns_lwdclient_t *client, lwres_buffer_t *b) { 443 lwres_grbnrequest_t *req; 444 isc_result_t result; 445 ns_lwdclientmgr_t *cm; 446 isc_buffer_t namebuf; 447 448 REQUIRE(NS_LWDCLIENT_ISRECVDONE(client)); 449 INSIST(client->byaddr == NULL); 450 451 cm = client->clientmgr; 452 req = NULL; 453 454 result = lwres_grbnrequest_parse(cm->lwctx, 455 b, &client->pkt, &req); 456 if (result != LWRES_R_SUCCESS) 457 goto out; 458 if (req->name == NULL) 459 goto out; 460 461 client->options = 0; 462 if (req->rdclass != cm->view->rdclass) 463 goto out; 464 465 if (req->rdclass == dns_rdataclass_any || 466 req->rdtype == dns_rdatatype_any) 467 goto out; 468 469 client->rdtype = req->rdtype; 470 471 isc_buffer_init(&namebuf, req->name, req->namelen); 472 isc_buffer_add(&namebuf, req->namelen); 473 474 dns_fixedname_init(&client->query_name); 475 result = dns_name_fromtext(dns_fixedname_name(&client->query_name), 476 &namebuf, NULL, 0, NULL); 477 if (result != ISC_R_SUCCESS) 478 goto out; 479 ns_lwsearchctx_init(&client->searchctx, 480 cm->listener->manager->search, 481 dns_fixedname_name(&client->query_name), 482 cm->listener->manager->ndots); 483 ns_lwsearchctx_first(&client->searchctx); 484 485 ns_lwdclient_log(50, "client %p looking for type %d", 486 client, client->rdtype); 487 488 /* 489 * We no longer need to keep this around. 490 */ 491 lwres_grbnrequest_free(cm->lwctx, &req); 492 493 /* 494 * Initialize the real name and alias arrays in the reply we're 495 * going to build up. 496 */ 497 init_grbn(client); 498 499 /* 500 * Start the find. 501 */ 502 start_lookup(client); 503 504 return; 505 506 /* 507 * We're screwed. Return an error packet to our caller. 508 */ 509 out: 510 if (req != NULL) 511 lwres_grbnrequest_free(cm->lwctx, &req); 512 513 ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); 514} 515