1 1.1 christos /* $NetBSD: request.c,v 1.1 2024/02/18 20:57:33 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.1 christos * SPDX-License-Identifier: MPL-2.0 7 1.1 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.1 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /*! \file */ 17 1.1 christos 18 1.1 christos #include <inttypes.h> 19 1.1 christos #include <stdbool.h> 20 1.1 christos 21 1.1 christos #include <isc/magic.h> 22 1.1 christos #include <isc/mem.h> 23 1.1 christos #include <isc/task.h> 24 1.1 christos #include <isc/timer.h> 25 1.1 christos #include <isc/util.h> 26 1.1 christos 27 1.1 christos #include <dns/acl.h> 28 1.1 christos #include <dns/compress.h> 29 1.1 christos #include <dns/dispatch.h> 30 1.1 christos #include <dns/events.h> 31 1.1 christos #include <dns/log.h> 32 1.1 christos #include <dns/message.h> 33 1.1 christos #include <dns/rdata.h> 34 1.1 christos #include <dns/rdatastruct.h> 35 1.1 christos #include <dns/request.h> 36 1.1 christos #include <dns/result.h> 37 1.1 christos #include <dns/tsig.h> 38 1.1 christos 39 1.1 christos #define REQUESTMGR_MAGIC ISC_MAGIC('R', 'q', 'u', 'M') 40 1.1 christos #define VALID_REQUESTMGR(mgr) ISC_MAGIC_VALID(mgr, REQUESTMGR_MAGIC) 41 1.1 christos 42 1.1 christos #define REQUEST_MAGIC ISC_MAGIC('R', 'q', 'u', '!') 43 1.1 christos #define VALID_REQUEST(request) ISC_MAGIC_VALID(request, REQUEST_MAGIC) 44 1.1 christos 45 1.1 christos typedef ISC_LIST(dns_request_t) dns_requestlist_t; 46 1.1 christos 47 1.1 christos #define DNS_REQUEST_NLOCKS 7 48 1.1 christos 49 1.1 christos struct dns_requestmgr { 50 1.1 christos unsigned int magic; 51 1.1 christos isc_mutex_t lock; 52 1.1 christos isc_mem_t *mctx; 53 1.1 christos 54 1.1 christos /* locked */ 55 1.1 christos int32_t eref; 56 1.1 christos int32_t iref; 57 1.1 christos isc_timermgr_t *timermgr; 58 1.1 christos isc_socketmgr_t *socketmgr; 59 1.1 christos isc_taskmgr_t *taskmgr; 60 1.1 christos dns_dispatchmgr_t *dispatchmgr; 61 1.1 christos dns_dispatch_t *dispatchv4; 62 1.1 christos dns_dispatch_t *dispatchv6; 63 1.1 christos bool exiting; 64 1.1 christos isc_eventlist_t whenshutdown; 65 1.1 christos unsigned int hash; 66 1.1 christos isc_mutex_t locks[DNS_REQUEST_NLOCKS]; 67 1.1 christos dns_requestlist_t requests; 68 1.1 christos }; 69 1.1 christos 70 1.1 christos struct dns_request { 71 1.1 christos unsigned int magic; 72 1.1 christos unsigned int hash; 73 1.1 christos isc_mem_t *mctx; 74 1.1 christos int32_t flags; 75 1.1 christos ISC_LINK(dns_request_t) link; 76 1.1 christos isc_buffer_t *query; 77 1.1 christos isc_buffer_t *answer; 78 1.1 christos dns_requestevent_t *event; 79 1.1 christos dns_dispatch_t *dispatch; 80 1.1 christos dns_dispentry_t *dispentry; 81 1.1 christos isc_timer_t *timer; 82 1.1 christos dns_requestmgr_t *requestmgr; 83 1.1 christos isc_buffer_t *tsig; 84 1.1 christos dns_tsigkey_t *tsigkey; 85 1.1 christos isc_event_t ctlevent; 86 1.1 christos bool canceling; /* ctlevent outstanding */ 87 1.1 christos isc_sockaddr_t destaddr; 88 1.1 christos unsigned int udpcount; 89 1.1 christos isc_dscp_t dscp; 90 1.1 christos }; 91 1.1 christos 92 1.1 christos #define DNS_REQUEST_F_CONNECTING 0x0001 93 1.1 christos #define DNS_REQUEST_F_SENDING 0x0002 94 1.1 christos #define DNS_REQUEST_F_CANCELED \ 95 1.1 christos 0x0004 /*%< ctlevent received, or otherwise \ 96 1.1 christos * synchronously canceled */ 97 1.1 christos #define DNS_REQUEST_F_TIMEDOUT 0x0008 /*%< canceled due to a timeout */ 98 1.1 christos #define DNS_REQUEST_F_TCP 0x0010 /*%< This request used TCP */ 99 1.1 christos #define DNS_REQUEST_CANCELED(r) (((r)->flags & DNS_REQUEST_F_CANCELED) != 0) 100 1.1 christos #define DNS_REQUEST_CONNECTING(r) (((r)->flags & DNS_REQUEST_F_CONNECTING) != 0) 101 1.1 christos #define DNS_REQUEST_SENDING(r) (((r)->flags & DNS_REQUEST_F_SENDING) != 0) 102 1.1 christos #define DNS_REQUEST_TIMEDOUT(r) (((r)->flags & DNS_REQUEST_F_TIMEDOUT) != 0) 103 1.1 christos 104 1.1 christos /*** 105 1.1 christos *** Forward 106 1.1 christos ***/ 107 1.1 christos 108 1.1 christos static void 109 1.1 christos mgr_destroy(dns_requestmgr_t *requestmgr); 110 1.1 christos static void 111 1.1 christos mgr_shutdown(dns_requestmgr_t *requestmgr); 112 1.1 christos static unsigned int 113 1.1 christos mgr_gethash(dns_requestmgr_t *requestmgr); 114 1.1 christos static void 115 1.1 christos send_shutdown_events(dns_requestmgr_t *requestmgr); 116 1.1 christos 117 1.1 christos static isc_result_t 118 1.1 christos req_render(dns_message_t *message, isc_buffer_t **buffer, unsigned int options, 119 1.1 christos isc_mem_t *mctx); 120 1.1 christos static void 121 1.1 christos req_senddone(isc_task_t *task, isc_event_t *event); 122 1.1 christos static void 123 1.1 christos req_response(isc_task_t *task, isc_event_t *event); 124 1.1 christos static void 125 1.1 christos req_timeout(isc_task_t *task, isc_event_t *event); 126 1.1 christos static isc_socket_t * 127 1.1 christos req_getsocket(dns_request_t *request); 128 1.1 christos static void 129 1.1 christos req_connected(isc_task_t *task, isc_event_t *event); 130 1.1 christos static void 131 1.1 christos req_sendevent(dns_request_t *request, isc_result_t result); 132 1.1 christos static void 133 1.1 christos req_cancel(dns_request_t *request); 134 1.1 christos static void 135 1.1 christos req_destroy(dns_request_t *request); 136 1.1 christos static void 137 1.1 christos req_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); 138 1.1 christos static void 139 1.1 christos do_cancel(isc_task_t *task, isc_event_t *event); 140 1.1 christos 141 1.1 christos /*** 142 1.1 christos *** Public 143 1.1 christos ***/ 144 1.1 christos 145 1.1 christos isc_result_t 146 1.1 christos dns_requestmgr_create(isc_mem_t *mctx, isc_timermgr_t *timermgr, 147 1.1 christos isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr, 148 1.1 christos dns_dispatchmgr_t *dispatchmgr, 149 1.1 christos dns_dispatch_t *dispatchv4, dns_dispatch_t *dispatchv6, 150 1.1 christos dns_requestmgr_t **requestmgrp) { 151 1.1 christos dns_requestmgr_t *requestmgr; 152 1.1 christos int i; 153 1.1 christos unsigned int dispattr; 154 1.1 christos 155 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create"); 156 1.1 christos 157 1.1 christos REQUIRE(requestmgrp != NULL && *requestmgrp == NULL); 158 1.1 christos REQUIRE(timermgr != NULL); 159 1.1 christos REQUIRE(socketmgr != NULL); 160 1.1 christos REQUIRE(taskmgr != NULL); 161 1.1 christos REQUIRE(dispatchmgr != NULL); 162 1.1 christos 163 1.1 christos if (dispatchv4 != NULL) { 164 1.1 christos dispattr = dns_dispatch_getattributes(dispatchv4); 165 1.1 christos REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0); 166 1.1 christos } 167 1.1 christos if (dispatchv6 != NULL) { 168 1.1 christos dispattr = dns_dispatch_getattributes(dispatchv6); 169 1.1 christos REQUIRE((dispattr & DNS_DISPATCHATTR_UDP) != 0); 170 1.1 christos } 171 1.1 christos 172 1.1 christos requestmgr = isc_mem_get(mctx, sizeof(*requestmgr)); 173 1.1 christos 174 1.1 christos isc_mutex_init(&requestmgr->lock); 175 1.1 christos 176 1.1 christos for (i = 0; i < DNS_REQUEST_NLOCKS; i++) { 177 1.1 christos isc_mutex_init(&requestmgr->locks[i]); 178 1.1 christos } 179 1.1 christos requestmgr->timermgr = timermgr; 180 1.1 christos requestmgr->socketmgr = socketmgr; 181 1.1 christos requestmgr->taskmgr = taskmgr; 182 1.1 christos requestmgr->dispatchmgr = dispatchmgr; 183 1.1 christos requestmgr->dispatchv4 = NULL; 184 1.1 christos if (dispatchv4 != NULL) { 185 1.1 christos dns_dispatch_attach(dispatchv4, &requestmgr->dispatchv4); 186 1.1 christos } 187 1.1 christos requestmgr->dispatchv6 = NULL; 188 1.1 christos if (dispatchv6 != NULL) { 189 1.1 christos dns_dispatch_attach(dispatchv6, &requestmgr->dispatchv6); 190 1.1 christos } 191 1.1 christos requestmgr->mctx = NULL; 192 1.1 christos isc_mem_attach(mctx, &requestmgr->mctx); 193 1.1 christos requestmgr->eref = 1; /* implicit attach */ 194 1.1 christos requestmgr->iref = 0; 195 1.1 christos ISC_LIST_INIT(requestmgr->whenshutdown); 196 1.1 christos ISC_LIST_INIT(requestmgr->requests); 197 1.1 christos requestmgr->exiting = false; 198 1.1 christos requestmgr->hash = 0; 199 1.1 christos requestmgr->magic = REQUESTMGR_MAGIC; 200 1.1 christos 201 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_create: %p", requestmgr); 202 1.1 christos 203 1.1 christos *requestmgrp = requestmgr; 204 1.1 christos return (ISC_R_SUCCESS); 205 1.1 christos } 206 1.1 christos 207 1.1 christos void 208 1.1 christos dns_requestmgr_whenshutdown(dns_requestmgr_t *requestmgr, isc_task_t *task, 209 1.1 christos isc_event_t **eventp) { 210 1.1 christos isc_task_t *tclone; 211 1.1 christos isc_event_t *event; 212 1.1 christos 213 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_whenshutdown"); 214 1.1 christos 215 1.1 christos REQUIRE(VALID_REQUESTMGR(requestmgr)); 216 1.1 christos REQUIRE(eventp != NULL); 217 1.1 christos 218 1.1 christos event = *eventp; 219 1.1 christos *eventp = NULL; 220 1.1 christos 221 1.1 christos LOCK(&requestmgr->lock); 222 1.1 christos 223 1.1 christos if (requestmgr->exiting) { 224 1.1 christos /* 225 1.1 christos * We're already shutdown. Send the event. 226 1.1 christos */ 227 1.1 christos event->ev_sender = requestmgr; 228 1.1 christos isc_task_send(task, &event); 229 1.1 christos } else { 230 1.1 christos tclone = NULL; 231 1.1 christos isc_task_attach(task, &tclone); 232 1.1 christos event->ev_sender = tclone; 233 1.1 christos ISC_LIST_APPEND(requestmgr->whenshutdown, event, ev_link); 234 1.1 christos } 235 1.1 christos UNLOCK(&requestmgr->lock); 236 1.1 christos } 237 1.1 christos 238 1.1 christos void 239 1.1 christos dns_requestmgr_shutdown(dns_requestmgr_t *requestmgr) { 240 1.1 christos REQUIRE(VALID_REQUESTMGR(requestmgr)); 241 1.1 christos 242 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_shutdown: %p", requestmgr); 243 1.1 christos 244 1.1 christos LOCK(&requestmgr->lock); 245 1.1 christos mgr_shutdown(requestmgr); 246 1.1 christos UNLOCK(&requestmgr->lock); 247 1.1 christos } 248 1.1 christos 249 1.1 christos static void 250 1.1 christos mgr_shutdown(dns_requestmgr_t *requestmgr) { 251 1.1 christos dns_request_t *request; 252 1.1 christos 253 1.1 christos /* 254 1.1 christos * Caller holds lock. 255 1.1 christos */ 256 1.1 christos if (!requestmgr->exiting) { 257 1.1 christos requestmgr->exiting = true; 258 1.1 christos for (request = ISC_LIST_HEAD(requestmgr->requests); 259 1.1 christos request != NULL; request = ISC_LIST_NEXT(request, link)) 260 1.1 christos { 261 1.1 christos dns_request_cancel(request); 262 1.1 christos } 263 1.1 christos if (requestmgr->iref == 0) { 264 1.1 christos INSIST(ISC_LIST_EMPTY(requestmgr->requests)); 265 1.1 christos send_shutdown_events(requestmgr); 266 1.1 christos } 267 1.1 christos } 268 1.1 christos } 269 1.1 christos 270 1.1 christos static void 271 1.1 christos requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) { 272 1.1 christos /* 273 1.1 christos * Locked by caller. 274 1.1 christos */ 275 1.1 christos 276 1.1 christos REQUIRE(VALID_REQUESTMGR(source)); 277 1.1 christos REQUIRE(targetp != NULL && *targetp == NULL); 278 1.1 christos 279 1.1 christos REQUIRE(!source->exiting); 280 1.1 christos 281 1.1 christos source->iref++; 282 1.1 christos *targetp = source; 283 1.1 christos 284 1.1 christos req_log(ISC_LOG_DEBUG(3), "requestmgr_attach: %p: eref %d iref %d", 285 1.1 christos source, source->eref, source->iref); 286 1.1 christos } 287 1.1 christos 288 1.1 christos static void 289 1.1 christos requestmgr_detach(dns_requestmgr_t **requestmgrp) { 290 1.1 christos dns_requestmgr_t *requestmgr; 291 1.1 christos bool need_destroy = false; 292 1.1 christos 293 1.1 christos REQUIRE(requestmgrp != NULL); 294 1.1 christos requestmgr = *requestmgrp; 295 1.1 christos *requestmgrp = NULL; 296 1.1 christos REQUIRE(VALID_REQUESTMGR(requestmgr)); 297 1.1 christos 298 1.1 christos LOCK(&requestmgr->lock); 299 1.1 christos INSIST(requestmgr->iref > 0); 300 1.1 christos requestmgr->iref--; 301 1.1 christos 302 1.1 christos req_log(ISC_LOG_DEBUG(3), "requestmgr_detach: %p: eref %d iref %d", 303 1.1 christos requestmgr, requestmgr->eref, requestmgr->iref); 304 1.1 christos 305 1.1 christos if (requestmgr->iref == 0 && requestmgr->exiting) { 306 1.1 christos INSIST(ISC_LIST_HEAD(requestmgr->requests) == NULL); 307 1.1 christos send_shutdown_events(requestmgr); 308 1.1 christos if (requestmgr->eref == 0) { 309 1.1 christos need_destroy = true; 310 1.1 christos } 311 1.1 christos } 312 1.1 christos UNLOCK(&requestmgr->lock); 313 1.1 christos 314 1.1 christos if (need_destroy) { 315 1.1 christos mgr_destroy(requestmgr); 316 1.1 christos } 317 1.1 christos } 318 1.1 christos 319 1.1 christos void 320 1.1 christos dns_requestmgr_attach(dns_requestmgr_t *source, dns_requestmgr_t **targetp) { 321 1.1 christos REQUIRE(VALID_REQUESTMGR(source)); 322 1.1 christos REQUIRE(targetp != NULL && *targetp == NULL); 323 1.1 christos REQUIRE(!source->exiting); 324 1.1 christos 325 1.1 christos LOCK(&source->lock); 326 1.1 christos source->eref++; 327 1.1 christos *targetp = source; 328 1.1 christos UNLOCK(&source->lock); 329 1.1 christos 330 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_attach: %p: eref %d iref %d", 331 1.1 christos source, source->eref, source->iref); 332 1.1 christos } 333 1.1 christos 334 1.1 christos void 335 1.1 christos dns_requestmgr_detach(dns_requestmgr_t **requestmgrp) { 336 1.1 christos dns_requestmgr_t *requestmgr; 337 1.1 christos bool need_destroy = false; 338 1.1 christos 339 1.1 christos REQUIRE(requestmgrp != NULL); 340 1.1 christos requestmgr = *requestmgrp; 341 1.1 christos *requestmgrp = NULL; 342 1.1 christos REQUIRE(VALID_REQUESTMGR(requestmgr)); 343 1.1 christos 344 1.1 christos LOCK(&requestmgr->lock); 345 1.1 christos INSIST(requestmgr->eref > 0); 346 1.1 christos requestmgr->eref--; 347 1.1 christos 348 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_requestmgr_detach: %p: eref %d iref %d", 349 1.1 christos requestmgr, requestmgr->eref, requestmgr->iref); 350 1.1 christos 351 1.1 christos if (requestmgr->eref == 0 && requestmgr->iref == 0) { 352 1.1 christos INSIST(requestmgr->exiting && 353 1.1 christos ISC_LIST_HEAD(requestmgr->requests) == NULL); 354 1.1 christos need_destroy = true; 355 1.1 christos } 356 1.1 christos UNLOCK(&requestmgr->lock); 357 1.1 christos 358 1.1 christos if (need_destroy) { 359 1.1 christos mgr_destroy(requestmgr); 360 1.1 christos } 361 1.1 christos } 362 1.1 christos 363 1.1 christos static void 364 1.1 christos send_shutdown_events(dns_requestmgr_t *requestmgr) { 365 1.1 christos isc_event_t *event, *next_event; 366 1.1 christos isc_task_t *etask; 367 1.1 christos 368 1.1 christos req_log(ISC_LOG_DEBUG(3), "send_shutdown_events: %p", requestmgr); 369 1.1 christos 370 1.1 christos /* 371 1.1 christos * Caller must be holding the manager lock. 372 1.1 christos */ 373 1.1 christos for (event = ISC_LIST_HEAD(requestmgr->whenshutdown); event != NULL; 374 1.1 christos event = next_event) 375 1.1 christos { 376 1.1 christos next_event = ISC_LIST_NEXT(event, ev_link); 377 1.1 christos ISC_LIST_UNLINK(requestmgr->whenshutdown, event, ev_link); 378 1.1 christos etask = event->ev_sender; 379 1.1 christos event->ev_sender = requestmgr; 380 1.1 christos isc_task_sendanddetach(&etask, &event); 381 1.1 christos } 382 1.1 christos } 383 1.1 christos 384 1.1 christos static void 385 1.1 christos mgr_destroy(dns_requestmgr_t *requestmgr) { 386 1.1 christos int i; 387 1.1 christos 388 1.1 christos req_log(ISC_LOG_DEBUG(3), "mgr_destroy"); 389 1.1 christos 390 1.1 christos REQUIRE(requestmgr->eref == 0); 391 1.1 christos REQUIRE(requestmgr->iref == 0); 392 1.1 christos 393 1.1 christos isc_mutex_destroy(&requestmgr->lock); 394 1.1 christos for (i = 0; i < DNS_REQUEST_NLOCKS; i++) { 395 1.1 christos isc_mutex_destroy(&requestmgr->locks[i]); 396 1.1 christos } 397 1.1 christos if (requestmgr->dispatchv4 != NULL) { 398 1.1 christos dns_dispatch_detach(&requestmgr->dispatchv4); 399 1.1 christos } 400 1.1 christos if (requestmgr->dispatchv6 != NULL) { 401 1.1 christos dns_dispatch_detach(&requestmgr->dispatchv6); 402 1.1 christos } 403 1.1 christos requestmgr->magic = 0; 404 1.1 christos isc_mem_putanddetach(&requestmgr->mctx, requestmgr, 405 1.1 christos sizeof(*requestmgr)); 406 1.1 christos } 407 1.1 christos 408 1.1 christos static unsigned int 409 1.1 christos mgr_gethash(dns_requestmgr_t *requestmgr) { 410 1.1 christos req_log(ISC_LOG_DEBUG(3), "mgr_gethash"); 411 1.1 christos /* 412 1.1 christos * Locked by caller. 413 1.1 christos */ 414 1.1 christos requestmgr->hash++; 415 1.1 christos return (requestmgr->hash % DNS_REQUEST_NLOCKS); 416 1.1 christos } 417 1.1 christos 418 1.1 christos static isc_result_t 419 1.1 christos req_send(dns_request_t *request, isc_task_t *task, 420 1.1 christos const isc_sockaddr_t *address) { 421 1.1 christos isc_region_t r; 422 1.1 christos isc_socket_t *sock; 423 1.1 christos isc_socketevent_t *sendevent; 424 1.1 christos isc_result_t result; 425 1.1 christos 426 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_send: request %p", request); 427 1.1 christos 428 1.1 christos REQUIRE(VALID_REQUEST(request)); 429 1.1 christos sock = req_getsocket(request); 430 1.1 christos isc_buffer_usedregion(request->query, &r); 431 1.1 christos /* 432 1.1 christos * We could connect the socket when we are using an exclusive dispatch 433 1.1 christos * as we do in resolver.c, but we prefer implementation simplicity 434 1.1 christos * at this moment. 435 1.1 christos */ 436 1.1 christos sendevent = isc_socket_socketevent(request->mctx, sock, 437 1.1 christos ISC_SOCKEVENT_SENDDONE, req_senddone, 438 1.1 christos request); 439 1.1 christos if (sendevent == NULL) { 440 1.1 christos return (ISC_R_NOMEMORY); 441 1.1 christos } 442 1.1 christos if (request->dscp == -1) { 443 1.1 christos sendevent->attributes &= ~ISC_SOCKEVENTATTR_DSCP; 444 1.1 christos sendevent->dscp = 0; 445 1.1 christos } else { 446 1.1 christos sendevent->attributes |= ISC_SOCKEVENTATTR_DSCP; 447 1.1 christos sendevent->dscp = request->dscp; 448 1.1 christos } 449 1.1 christos 450 1.1 christos request->flags |= DNS_REQUEST_F_SENDING; 451 1.1 christos result = isc_socket_sendto2(sock, &r, task, address, NULL, sendevent, 452 1.1 christos 0); 453 1.1 christos INSIST(result == ISC_R_SUCCESS); 454 1.1 christos return (result); 455 1.1 christos } 456 1.1 christos 457 1.1 christos static isc_result_t 458 1.1 christos new_request(isc_mem_t *mctx, dns_request_t **requestp) { 459 1.1 christos dns_request_t *request; 460 1.1 christos 461 1.1 christos request = isc_mem_get(mctx, sizeof(*request)); 462 1.1 christos 463 1.1 christos /* 464 1.1 christos * Zero structure. 465 1.1 christos */ 466 1.1 christos request->magic = 0; 467 1.1 christos request->mctx = NULL; 468 1.1 christos request->flags = 0; 469 1.1 christos ISC_LINK_INIT(request, link); 470 1.1 christos request->query = NULL; 471 1.1 christos request->answer = NULL; 472 1.1 christos request->event = NULL; 473 1.1 christos request->dispatch = NULL; 474 1.1 christos request->dispentry = NULL; 475 1.1 christos request->timer = NULL; 476 1.1 christos request->requestmgr = NULL; 477 1.1 christos request->tsig = NULL; 478 1.1 christos request->tsigkey = NULL; 479 1.1 christos request->dscp = -1; 480 1.1 christos ISC_EVENT_INIT(&request->ctlevent, sizeof(request->ctlevent), 0, NULL, 481 1.1 christos DNS_EVENT_REQUESTCONTROL, do_cancel, request, NULL, NULL, 482 1.1 christos NULL); 483 1.1 christos request->canceling = false; 484 1.1 christos request->udpcount = 0; 485 1.1 christos 486 1.1 christos isc_mem_attach(mctx, &request->mctx); 487 1.1 christos 488 1.1 christos request->magic = REQUEST_MAGIC; 489 1.1 christos *requestp = request; 490 1.1 christos return (ISC_R_SUCCESS); 491 1.1 christos } 492 1.1 christos 493 1.1 christos static bool 494 1.1 christos isblackholed(dns_dispatchmgr_t *dispatchmgr, const isc_sockaddr_t *destaddr) { 495 1.1 christos dns_acl_t *blackhole; 496 1.1 christos isc_netaddr_t netaddr; 497 1.1 christos int match; 498 1.1 christos bool drop = false; 499 1.1 christos char netaddrstr[ISC_NETADDR_FORMATSIZE]; 500 1.1 christos 501 1.1 christos blackhole = dns_dispatchmgr_getblackhole(dispatchmgr); 502 1.1 christos if (blackhole != NULL) { 503 1.1 christos isc_netaddr_fromsockaddr(&netaddr, destaddr); 504 1.1 christos if (dns_acl_match(&netaddr, NULL, blackhole, NULL, &match, 505 1.1 christos NULL) == ISC_R_SUCCESS && 506 1.1 christos match > 0) 507 1.1 christos { 508 1.1 christos drop = true; 509 1.1 christos } 510 1.1 christos } 511 1.1 christos if (drop) { 512 1.1 christos isc_netaddr_format(&netaddr, netaddrstr, sizeof(netaddrstr)); 513 1.1 christos req_log(ISC_LOG_DEBUG(10), "blackholed address %s", netaddrstr); 514 1.1 christos } 515 1.1 christos return (drop); 516 1.1 christos } 517 1.1 christos 518 1.1 christos static isc_result_t 519 1.1 christos create_tcp_dispatch(bool newtcp, bool share, dns_requestmgr_t *requestmgr, 520 1.1 christos const isc_sockaddr_t *srcaddr, 521 1.1 christos const isc_sockaddr_t *destaddr, isc_dscp_t dscp, 522 1.1 christos bool *connected, dns_dispatch_t **dispatchp) { 523 1.1 christos isc_result_t result; 524 1.1 christos isc_socket_t *sock = NULL; 525 1.1 christos isc_sockaddr_t src; 526 1.1 christos unsigned int attrs; 527 1.1 christos isc_sockaddr_t bind_any; 528 1.1 christos 529 1.1 christos if (!newtcp && share) { 530 1.1 christos result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr, 531 1.1 christos srcaddr, connected, dispatchp); 532 1.1 christos if (result == ISC_R_SUCCESS) { 533 1.1 christos char peer[ISC_SOCKADDR_FORMATSIZE]; 534 1.1 christos 535 1.1 christos isc_sockaddr_format(destaddr, peer, sizeof(peer)); 536 1.1 christos req_log(ISC_LOG_DEBUG(1), 537 1.1 christos "attached to %s TCP " 538 1.1 christos "connection to %s", 539 1.1 christos *connected ? "existing" : "pending", peer); 540 1.1 christos return (result); 541 1.1 christos } 542 1.1 christos } else if (!newtcp) { 543 1.1 christos result = dns_dispatch_gettcp(requestmgr->dispatchmgr, destaddr, 544 1.1 christos srcaddr, NULL, dispatchp); 545 1.1 christos if (result == ISC_R_SUCCESS) { 546 1.1 christos char peer[ISC_SOCKADDR_FORMATSIZE]; 547 1.1 christos 548 1.1 christos *connected = true; 549 1.1 christos isc_sockaddr_format(destaddr, peer, sizeof(peer)); 550 1.1 christos req_log(ISC_LOG_DEBUG(1), 551 1.1 christos "attached to existing TCP " 552 1.1 christos "connection to %s", 553 1.1 christos peer); 554 1.1 christos return (result); 555 1.1 christos } 556 1.1 christos } 557 1.1 christos 558 1.1 christos result = isc_socket_create(requestmgr->socketmgr, 559 1.1 christos isc_sockaddr_pf(destaddr), 560 1.1 christos isc_sockettype_tcp, &sock); 561 1.1 christos if (result != ISC_R_SUCCESS) { 562 1.1 christos return (result); 563 1.1 christos } 564 1.1 christos #ifndef BROKEN_TCP_BIND_BEFORE_CONNECT 565 1.1 christos if (srcaddr == NULL) { 566 1.1 christos isc_sockaddr_anyofpf(&bind_any, isc_sockaddr_pf(destaddr)); 567 1.1 christos result = isc_socket_bind(sock, &bind_any, 0); 568 1.1 christos } else { 569 1.1 christos src = *srcaddr; 570 1.1 christos isc_sockaddr_setport(&src, 0); 571 1.1 christos result = isc_socket_bind(sock, &src, 0); 572 1.1 christos } 573 1.1 christos if (result != ISC_R_SUCCESS) { 574 1.1 christos goto cleanup; 575 1.1 christos } 576 1.1 christos #endif /* ifndef BROKEN_TCP_BIND_BEFORE_CONNECT */ 577 1.1 christos 578 1.1 christos attrs = 0; 579 1.1 christos attrs |= DNS_DISPATCHATTR_TCP; 580 1.1 christos if (isc_sockaddr_pf(destaddr) == AF_INET) { 581 1.1 christos attrs |= DNS_DISPATCHATTR_IPV4; 582 1.1 christos } else { 583 1.1 christos attrs |= DNS_DISPATCHATTR_IPV6; 584 1.1 christos } 585 1.1 christos attrs |= DNS_DISPATCHATTR_MAKEQUERY; 586 1.1 christos 587 1.1 christos isc_socket_dscp(sock, dscp); 588 1.1 christos result = dns_dispatch_createtcp( 589 1.1 christos requestmgr->dispatchmgr, sock, requestmgr->taskmgr, srcaddr, 590 1.1 christos destaddr, 4096, 32768, 32768, 16411, 16433, attrs, dispatchp); 591 1.1 christos cleanup: 592 1.1 christos isc_socket_detach(&sock); 593 1.1 christos return (result); 594 1.1 christos } 595 1.1 christos 596 1.1 christos static isc_result_t 597 1.1 christos find_udp_dispatch(dns_requestmgr_t *requestmgr, const isc_sockaddr_t *srcaddr, 598 1.1 christos const isc_sockaddr_t *destaddr, dns_dispatch_t **dispatchp) { 599 1.1 christos dns_dispatch_t *disp = NULL; 600 1.1 christos unsigned int attrs, attrmask; 601 1.1 christos 602 1.1 christos if (srcaddr == NULL) { 603 1.1 christos switch (isc_sockaddr_pf(destaddr)) { 604 1.1 christos case PF_INET: 605 1.1 christos disp = requestmgr->dispatchv4; 606 1.1 christos break; 607 1.1 christos 608 1.1 christos case PF_INET6: 609 1.1 christos disp = requestmgr->dispatchv6; 610 1.1 christos break; 611 1.1 christos 612 1.1 christos default: 613 1.1 christos return (ISC_R_NOTIMPLEMENTED); 614 1.1 christos } 615 1.1 christos if (disp == NULL) { 616 1.1 christos return (ISC_R_FAMILYNOSUPPORT); 617 1.1 christos } 618 1.1 christos dns_dispatch_attach(disp, dispatchp); 619 1.1 christos return (ISC_R_SUCCESS); 620 1.1 christos } 621 1.1 christos attrs = 0; 622 1.1 christos attrs |= DNS_DISPATCHATTR_UDP; 623 1.1 christos switch (isc_sockaddr_pf(srcaddr)) { 624 1.1 christos case PF_INET: 625 1.1 christos attrs |= DNS_DISPATCHATTR_IPV4; 626 1.1 christos break; 627 1.1 christos 628 1.1 christos case PF_INET6: 629 1.1 christos attrs |= DNS_DISPATCHATTR_IPV6; 630 1.1 christos break; 631 1.1 christos 632 1.1 christos default: 633 1.1 christos return (ISC_R_NOTIMPLEMENTED); 634 1.1 christos } 635 1.1 christos attrmask = 0; 636 1.1 christos attrmask |= DNS_DISPATCHATTR_UDP; 637 1.1 christos attrmask |= DNS_DISPATCHATTR_TCP; 638 1.1 christos attrmask |= DNS_DISPATCHATTR_IPV4; 639 1.1 christos attrmask |= DNS_DISPATCHATTR_IPV6; 640 1.1 christos return (dns_dispatch_getudp(requestmgr->dispatchmgr, 641 1.1 christos requestmgr->socketmgr, requestmgr->taskmgr, 642 1.1 christos srcaddr, 4096, 32768, 32768, 16411, 16433, 643 1.1 christos attrs, attrmask, dispatchp)); 644 1.1 christos } 645 1.1 christos 646 1.1 christos static isc_result_t 647 1.1 christos get_dispatch(bool tcp, bool newtcp, bool share, dns_requestmgr_t *requestmgr, 648 1.1 christos const isc_sockaddr_t *srcaddr, const isc_sockaddr_t *destaddr, 649 1.1 christos isc_dscp_t dscp, bool *connected, dns_dispatch_t **dispatchp) { 650 1.1 christos isc_result_t result; 651 1.1 christos 652 1.1 christos if (tcp) { 653 1.1 christos result = create_tcp_dispatch(newtcp, share, requestmgr, srcaddr, 654 1.1 christos destaddr, dscp, connected, 655 1.1 christos dispatchp); 656 1.1 christos } else { 657 1.1 christos result = find_udp_dispatch(requestmgr, srcaddr, destaddr, 658 1.1 christos dispatchp); 659 1.1 christos } 660 1.1 christos return (result); 661 1.1 christos } 662 1.1 christos 663 1.1 christos static isc_result_t 664 1.1 christos set_timer(isc_timer_t *timer, unsigned int timeout, unsigned int udpresend) { 665 1.1 christos isc_time_t expires; 666 1.1 christos isc_interval_t interval; 667 1.1 christos isc_result_t result; 668 1.1 christos isc_timertype_t timertype; 669 1.1 christos 670 1.1 christos isc_interval_set(&interval, timeout, 0); 671 1.1 christos result = isc_time_nowplusinterval(&expires, &interval); 672 1.1 christos isc_interval_set(&interval, udpresend, 0); 673 1.1 christos 674 1.1 christos timertype = udpresend != 0 ? isc_timertype_limited : isc_timertype_once; 675 1.1 christos if (result == ISC_R_SUCCESS) { 676 1.1 christos result = isc_timer_reset(timer, timertype, &expires, &interval, 677 1.1 christos false); 678 1.1 christos } 679 1.1 christos return (result); 680 1.1 christos } 681 1.1 christos 682 1.1 christos isc_result_t 683 1.1 christos dns_request_createraw(dns_requestmgr_t *requestmgr, isc_buffer_t *msgbuf, 684 1.1 christos const isc_sockaddr_t *srcaddr, 685 1.1 christos const isc_sockaddr_t *destaddr, isc_dscp_t dscp, 686 1.1 christos unsigned int options, unsigned int timeout, 687 1.1 christos unsigned int udptimeout, unsigned int udpretries, 688 1.1 christos isc_task_t *task, isc_taskaction_t action, void *arg, 689 1.1 christos dns_request_t **requestp) { 690 1.1 christos dns_request_t *request = NULL; 691 1.1 christos isc_task_t *tclone = NULL; 692 1.1 christos isc_socket_t *sock = NULL; 693 1.1 christos isc_result_t result; 694 1.1 christos isc_mem_t *mctx; 695 1.1 christos dns_messageid_t id; 696 1.1 christos bool tcp = false; 697 1.1 christos bool newtcp = false; 698 1.1 christos bool share = false; 699 1.1 christos isc_region_t r; 700 1.1 christos bool connected = false; 701 1.1 christos unsigned int dispopt = 0; 702 1.1 christos 703 1.1 christos REQUIRE(VALID_REQUESTMGR(requestmgr)); 704 1.1 christos REQUIRE(msgbuf != NULL); 705 1.1 christos REQUIRE(destaddr != NULL); 706 1.1 christos REQUIRE(task != NULL); 707 1.1 christos REQUIRE(action != NULL); 708 1.1 christos REQUIRE(requestp != NULL && *requestp == NULL); 709 1.1 christos REQUIRE(timeout > 0); 710 1.1 christos if (srcaddr != NULL) { 711 1.1 christos REQUIRE(isc_sockaddr_pf(srcaddr) == isc_sockaddr_pf(destaddr)); 712 1.1 christos } 713 1.1 christos 714 1.1 christos mctx = requestmgr->mctx; 715 1.1 christos 716 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_createraw"); 717 1.1 christos 718 1.1 christos if (isblackholed(requestmgr->dispatchmgr, destaddr)) { 719 1.1 christos return (DNS_R_BLACKHOLED); 720 1.1 christos } 721 1.1 christos 722 1.1 christos request = NULL; 723 1.1 christos result = new_request(mctx, &request); 724 1.1 christos if (result != ISC_R_SUCCESS) { 725 1.1 christos return (result); 726 1.1 christos } 727 1.1 christos 728 1.1 christos if (udptimeout == 0 && udpretries != 0) { 729 1.1 christos udptimeout = timeout / (udpretries + 1); 730 1.1 christos if (udptimeout == 0) { 731 1.1 christos udptimeout = 1; 732 1.1 christos } 733 1.1 christos } 734 1.1 christos request->udpcount = udpretries; 735 1.1 christos request->dscp = dscp; 736 1.1 christos 737 1.1 christos /* 738 1.1 christos * Create timer now. We will set it below once. 739 1.1 christos */ 740 1.1 christos result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, 741 1.1 christos NULL, NULL, task, req_timeout, request, 742 1.1 christos &request->timer); 743 1.1 christos if (result != ISC_R_SUCCESS) { 744 1.1 christos goto cleanup; 745 1.1 christos } 746 1.1 christos 747 1.1 christos request->event = (dns_requestevent_t *)isc_event_allocate( 748 1.1 christos mctx, task, DNS_EVENT_REQUESTDONE, action, arg, 749 1.1 christos sizeof(dns_requestevent_t)); 750 1.1 christos isc_task_attach(task, &tclone); 751 1.1 christos request->event->ev_sender = task; 752 1.1 christos request->event->request = request; 753 1.1 christos request->event->result = ISC_R_FAILURE; 754 1.1 christos 755 1.1 christos isc_buffer_usedregion(msgbuf, &r); 756 1.1 christos if (r.length < DNS_MESSAGE_HEADERLEN || r.length > 65535) { 757 1.1 christos result = DNS_R_FORMERR; 758 1.1 christos goto cleanup; 759 1.1 christos } 760 1.1 christos 761 1.1 christos if ((options & DNS_REQUESTOPT_TCP) != 0 || r.length > 512) { 762 1.1 christos tcp = true; 763 1.1 christos } 764 1.1 christos share = (options & DNS_REQUESTOPT_SHARE); 765 1.1 christos 766 1.1 christos again: 767 1.1 christos result = get_dispatch(tcp, newtcp, share, requestmgr, srcaddr, destaddr, 768 1.1 christos dscp, &connected, &request->dispatch); 769 1.1 christos if (result != ISC_R_SUCCESS) { 770 1.1 christos goto cleanup; 771 1.1 christos } 772 1.1 christos 773 1.1 christos if ((options & DNS_REQUESTOPT_FIXEDID) != 0) { 774 1.1 christos id = (r.base[0] << 8) | r.base[1]; 775 1.1 christos dispopt |= DNS_DISPATCHOPT_FIXEDID; 776 1.1 christos } 777 1.1 christos 778 1.1 christos result = dns_dispatch_addresponse( 779 1.1 christos request->dispatch, dispopt, destaddr, task, req_response, 780 1.1 christos request, &id, &request->dispentry, requestmgr->socketmgr); 781 1.1 christos if (result != ISC_R_SUCCESS) { 782 1.1 christos if ((options & DNS_REQUESTOPT_FIXEDID) != 0 && !newtcp) { 783 1.1 christos newtcp = true; 784 1.1 christos connected = false; 785 1.1 christos dns_dispatch_detach(&request->dispatch); 786 1.1 christos goto again; 787 1.1 christos } 788 1.1 christos goto cleanup; 789 1.1 christos } 790 1.1 christos 791 1.1 christos sock = req_getsocket(request); 792 1.1 christos INSIST(sock != NULL); 793 1.1 christos 794 1.1 christos isc_buffer_allocate(mctx, &request->query, r.length + (tcp ? 2 : 0)); 795 1.1 christos if (tcp) { 796 1.1 christos isc_buffer_putuint16(request->query, (uint16_t)r.length); 797 1.1 christos } 798 1.1 christos result = isc_buffer_copyregion(request->query, &r); 799 1.1 christos if (result != ISC_R_SUCCESS) { 800 1.1 christos goto cleanup; 801 1.1 christos } 802 1.1 christos 803 1.1 christos /* Add message ID. */ 804 1.1 christos isc_buffer_usedregion(request->query, &r); 805 1.1 christos if (tcp) { 806 1.1 christos isc_region_consume(&r, 2); 807 1.1 christos } 808 1.1 christos r.base[0] = (id >> 8) & 0xff; 809 1.1 christos r.base[1] = id & 0xff; 810 1.1 christos 811 1.1 christos LOCK(&requestmgr->lock); 812 1.1 christos if (requestmgr->exiting) { 813 1.1 christos UNLOCK(&requestmgr->lock); 814 1.1 christos result = ISC_R_SHUTTINGDOWN; 815 1.1 christos goto cleanup; 816 1.1 christos } 817 1.1 christos requestmgr_attach(requestmgr, &request->requestmgr); 818 1.1 christos request->hash = mgr_gethash(requestmgr); 819 1.1 christos ISC_LIST_APPEND(requestmgr->requests, request, link); 820 1.1 christos UNLOCK(&requestmgr->lock); 821 1.1 christos 822 1.1 christos result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); 823 1.1 christos if (result != ISC_R_SUCCESS) { 824 1.1 christos goto unlink; 825 1.1 christos } 826 1.1 christos 827 1.1 christos request->destaddr = *destaddr; 828 1.1 christos if (tcp && !connected) { 829 1.1 christos result = isc_socket_connect(sock, destaddr, task, req_connected, 830 1.1 christos request); 831 1.1 christos if (result != ISC_R_SUCCESS) { 832 1.1 christos goto unlink; 833 1.1 christos } 834 1.1 christos request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; 835 1.1 christos } else { 836 1.1 christos result = req_send(request, task, connected ? NULL : destaddr); 837 1.1 christos if (result != ISC_R_SUCCESS) { 838 1.1 christos goto unlink; 839 1.1 christos } 840 1.1 christos } 841 1.1 christos 842 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: request %p", request); 843 1.1 christos *requestp = request; 844 1.1 christos return (ISC_R_SUCCESS); 845 1.1 christos 846 1.1 christos unlink: 847 1.1 christos LOCK(&requestmgr->lock); 848 1.1 christos ISC_LIST_UNLINK(requestmgr->requests, request, link); 849 1.1 christos UNLOCK(&requestmgr->lock); 850 1.1 christos 851 1.1 christos cleanup: 852 1.1 christos if (tclone != NULL) { 853 1.1 christos isc_task_detach(&tclone); 854 1.1 christos } 855 1.1 christos req_destroy(request); 856 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_createraw: failed %s", 857 1.1 christos dns_result_totext(result)); 858 1.1 christos return (result); 859 1.1 christos } 860 1.1 christos 861 1.1 christos isc_result_t 862 1.1 christos dns_request_create(dns_requestmgr_t *requestmgr, dns_message_t *message, 863 1.1 christos const isc_sockaddr_t *address, unsigned int options, 864 1.1 christos dns_tsigkey_t *key, unsigned int timeout, isc_task_t *task, 865 1.1 christos isc_taskaction_t action, void *arg, 866 1.1 christos dns_request_t **requestp) { 867 1.1 christos return (dns_request_createvia(requestmgr, message, NULL, address, -1, 868 1.1 christos options, key, timeout, 0, 0, task, action, 869 1.1 christos arg, requestp)); 870 1.1 christos } 871 1.1 christos 872 1.1 christos isc_result_t 873 1.1 christos dns_request_createvia(dns_requestmgr_t *requestmgr, dns_message_t *message, 874 1.1 christos const isc_sockaddr_t *srcaddr, 875 1.1 christos const isc_sockaddr_t *destaddr, isc_dscp_t dscp, 876 1.1 christos unsigned int options, dns_tsigkey_t *key, 877 1.1 christos unsigned int timeout, unsigned int udptimeout, 878 1.1 christos unsigned int udpretries, isc_task_t *task, 879 1.1 christos isc_taskaction_t action, void *arg, 880 1.1 christos dns_request_t **requestp) { 881 1.1 christos dns_request_t *request = NULL; 882 1.1 christos isc_task_t *tclone = NULL; 883 1.1 christos isc_socket_t *sock = NULL; 884 1.1 christos isc_result_t result; 885 1.1 christos isc_mem_t *mctx; 886 1.1 christos dns_messageid_t id; 887 1.1 christos bool tcp; 888 1.1 christos bool share; 889 1.1 christos bool settsigkey = true; 890 1.1 christos bool connected = false; 891 1.1 christos 892 1.1 christos REQUIRE(VALID_REQUESTMGR(requestmgr)); 893 1.1 christos REQUIRE(message != NULL); 894 1.1 christos REQUIRE(destaddr != NULL); 895 1.1 christos REQUIRE(task != NULL); 896 1.1 christos REQUIRE(action != NULL); 897 1.1 christos REQUIRE(requestp != NULL && *requestp == NULL); 898 1.1 christos REQUIRE(timeout > 0); 899 1.1 christos 900 1.1 christos mctx = requestmgr->mctx; 901 1.1 christos 902 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_createvia"); 903 1.1 christos 904 1.1 christos if (srcaddr != NULL && 905 1.1 christos isc_sockaddr_pf(srcaddr) != isc_sockaddr_pf(destaddr)) 906 1.1 christos { 907 1.1 christos return (ISC_R_FAMILYMISMATCH); 908 1.1 christos } 909 1.1 christos 910 1.1 christos if (isblackholed(requestmgr->dispatchmgr, destaddr)) { 911 1.1 christos return (DNS_R_BLACKHOLED); 912 1.1 christos } 913 1.1 christos 914 1.1 christos request = NULL; 915 1.1 christos result = new_request(mctx, &request); 916 1.1 christos if (result != ISC_R_SUCCESS) { 917 1.1 christos return (result); 918 1.1 christos } 919 1.1 christos 920 1.1 christos if (udptimeout == 0 && udpretries != 0) { 921 1.1 christos udptimeout = timeout / (udpretries + 1); 922 1.1 christos if (udptimeout == 0) { 923 1.1 christos udptimeout = 1; 924 1.1 christos } 925 1.1 christos } 926 1.1 christos request->udpcount = udpretries; 927 1.1 christos request->dscp = dscp; 928 1.1 christos 929 1.1 christos /* 930 1.1 christos * Create timer now. We will set it below once. 931 1.1 christos */ 932 1.1 christos result = isc_timer_create(requestmgr->timermgr, isc_timertype_inactive, 933 1.1 christos NULL, NULL, task, req_timeout, request, 934 1.1 christos &request->timer); 935 1.1 christos if (result != ISC_R_SUCCESS) { 936 1.1 christos goto cleanup; 937 1.1 christos } 938 1.1 christos 939 1.1 christos request->event = (dns_requestevent_t *)isc_event_allocate( 940 1.1 christos mctx, task, DNS_EVENT_REQUESTDONE, action, arg, 941 1.1 christos sizeof(dns_requestevent_t)); 942 1.1 christos isc_task_attach(task, &tclone); 943 1.1 christos request->event->ev_sender = task; 944 1.1 christos request->event->request = request; 945 1.1 christos request->event->result = ISC_R_FAILURE; 946 1.1 christos if (key != NULL) { 947 1.1 christos dns_tsigkey_attach(key, &request->tsigkey); 948 1.1 christos } 949 1.1 christos 950 1.1 christos use_tcp: 951 1.1 christos tcp = ((options & DNS_REQUESTOPT_TCP) != 0); 952 1.1 christos share = ((options & DNS_REQUESTOPT_SHARE) != 0); 953 1.1 christos result = get_dispatch(tcp, false, share, requestmgr, srcaddr, destaddr, 954 1.1 christos dscp, &connected, &request->dispatch); 955 1.1 christos if (result != ISC_R_SUCCESS) { 956 1.1 christos goto cleanup; 957 1.1 christos } 958 1.1 christos 959 1.1 christos result = dns_dispatch_addresponse( 960 1.1 christos request->dispatch, 0, destaddr, task, req_response, request, 961 1.1 christos &id, &request->dispentry, requestmgr->socketmgr); 962 1.1 christos if (result != ISC_R_SUCCESS) { 963 1.1 christos goto cleanup; 964 1.1 christos } 965 1.1 christos sock = req_getsocket(request); 966 1.1 christos INSIST(sock != NULL); 967 1.1 christos 968 1.1 christos message->id = id; 969 1.1 christos if (settsigkey) { 970 1.1 christos result = dns_message_settsigkey(message, request->tsigkey); 971 1.1 christos if (result != ISC_R_SUCCESS) { 972 1.1 christos goto cleanup; 973 1.1 christos } 974 1.1 christos } 975 1.1 christos result = req_render(message, &request->query, options, mctx); 976 1.1 christos if (result == DNS_R_USETCP && (options & DNS_REQUESTOPT_TCP) == 0) { 977 1.1 christos /* 978 1.1 christos * Try again using TCP. 979 1.1 christos */ 980 1.1 christos dns_message_renderreset(message); 981 1.1 christos dns_dispatch_removeresponse(&request->dispentry, NULL); 982 1.1 christos dns_dispatch_detach(&request->dispatch); 983 1.1 christos sock = NULL; 984 1.1 christos options |= DNS_REQUESTOPT_TCP; 985 1.1 christos settsigkey = false; 986 1.1 christos goto use_tcp; 987 1.1 christos } 988 1.1 christos if (result != ISC_R_SUCCESS) { 989 1.1 christos goto cleanup; 990 1.1 christos } 991 1.1 christos 992 1.1 christos result = dns_message_getquerytsig(message, mctx, &request->tsig); 993 1.1 christos if (result != ISC_R_SUCCESS) { 994 1.1 christos goto cleanup; 995 1.1 christos } 996 1.1 christos 997 1.1 christos LOCK(&requestmgr->lock); 998 1.1 christos if (requestmgr->exiting) { 999 1.1 christos UNLOCK(&requestmgr->lock); 1000 1.1 christos result = ISC_R_SHUTTINGDOWN; 1001 1.1 christos goto cleanup; 1002 1.1 christos } 1003 1.1 christos requestmgr_attach(requestmgr, &request->requestmgr); 1004 1.1 christos request->hash = mgr_gethash(requestmgr); 1005 1.1 christos ISC_LIST_APPEND(requestmgr->requests, request, link); 1006 1.1 christos UNLOCK(&requestmgr->lock); 1007 1.1 christos 1008 1.1 christos result = set_timer(request->timer, timeout, tcp ? 0 : udptimeout); 1009 1.1 christos if (result != ISC_R_SUCCESS) { 1010 1.1 christos goto unlink; 1011 1.1 christos } 1012 1.1 christos 1013 1.1 christos request->destaddr = *destaddr; 1014 1.1 christos if (tcp && !connected) { 1015 1.1 christos result = isc_socket_connect(sock, destaddr, task, req_connected, 1016 1.1 christos request); 1017 1.1 christos if (result != ISC_R_SUCCESS) { 1018 1.1 christos goto unlink; 1019 1.1 christos } 1020 1.1 christos request->flags |= DNS_REQUEST_F_CONNECTING | DNS_REQUEST_F_TCP; 1021 1.1 christos } else { 1022 1.1 christos result = req_send(request, task, connected ? NULL : destaddr); 1023 1.1 christos if (result != ISC_R_SUCCESS) { 1024 1.1 christos goto unlink; 1025 1.1 christos } 1026 1.1 christos } 1027 1.1 christos 1028 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: request %p", request); 1029 1.1 christos *requestp = request; 1030 1.1 christos return (ISC_R_SUCCESS); 1031 1.1 christos 1032 1.1 christos unlink: 1033 1.1 christos LOCK(&requestmgr->lock); 1034 1.1 christos ISC_LIST_UNLINK(requestmgr->requests, request, link); 1035 1.1 christos UNLOCK(&requestmgr->lock); 1036 1.1 christos 1037 1.1 christos cleanup: 1038 1.1 christos if (tclone != NULL) { 1039 1.1 christos isc_task_detach(&tclone); 1040 1.1 christos } 1041 1.1 christos req_destroy(request); 1042 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_createvia: failed %s", 1043 1.1 christos dns_result_totext(result)); 1044 1.1 christos return (result); 1045 1.1 christos } 1046 1.1 christos 1047 1.1 christos static isc_result_t 1048 1.1 christos req_render(dns_message_t *message, isc_buffer_t **bufferp, unsigned int options, 1049 1.1 christos isc_mem_t *mctx) { 1050 1.1 christos isc_buffer_t *buf1 = NULL; 1051 1.1 christos isc_buffer_t *buf2 = NULL; 1052 1.1 christos isc_result_t result; 1053 1.1 christos isc_region_t r; 1054 1.1 christos bool tcp = false; 1055 1.1 christos dns_compress_t cctx; 1056 1.1 christos bool cleanup_cctx = false; 1057 1.1 christos 1058 1.1 christos REQUIRE(bufferp != NULL && *bufferp == NULL); 1059 1.1 christos 1060 1.1 christos req_log(ISC_LOG_DEBUG(3), "request_render"); 1061 1.1 christos 1062 1.1 christos /* 1063 1.1 christos * Create buffer able to hold largest possible message. 1064 1.1 christos */ 1065 1.1 christos isc_buffer_allocate(mctx, &buf1, 65535); 1066 1.1 christos 1067 1.1 christos result = dns_compress_init(&cctx, -1, mctx); 1068 1.1 christos if (result != ISC_R_SUCCESS) { 1069 1.1 christos return (result); 1070 1.1 christos } 1071 1.1 christos cleanup_cctx = true; 1072 1.1 christos 1073 1.1 christos if ((options & DNS_REQUESTOPT_CASE) != 0) { 1074 1.1 christos dns_compress_setsensitive(&cctx, true); 1075 1.1 christos } 1076 1.1 christos 1077 1.1 christos /* 1078 1.1 christos * Render message. 1079 1.1 christos */ 1080 1.1 christos result = dns_message_renderbegin(message, &cctx, buf1); 1081 1.1 christos if (result != ISC_R_SUCCESS) { 1082 1.1 christos goto cleanup; 1083 1.1 christos } 1084 1.1 christos result = dns_message_rendersection(message, DNS_SECTION_QUESTION, 0); 1085 1.1 christos if (result != ISC_R_SUCCESS) { 1086 1.1 christos goto cleanup; 1087 1.1 christos } 1088 1.1 christos result = dns_message_rendersection(message, DNS_SECTION_ANSWER, 0); 1089 1.1 christos if (result != ISC_R_SUCCESS) { 1090 1.1 christos goto cleanup; 1091 1.1 christos } 1092 1.1 christos result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY, 0); 1093 1.1 christos if (result != ISC_R_SUCCESS) { 1094 1.1 christos goto cleanup; 1095 1.1 christos } 1096 1.1 christos result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL, 0); 1097 1.1 christos if (result != ISC_R_SUCCESS) { 1098 1.1 christos goto cleanup; 1099 1.1 christos } 1100 1.1 christos result = dns_message_renderend(message); 1101 1.1 christos if (result != ISC_R_SUCCESS) { 1102 1.1 christos goto cleanup; 1103 1.1 christos } 1104 1.1 christos 1105 1.1 christos dns_compress_invalidate(&cctx); 1106 1.1 christos cleanup_cctx = false; 1107 1.1 christos 1108 1.1 christos /* 1109 1.1 christos * Copy rendered message to exact sized buffer. 1110 1.1 christos */ 1111 1.1 christos isc_buffer_usedregion(buf1, &r); 1112 1.1 christos if ((options & DNS_REQUESTOPT_TCP) != 0) { 1113 1.1 christos tcp = true; 1114 1.1 christos } else if (r.length > 512) { 1115 1.1 christos result = DNS_R_USETCP; 1116 1.1 christos goto cleanup; 1117 1.1 christos } 1118 1.1 christos isc_buffer_allocate(mctx, &buf2, r.length + (tcp ? 2 : 0)); 1119 1.1 christos if (tcp) { 1120 1.1 christos isc_buffer_putuint16(buf2, (uint16_t)r.length); 1121 1.1 christos } 1122 1.1 christos result = isc_buffer_copyregion(buf2, &r); 1123 1.1 christos if (result != ISC_R_SUCCESS) { 1124 1.1 christos goto cleanup; 1125 1.1 christos } 1126 1.1 christos 1127 1.1 christos /* 1128 1.1 christos * Cleanup and return. 1129 1.1 christos */ 1130 1.1 christos isc_buffer_free(&buf1); 1131 1.1 christos *bufferp = buf2; 1132 1.1 christos return (ISC_R_SUCCESS); 1133 1.1 christos 1134 1.1 christos cleanup: 1135 1.1 christos dns_message_renderreset(message); 1136 1.1 christos if (buf1 != NULL) { 1137 1.1 christos isc_buffer_free(&buf1); 1138 1.1 christos } 1139 1.1 christos if (buf2 != NULL) { 1140 1.1 christos isc_buffer_free(&buf2); 1141 1.1 christos } 1142 1.1 christos if (cleanup_cctx) { 1143 1.1 christos dns_compress_invalidate(&cctx); 1144 1.1 christos } 1145 1.1 christos return (result); 1146 1.1 christos } 1147 1.1 christos 1148 1.1 christos /* 1149 1.1 christos * If this request is no longer waiting for events, 1150 1.1 christos * send the completion event. This will ultimately 1151 1.1 christos * cause the request to be destroyed. 1152 1.1 christos * 1153 1.1 christos * Requires: 1154 1.1 christos * 'request' is locked by the caller. 1155 1.1 christos */ 1156 1.1 christos static void 1157 1.1 christos send_if_done(dns_request_t *request, isc_result_t result) { 1158 1.1 christos if (request->event != NULL && !request->canceling) { 1159 1.1 christos req_sendevent(request, result); 1160 1.1 christos } 1161 1.1 christos } 1162 1.1 christos 1163 1.1 christos /* 1164 1.1 christos * Handle the control event. 1165 1.1 christos */ 1166 1.1 christos static void 1167 1.1 christos do_cancel(isc_task_t *task, isc_event_t *event) { 1168 1.1 christos dns_request_t *request = event->ev_arg; 1169 1.1 christos UNUSED(task); 1170 1.1 christos INSIST(event->ev_type == DNS_EVENT_REQUESTCONTROL); 1171 1.1 christos LOCK(&request->requestmgr->locks[request->hash]); 1172 1.1 christos request->canceling = false; 1173 1.1 christos if (!DNS_REQUEST_CANCELED(request)) { 1174 1.1 christos req_cancel(request); 1175 1.1 christos } 1176 1.1 christos send_if_done(request, ISC_R_CANCELED); 1177 1.1 christos UNLOCK(&request->requestmgr->locks[request->hash]); 1178 1.1 christos } 1179 1.1 christos 1180 1.1 christos void 1181 1.1 christos dns_request_cancel(dns_request_t *request) { 1182 1.1 christos REQUIRE(VALID_REQUEST(request)); 1183 1.1 christos 1184 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_cancel: request %p", request); 1185 1.1 christos 1186 1.1 christos REQUIRE(VALID_REQUEST(request)); 1187 1.1 christos 1188 1.1 christos LOCK(&request->requestmgr->locks[request->hash]); 1189 1.1 christos if (!request->canceling && !DNS_REQUEST_CANCELED(request)) { 1190 1.1 christos isc_event_t *ev = &request->ctlevent; 1191 1.1 christos isc_task_send(request->event->ev_sender, &ev); 1192 1.1 christos request->canceling = true; 1193 1.1 christos } 1194 1.1 christos UNLOCK(&request->requestmgr->locks[request->hash]); 1195 1.1 christos } 1196 1.1 christos 1197 1.1 christos isc_result_t 1198 1.1 christos dns_request_getresponse(dns_request_t *request, dns_message_t *message, 1199 1.1 christos unsigned int options) { 1200 1.1 christos isc_result_t result; 1201 1.1 christos 1202 1.1 christos REQUIRE(VALID_REQUEST(request)); 1203 1.1 christos REQUIRE(request->answer != NULL); 1204 1.1 christos 1205 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_getresponse: request %p", 1206 1.1 christos request); 1207 1.1 christos 1208 1.1 christos result = dns_message_setquerytsig(message, request->tsig); 1209 1.1 christos if (result != ISC_R_SUCCESS) { 1210 1.1 christos return (result); 1211 1.1 christos } 1212 1.1 christos result = dns_message_settsigkey(message, request->tsigkey); 1213 1.1 christos if (result != ISC_R_SUCCESS) { 1214 1.1 christos return (result); 1215 1.1 christos } 1216 1.1 christos result = dns_message_parse(message, request->answer, options); 1217 1.1 christos if (result != ISC_R_SUCCESS) { 1218 1.1 christos return (result); 1219 1.1 christos } 1220 1.1 christos if (request->tsigkey != NULL) { 1221 1.1 christos result = dns_tsig_verify(request->answer, message, NULL, NULL); 1222 1.1 christos } 1223 1.1 christos return (result); 1224 1.1 christos } 1225 1.1 christos 1226 1.1 christos isc_buffer_t * 1227 1.1 christos dns_request_getanswer(dns_request_t *request) { 1228 1.1 christos REQUIRE(VALID_REQUEST(request)); 1229 1.1 christos 1230 1.1 christos return (request->answer); 1231 1.1 christos } 1232 1.1 christos 1233 1.1 christos bool 1234 1.1 christos dns_request_usedtcp(dns_request_t *request) { 1235 1.1 christos REQUIRE(VALID_REQUEST(request)); 1236 1.1 christos 1237 1.1 christos return ((request->flags & DNS_REQUEST_F_TCP) != 0); 1238 1.1 christos } 1239 1.1 christos 1240 1.1 christos void 1241 1.1 christos dns_request_destroy(dns_request_t **requestp) { 1242 1.1 christos dns_request_t *request; 1243 1.1 christos 1244 1.1 christos REQUIRE(requestp != NULL && VALID_REQUEST(*requestp)); 1245 1.1 christos 1246 1.1 christos request = *requestp; 1247 1.1 christos *requestp = NULL; 1248 1.1 christos 1249 1.1 christos req_log(ISC_LOG_DEBUG(3), "dns_request_destroy: request %p", request); 1250 1.1 christos 1251 1.1 christos LOCK(&request->requestmgr->lock); 1252 1.1 christos LOCK(&request->requestmgr->locks[request->hash]); 1253 1.1 christos ISC_LIST_UNLINK(request->requestmgr->requests, request, link); 1254 1.1 christos INSIST(!DNS_REQUEST_CONNECTING(request)); 1255 1.1 christos INSIST(!DNS_REQUEST_SENDING(request)); 1256 1.1 christos UNLOCK(&request->requestmgr->locks[request->hash]); 1257 1.1 christos UNLOCK(&request->requestmgr->lock); 1258 1.1 christos 1259 1.1 christos /* 1260 1.1 christos * These should have been cleaned up by req_cancel() before 1261 1.1 christos * the completion event was sent. 1262 1.1 christos */ 1263 1.1 christos INSIST(!ISC_LINK_LINKED(request, link)); 1264 1.1 christos INSIST(request->dispentry == NULL); 1265 1.1 christos INSIST(request->dispatch == NULL); 1266 1.1 christos INSIST(request->timer == NULL); 1267 1.1 christos 1268 1.1 christos req_destroy(request); 1269 1.1 christos } 1270 1.1 christos 1271 1.1 christos /*** 1272 1.1 christos *** Private: request. 1273 1.1 christos ***/ 1274 1.1 christos 1275 1.1 christos static isc_socket_t * 1276 1.1 christos req_getsocket(dns_request_t *request) { 1277 1.1 christos unsigned int dispattr; 1278 1.1 christos isc_socket_t *sock; 1279 1.1 christos 1280 1.1 christos dispattr = dns_dispatch_getattributes(request->dispatch); 1281 1.1 christos if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 1282 1.1 christos INSIST(request->dispentry != NULL); 1283 1.1 christos sock = dns_dispatch_getentrysocket(request->dispentry); 1284 1.1 christos } else { 1285 1.1 christos sock = dns_dispatch_getsocket(request->dispatch); 1286 1.1 christos } 1287 1.1 christos 1288 1.1 christos return (sock); 1289 1.1 christos } 1290 1.1 christos 1291 1.1 christos static void 1292 1.1 christos req_connected(isc_task_t *task, isc_event_t *event) { 1293 1.1 christos isc_socketevent_t *sevent = (isc_socketevent_t *)event; 1294 1.1 christos isc_result_t result; 1295 1.1 christos dns_request_t *request = event->ev_arg; 1296 1.1 christos 1297 1.1 christos REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT); 1298 1.1 christos REQUIRE(VALID_REQUEST(request)); 1299 1.1 christos REQUIRE(DNS_REQUEST_CONNECTING(request)); 1300 1.1 christos 1301 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_connected: request %p", request); 1302 1.1 christos 1303 1.1 christos result = sevent->result; 1304 1.1 christos isc_event_free(&event); 1305 1.1 christos 1306 1.1 christos LOCK(&request->requestmgr->locks[request->hash]); 1307 1.1 christos request->flags &= ~DNS_REQUEST_F_CONNECTING; 1308 1.1 christos 1309 1.1 christos if (DNS_REQUEST_CANCELED(request)) { 1310 1.1 christos /* 1311 1.1 christos * Send delayed event. 1312 1.1 christos */ 1313 1.1 christos if (DNS_REQUEST_TIMEDOUT(request)) { 1314 1.1 christos send_if_done(request, ISC_R_TIMEDOUT); 1315 1.1 christos } else { 1316 1.1 christos send_if_done(request, ISC_R_CANCELED); 1317 1.1 christos } 1318 1.1 christos } else { 1319 1.1 christos dns_dispatch_starttcp(request->dispatch); 1320 1.1 christos if (result == ISC_R_SUCCESS) { 1321 1.1 christos result = req_send(request, task, NULL); 1322 1.1 christos } 1323 1.1 christos 1324 1.1 christos if (result != ISC_R_SUCCESS) { 1325 1.1 christos req_cancel(request); 1326 1.1 christos send_if_done(request, ISC_R_CANCELED); 1327 1.1 christos } 1328 1.1 christos } 1329 1.1 christos UNLOCK(&request->requestmgr->locks[request->hash]); 1330 1.1 christos } 1331 1.1 christos 1332 1.1 christos static void 1333 1.1 christos req_senddone(isc_task_t *task, isc_event_t *event) { 1334 1.1 christos isc_socketevent_t *sevent = (isc_socketevent_t *)event; 1335 1.1 christos dns_request_t *request = event->ev_arg; 1336 1.1 christos isc_result_t result = sevent->result; 1337 1.1 christos 1338 1.1 christos REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE); 1339 1.1 christos REQUIRE(VALID_REQUEST(request)); 1340 1.1 christos REQUIRE(DNS_REQUEST_SENDING(request)); 1341 1.1 christos 1342 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_senddone: request %p", request); 1343 1.1 christos 1344 1.1 christos UNUSED(task); 1345 1.1 christos 1346 1.1 christos isc_event_free(&event); 1347 1.1 christos 1348 1.1 christos LOCK(&request->requestmgr->locks[request->hash]); 1349 1.1 christos request->flags &= ~DNS_REQUEST_F_SENDING; 1350 1.1 christos 1351 1.1 christos if (DNS_REQUEST_CANCELED(request)) { 1352 1.1 christos /* 1353 1.1 christos * Send delayed event. 1354 1.1 christos */ 1355 1.1 christos if (DNS_REQUEST_TIMEDOUT(request)) { 1356 1.1 christos send_if_done(request, ISC_R_TIMEDOUT); 1357 1.1 christos } else { 1358 1.1 christos send_if_done(request, ISC_R_CANCELED); 1359 1.1 christos } 1360 1.1 christos } else if (result != ISC_R_SUCCESS) { 1361 1.1 christos req_cancel(request); 1362 1.1 christos send_if_done(request, ISC_R_CANCELED); 1363 1.1 christos } 1364 1.1 christos UNLOCK(&request->requestmgr->locks[request->hash]); 1365 1.1 christos } 1366 1.1 christos 1367 1.1 christos static void 1368 1.1 christos req_response(isc_task_t *task, isc_event_t *event) { 1369 1.1 christos isc_result_t result; 1370 1.1 christos dns_request_t *request = event->ev_arg; 1371 1.1 christos dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event; 1372 1.1 christos isc_region_t r; 1373 1.1 christos 1374 1.1 christos REQUIRE(VALID_REQUEST(request)); 1375 1.1 christos REQUIRE(event->ev_type == DNS_EVENT_DISPATCH); 1376 1.1 christos 1377 1.1 christos UNUSED(task); 1378 1.1 christos 1379 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_response: request %p: %s", request, 1380 1.1 christos dns_result_totext(devent->result)); 1381 1.1 christos 1382 1.1 christos LOCK(&request->requestmgr->locks[request->hash]); 1383 1.1 christos result = devent->result; 1384 1.1 christos if (result != ISC_R_SUCCESS) { 1385 1.1 christos goto done; 1386 1.1 christos } 1387 1.1 christos 1388 1.1 christos /* 1389 1.1 christos * Copy buffer to request. 1390 1.1 christos */ 1391 1.1 christos isc_buffer_usedregion(&devent->buffer, &r); 1392 1.1 christos isc_buffer_allocate(request->mctx, &request->answer, r.length); 1393 1.1 christos result = isc_buffer_copyregion(request->answer, &r); 1394 1.1 christos if (result != ISC_R_SUCCESS) { 1395 1.1 christos isc_buffer_free(&request->answer); 1396 1.1 christos } 1397 1.1 christos done: 1398 1.1 christos /* 1399 1.1 christos * Cleanup. 1400 1.1 christos */ 1401 1.1 christos dns_dispatch_removeresponse(&request->dispentry, &devent); 1402 1.1 christos req_cancel(request); 1403 1.1 christos /* 1404 1.1 christos * Send completion event. 1405 1.1 christos */ 1406 1.1 christos send_if_done(request, result); 1407 1.1 christos UNLOCK(&request->requestmgr->locks[request->hash]); 1408 1.1 christos } 1409 1.1 christos 1410 1.1 christos static void 1411 1.1 christos req_timeout(isc_task_t *task, isc_event_t *event) { 1412 1.1 christos dns_request_t *request = event->ev_arg; 1413 1.1 christos isc_result_t result; 1414 1.1 christos isc_eventtype_t ev_type = event->ev_type; 1415 1.1 christos 1416 1.1 christos REQUIRE(VALID_REQUEST(request)); 1417 1.1 christos 1418 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_timeout: request %p", request); 1419 1.1 christos 1420 1.1 christos UNUSED(task); 1421 1.1 christos 1422 1.1 christos isc_event_free(&event); 1423 1.1 christos 1424 1.1 christos LOCK(&request->requestmgr->locks[request->hash]); 1425 1.1 christos if (ev_type == ISC_TIMEREVENT_TICK && request->udpcount-- != 0) { 1426 1.1 christos if (!DNS_REQUEST_SENDING(request)) { 1427 1.1 christos result = req_send(request, task, &request->destaddr); 1428 1.1 christos if (result != ISC_R_SUCCESS) { 1429 1.1 christos req_cancel(request); 1430 1.1 christos send_if_done(request, result); 1431 1.1 christos } 1432 1.1 christos } 1433 1.1 christos } else { 1434 1.1 christos request->flags |= DNS_REQUEST_F_TIMEDOUT; 1435 1.1 christos req_cancel(request); 1436 1.1 christos send_if_done(request, ISC_R_TIMEDOUT); 1437 1.1 christos } 1438 1.1 christos UNLOCK(&request->requestmgr->locks[request->hash]); 1439 1.1 christos } 1440 1.1 christos 1441 1.1 christos static void 1442 1.1 christos req_sendevent(dns_request_t *request, isc_result_t result) { 1443 1.1 christos isc_task_t *task; 1444 1.1 christos 1445 1.1 christos REQUIRE(VALID_REQUEST(request)); 1446 1.1 christos 1447 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_sendevent: request %p", request); 1448 1.1 christos 1449 1.1 christos /* 1450 1.1 christos * Lock held by caller. 1451 1.1 christos */ 1452 1.1 christos task = request->event->ev_sender; 1453 1.1 christos request->event->ev_sender = request; 1454 1.1 christos request->event->result = result; 1455 1.1 christos isc_task_sendanddetach(&task, (isc_event_t **)(void *)&request->event); 1456 1.1 christos } 1457 1.1 christos 1458 1.1 christos static void 1459 1.1 christos req_destroy(dns_request_t *request) { 1460 1.1 christos REQUIRE(VALID_REQUEST(request)); 1461 1.1 christos 1462 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_destroy: request %p", request); 1463 1.1 christos 1464 1.1 christos request->magic = 0; 1465 1.1 christos if (request->query != NULL) { 1466 1.1 christos isc_buffer_free(&request->query); 1467 1.1 christos } 1468 1.1 christos if (request->answer != NULL) { 1469 1.1 christos isc_buffer_free(&request->answer); 1470 1.1 christos } 1471 1.1 christos if (request->event != NULL) { 1472 1.1 christos isc_event_free((isc_event_t **)(void *)&request->event); 1473 1.1 christos } 1474 1.1 christos if (request->dispentry != NULL) { 1475 1.1 christos dns_dispatch_removeresponse(&request->dispentry, NULL); 1476 1.1 christos } 1477 1.1 christos if (request->dispatch != NULL) { 1478 1.1 christos dns_dispatch_detach(&request->dispatch); 1479 1.1 christos } 1480 1.1 christos if (request->timer != NULL) { 1481 1.1 christos isc_timer_destroy(&request->timer); 1482 1.1 christos } 1483 1.1 christos if (request->tsig != NULL) { 1484 1.1 christos isc_buffer_free(&request->tsig); 1485 1.1 christos } 1486 1.1 christos if (request->tsigkey != NULL) { 1487 1.1 christos dns_tsigkey_detach(&request->tsigkey); 1488 1.1 christos } 1489 1.1 christos if (request->requestmgr != NULL) { 1490 1.1 christos requestmgr_detach(&request->requestmgr); 1491 1.1 christos } 1492 1.1 christos isc_mem_putanddetach(&request->mctx, request, sizeof(*request)); 1493 1.1 christos } 1494 1.1 christos 1495 1.1 christos /* 1496 1.1 christos * Stop the current request. Must be called from the request's task. 1497 1.1 christos */ 1498 1.1 christos static void 1499 1.1 christos req_cancel(dns_request_t *request) { 1500 1.1 christos isc_socket_t *sock; 1501 1.1 christos unsigned int dispattr; 1502 1.1 christos 1503 1.1 christos REQUIRE(VALID_REQUEST(request)); 1504 1.1 christos 1505 1.1 christos req_log(ISC_LOG_DEBUG(3), "req_cancel: request %p", request); 1506 1.1 christos 1507 1.1 christos /* 1508 1.1 christos * Lock held by caller. 1509 1.1 christos */ 1510 1.1 christos request->flags |= DNS_REQUEST_F_CANCELED; 1511 1.1 christos 1512 1.1 christos if (request->timer != NULL) { 1513 1.1 christos isc_timer_destroy(&request->timer); 1514 1.1 christos } 1515 1.1 christos dispattr = dns_dispatch_getattributes(request->dispatch); 1516 1.1 christos sock = NULL; 1517 1.1 christos if (DNS_REQUEST_CONNECTING(request) || DNS_REQUEST_SENDING(request)) { 1518 1.1 christos if ((dispattr & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 1519 1.1 christos if (request->dispentry != NULL) { 1520 1.1 christos sock = dns_dispatch_getentrysocket( 1521 1.1 christos request->dispentry); 1522 1.1 christos } 1523 1.1 christos } else { 1524 1.1 christos sock = dns_dispatch_getsocket(request->dispatch); 1525 1.1 christos } 1526 1.1 christos if (DNS_REQUEST_CONNECTING(request) && sock != NULL) { 1527 1.1 christos isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_CONNECT); 1528 1.1 christos } 1529 1.1 christos if (DNS_REQUEST_SENDING(request) && sock != NULL) { 1530 1.1 christos isc_socket_cancel(sock, NULL, ISC_SOCKCANCEL_SEND); 1531 1.1 christos } 1532 1.1 christos } 1533 1.1 christos if (request->dispentry != NULL) { 1534 1.1 christos dns_dispatch_removeresponse(&request->dispentry, NULL); 1535 1.1 christos } 1536 1.1 christos dns_dispatch_detach(&request->dispatch); 1537 1.1 christos } 1538 1.1 christos 1539 1.1 christos static void 1540 1.1 christos req_log(int level, const char *fmt, ...) { 1541 1.1 christos va_list ap; 1542 1.1 christos 1543 1.1 christos va_start(ap, fmt); 1544 1.1 christos isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_REQUEST, 1545 1.1 christos level, fmt, ap); 1546 1.1 christos va_end(ap); 1547 1.1 christos } 1548