1 1.1 christos /* $NetBSD: dispatch.c,v 1.1 2024/02/18 20:57:31 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 #include <stdlib.h> 21 1.1 christos #include <sys/types.h> 22 1.1 christos #include <unistd.h> 23 1.1 christos 24 1.1 christos #include <isc/mem.h> 25 1.1 christos #include <isc/mutex.h> 26 1.1 christos #include <isc/portset.h> 27 1.1 christos #include <isc/print.h> 28 1.1 christos #include <isc/random.h> 29 1.1 christos #include <isc/socket.h> 30 1.1 christos #include <isc/stats.h> 31 1.1 christos #include <isc/string.h> 32 1.1 christos #include <isc/task.h> 33 1.1 christos #include <isc/time.h> 34 1.1 christos #include <isc/util.h> 35 1.1 christos 36 1.1 christos #include <dns/acl.h> 37 1.1 christos #include <dns/dispatch.h> 38 1.1 christos #include <dns/events.h> 39 1.1 christos #include <dns/log.h> 40 1.1 christos #include <dns/message.h> 41 1.1 christos #include <dns/portlist.h> 42 1.1 christos #include <dns/stats.h> 43 1.1 christos #include <dns/tcpmsg.h> 44 1.1 christos #include <dns/types.h> 45 1.1 christos 46 1.1 christos typedef ISC_LIST(dns_dispentry_t) dns_displist_t; 47 1.1 christos 48 1.1 christos typedef struct dispsocket dispsocket_t; 49 1.1 christos typedef ISC_LIST(dispsocket_t) dispsocketlist_t; 50 1.1 christos 51 1.1 christos typedef struct dispportentry dispportentry_t; 52 1.1 christos typedef ISC_LIST(dispportentry_t) dispportlist_t; 53 1.1 christos 54 1.1 christos typedef struct dns_qid { 55 1.1 christos unsigned int magic; 56 1.1 christos unsigned int qid_nbuckets; /*%< hash table size */ 57 1.1 christos unsigned int qid_increment; /*%< id increment on collision */ 58 1.1 christos isc_mutex_t lock; 59 1.1 christos dns_displist_t *qid_table; /*%< the table itself */ 60 1.1 christos dispsocketlist_t *sock_table; /*%< socket table */ 61 1.1 christos } dns_qid_t; 62 1.1 christos 63 1.1 christos struct dns_dispatchmgr { 64 1.1 christos /* Unlocked. */ 65 1.1 christos unsigned int magic; 66 1.1 christos isc_mem_t *mctx; 67 1.1 christos dns_acl_t *blackhole; 68 1.1 christos dns_portlist_t *portlist; 69 1.1 christos isc_stats_t *stats; 70 1.1 christos 71 1.1 christos /* Locked by "lock". */ 72 1.1 christos isc_mutex_t lock; 73 1.1 christos unsigned int state; 74 1.1 christos ISC_LIST(dns_dispatch_t) list; 75 1.1 christos 76 1.1 christos /* locked by buffer_lock */ 77 1.1 christos dns_qid_t *qid; 78 1.1 christos isc_mutex_t buffer_lock; 79 1.1 christos unsigned int buffers; /*%< allocated buffers */ 80 1.1 christos unsigned int buffersize; /*%< size of each buffer */ 81 1.1 christos unsigned int maxbuffers; /*%< max buffers */ 82 1.1 christos 83 1.1 christos isc_refcount_t irefs; 84 1.1 christos 85 1.1 christos /*% 86 1.1 christos * Locked by qid->lock if qid exists; otherwise, can be used without 87 1.1 christos * being locked. 88 1.1 christos * Memory footprint considerations: this is a simple implementation of 89 1.1 christos * available ports, i.e., an ordered array of the actual port numbers. 90 1.1 christos * This will require about 256KB of memory in the worst case (128KB for 91 1.1 christos * each of IPv4 and IPv6). We could reduce it by representing it as a 92 1.1 christos * more sophisticated way such as a list (or array) of ranges that are 93 1.1 christos * searched to identify a specific port. Our decision here is the saved 94 1.1 christos * memory isn't worth the implementation complexity, considering the 95 1.1 christos * fact that the whole BIND9 process (which is mainly named) already 96 1.1 christos * requires a pretty large memory footprint. We may, however, have to 97 1.1 christos * revisit the decision when we want to use it as a separate module for 98 1.1 christos * an environment where memory requirement is severer. 99 1.1 christos */ 100 1.1 christos in_port_t *v4ports; /*%< available ports for IPv4 */ 101 1.1 christos unsigned int nv4ports; /*%< # of available ports for IPv4 */ 102 1.1 christos in_port_t *v6ports; /*%< available ports for IPv4 */ 103 1.1 christos unsigned int nv6ports; /*%< # of available ports for IPv4 */ 104 1.1 christos }; 105 1.1 christos 106 1.1 christos #define MGR_SHUTTINGDOWN 0x00000001U 107 1.1 christos #define MGR_IS_SHUTTINGDOWN(l) (((l)->state & MGR_SHUTTINGDOWN) != 0) 108 1.1 christos 109 1.1 christos #define IS_PRIVATE(d) (((d)->attributes & DNS_DISPATCHATTR_PRIVATE) != 0) 110 1.1 christos 111 1.1 christos struct dns_dispentry { 112 1.1 christos unsigned int magic; 113 1.1 christos dns_dispatch_t *disp; 114 1.1 christos dns_messageid_t id; 115 1.1 christos in_port_t port; 116 1.1 christos unsigned int bucket; 117 1.1 christos isc_sockaddr_t host; 118 1.1 christos isc_task_t *task; 119 1.1 christos isc_taskaction_t action; 120 1.1 christos void *arg; 121 1.1 christos bool item_out; 122 1.1 christos dispsocket_t *dispsocket; 123 1.1 christos ISC_LIST(dns_dispatchevent_t) items; 124 1.1 christos ISC_LINK(dns_dispentry_t) link; 125 1.1 christos }; 126 1.1 christos 127 1.1 christos /*% 128 1.1 christos * Maximum number of dispatch sockets that can be pooled for reuse. The 129 1.1 christos * appropriate value may vary, but experiments have shown a busy caching server 130 1.1 christos * may need more than 1000 sockets concurrently opened. The maximum allowable 131 1.1 christos * number of dispatch sockets (per manager) will be set to the double of this 132 1.1 christos * value. 133 1.1 christos */ 134 1.1 christos #ifndef DNS_DISPATCH_POOLSOCKS 135 1.1 christos #define DNS_DISPATCH_POOLSOCKS 2048 136 1.1 christos #endif /* ifndef DNS_DISPATCH_POOLSOCKS */ 137 1.1 christos 138 1.1 christos /*% 139 1.1 christos * Quota to control the number of dispatch sockets. If a dispatch has more 140 1.1 christos * than the quota of sockets, new queries will purge oldest ones, so that 141 1.1 christos * a massive number of outstanding queries won't prevent subsequent queries 142 1.1 christos * (especially if the older ones take longer time and result in timeout). 143 1.1 christos */ 144 1.1 christos #ifndef DNS_DISPATCH_SOCKSQUOTA 145 1.1 christos #define DNS_DISPATCH_SOCKSQUOTA 3072 146 1.1 christos #endif /* ifndef DNS_DISPATCH_SOCKSQUOTA */ 147 1.1 christos 148 1.1 christos struct dispsocket { 149 1.1 christos unsigned int magic; 150 1.1 christos isc_socket_t *socket; 151 1.1 christos dns_dispatch_t *disp; 152 1.1 christos isc_sockaddr_t host; 153 1.1 christos in_port_t localport; /* XXX: should be removed later */ 154 1.1 christos dispportentry_t *portentry; 155 1.1 christos dns_dispentry_t *resp; 156 1.1 christos isc_task_t *task; 157 1.1 christos ISC_LINK(dispsocket_t) link; 158 1.1 christos unsigned int bucket; 159 1.1 christos ISC_LINK(dispsocket_t) blink; 160 1.1 christos }; 161 1.1 christos 162 1.1 christos /*% 163 1.1 christos * A port table entry. We remember every port we first open in a table with a 164 1.1 christos * reference counter so that we can 'reuse' the same port (with different 165 1.1 christos * destination addresses) using the SO_REUSEADDR socket option. 166 1.1 christos */ 167 1.1 christos struct dispportentry { 168 1.1 christos in_port_t port; 169 1.1 christos isc_refcount_t refs; 170 1.1 christos ISC_LINK(struct dispportentry) link; 171 1.1 christos }; 172 1.1 christos 173 1.1 christos #ifndef DNS_DISPATCH_PORTTABLESIZE 174 1.1 christos #define DNS_DISPATCH_PORTTABLESIZE 1024 175 1.1 christos #endif /* ifndef DNS_DISPATCH_PORTTABLESIZE */ 176 1.1 christos 177 1.1 christos #define INVALID_BUCKET (0xffffdead) 178 1.1 christos 179 1.1 christos /*% 180 1.1 christos * Number of tasks for each dispatch that use separate sockets for different 181 1.1 christos * transactions. This must be a power of 2 as it will divide 32 bit numbers 182 1.1 christos * to get an uniformly random tasks selection. See get_dispsocket(). 183 1.1 christos */ 184 1.1 christos #define MAX_INTERNAL_TASKS 64 185 1.1 christos 186 1.1 christos struct dns_dispatch { 187 1.1 christos /* Unlocked. */ 188 1.1 christos unsigned int magic; /*%< magic */ 189 1.1 christos dns_dispatchmgr_t *mgr; /*%< dispatch manager */ 190 1.1 christos int ntasks; 191 1.1 christos /*% 192 1.1 christos * internal task buckets. We use multiple tasks to distribute various 193 1.1 christos * socket events well when using separate dispatch sockets. We use the 194 1.1 christos * 1st task (task[0]) for internal control events. 195 1.1 christos */ 196 1.1 christos isc_task_t *task[MAX_INTERNAL_TASKS]; 197 1.1 christos isc_socket_t *socket; /*%< isc socket attached to */ 198 1.1 christos isc_sockaddr_t local; /*%< local address */ 199 1.1 christos in_port_t localport; /*%< local UDP port */ 200 1.1 christos isc_sockaddr_t peer; /*%< peer address (TCP) */ 201 1.1 christos isc_dscp_t dscp; /*%< "listen-on" DSCP value */ 202 1.1 christos unsigned int maxrequests; /*%< max requests */ 203 1.1 christos isc_event_t *ctlevent; 204 1.1 christos 205 1.1 christos isc_mem_t *sepool; /*%< pool for socket events */ 206 1.1 christos 207 1.1 christos /*% Locked by mgr->lock. */ 208 1.1 christos ISC_LINK(dns_dispatch_t) link; 209 1.1 christos 210 1.1 christos /* Locked by "lock". */ 211 1.1 christos isc_mutex_t lock; /*%< locks all below */ 212 1.1 christos isc_sockettype_t socktype; 213 1.1 christos unsigned int attributes; 214 1.1 christos unsigned int refcount; /*%< number of users */ 215 1.1 christos dns_dispatchevent_t *failsafe_ev; /*%< failsafe cancel event */ 216 1.1 christos unsigned int shutting_down : 1, shutdown_out : 1, connected : 1, 217 1.1 christos tcpmsg_valid : 1, recv_pending : 1; /*%< is a 218 1.1 christos * recv() 219 1.1 christos * pending? 220 1.1 christos * */ 221 1.1 christos isc_result_t shutdown_why; 222 1.1 christos ISC_LIST(dispsocket_t) activesockets; 223 1.1 christos ISC_LIST(dispsocket_t) inactivesockets; 224 1.1 christos unsigned int nsockets; 225 1.1 christos unsigned int requests; /*%< how many requests we have */ 226 1.1 christos unsigned int tcpbuffers; /*%< allocated buffers */ 227 1.1 christos dns_tcpmsg_t tcpmsg; /*%< for tcp streams */ 228 1.1 christos dns_qid_t *qid; 229 1.1 christos dispportlist_t *port_table; /*%< hold ports 'owned' by us */ 230 1.1 christos }; 231 1.1 christos 232 1.1 christos #define QID_MAGIC ISC_MAGIC('Q', 'i', 'd', ' ') 233 1.1 christos #define VALID_QID(e) ISC_MAGIC_VALID((e), QID_MAGIC) 234 1.1 christos 235 1.1 christos #define RESPONSE_MAGIC ISC_MAGIC('D', 'r', 's', 'p') 236 1.1 christos #define VALID_RESPONSE(e) ISC_MAGIC_VALID((e), RESPONSE_MAGIC) 237 1.1 christos 238 1.1 christos #define DISPSOCK_MAGIC ISC_MAGIC('D', 's', 'o', 'c') 239 1.1 christos #define VALID_DISPSOCK(e) ISC_MAGIC_VALID((e), DISPSOCK_MAGIC) 240 1.1 christos 241 1.1 christos #define DISPATCH_MAGIC ISC_MAGIC('D', 'i', 's', 'p') 242 1.1 christos #define VALID_DISPATCH(e) ISC_MAGIC_VALID((e), DISPATCH_MAGIC) 243 1.1 christos 244 1.1 christos #define DNS_DISPATCHMGR_MAGIC ISC_MAGIC('D', 'M', 'g', 'r') 245 1.1 christos #define VALID_DISPATCHMGR(e) ISC_MAGIC_VALID((e), DNS_DISPATCHMGR_MAGIC) 246 1.1 christos 247 1.1 christos #define DNS_QID(disp) \ 248 1.1 christos ((disp)->socktype == isc_sockettype_tcp) ? (disp)->qid \ 249 1.1 christos : (disp)->mgr->qid 250 1.1 christos 251 1.1 christos /*% 252 1.1 christos * Locking a query port buffer is a bit tricky. We access the buffer without 253 1.1 christos * locking until qid is created. Technically, there is a possibility of race 254 1.1 christos * between the creation of qid and access to the port buffer; in practice, 255 1.1 christos * however, this should be safe because qid isn't created until the first 256 1.1 christos * dispatch is created and there should be no contending situation until then. 257 1.1 christos */ 258 1.1 christos #define PORTBUFLOCK(mgr) \ 259 1.1 christos if ((mgr)->qid != NULL) \ 260 1.1 christos LOCK(&((mgr)->qid->lock)) 261 1.1 christos #define PORTBUFUNLOCK(mgr) \ 262 1.1 christos if ((mgr)->qid != NULL) \ 263 1.1 christos UNLOCK((&(mgr)->qid->lock)) 264 1.1 christos 265 1.1 christos /* 266 1.1 christos * Statics. 267 1.1 christos */ 268 1.1 christos static dns_dispentry_t * 269 1.1 christos entry_search(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t, 270 1.1 christos unsigned int); 271 1.1 christos static bool 272 1.1 christos destroy_disp_ok(dns_dispatch_t *); 273 1.1 christos static void 274 1.1 christos destroy_disp(isc_task_t *task, isc_event_t *event); 275 1.1 christos static void 276 1.1 christos destroy_dispsocket(dns_dispatch_t *, dispsocket_t **); 277 1.1 christos static void 278 1.1 christos deactivate_dispsocket(dns_dispatch_t *, dispsocket_t *); 279 1.1 christos static void 280 1.1 christos udp_exrecv(isc_task_t *, isc_event_t *); 281 1.1 christos static void 282 1.1 christos udp_shrecv(isc_task_t *, isc_event_t *); 283 1.1 christos static void 284 1.1 christos udp_recv(isc_event_t *, dns_dispatch_t *, dispsocket_t *); 285 1.1 christos static void 286 1.1 christos tcp_recv(isc_task_t *, isc_event_t *); 287 1.1 christos static isc_result_t 288 1.1 christos startrecv(dns_dispatch_t *, dispsocket_t *); 289 1.1 christos static uint32_t 290 1.1 christos dns_hash(dns_qid_t *, const isc_sockaddr_t *, dns_messageid_t, in_port_t); 291 1.1 christos static void 292 1.1 christos free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len); 293 1.1 christos static void * 294 1.1 christos allocate_udp_buffer(dns_dispatch_t *disp); 295 1.1 christos static void 296 1.1 christos free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev); 297 1.1 christos static dns_dispatchevent_t * 298 1.1 christos allocate_devent(dns_dispatch_t *disp); 299 1.1 christos static void 300 1.1 christos do_cancel(dns_dispatch_t *disp); 301 1.1 christos static dns_dispentry_t * 302 1.1 christos linear_first(dns_qid_t *disp); 303 1.1 christos static dns_dispentry_t * 304 1.1 christos linear_next(dns_qid_t *disp, dns_dispentry_t *resp); 305 1.1 christos static void 306 1.1 christos dispatch_free(dns_dispatch_t **dispp); 307 1.1 christos static isc_result_t 308 1.1 christos get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, 309 1.1 christos isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, 310 1.1 christos isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly); 311 1.1 christos static isc_result_t 312 1.1 christos dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, 313 1.1 christos isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, 314 1.1 christos unsigned int maxrequests, unsigned int attributes, 315 1.1 christos dns_dispatch_t **dispp, isc_socket_t *dup_socket); 316 1.1 christos static bool 317 1.1 christos destroy_mgr_ok(dns_dispatchmgr_t *mgr); 318 1.1 christos static void 319 1.1 christos destroy_mgr(dns_dispatchmgr_t **mgrp); 320 1.1 christos static isc_result_t 321 1.1 christos qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, 322 1.1 christos unsigned int increment, dns_qid_t **qidp, bool needaddrtable); 323 1.1 christos static void 324 1.1 christos qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp); 325 1.1 christos static isc_result_t 326 1.1 christos open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, 327 1.1 christos unsigned int options, isc_socket_t **sockp, 328 1.1 christos isc_socket_t *dup_socket, bool duponly); 329 1.1 christos static bool 330 1.1 christos portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, 331 1.1 christos isc_sockaddr_t *sockaddrp); 332 1.1 christos 333 1.1 christos #define LVL(x) ISC_LOG_DEBUG(x) 334 1.1 christos 335 1.1 christos static void 336 1.1 christos mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) 337 1.1 christos ISC_FORMAT_PRINTF(3, 4); 338 1.1 christos 339 1.1 christos static void 340 1.1 christos mgr_log(dns_dispatchmgr_t *mgr, int level, const char *fmt, ...) { 341 1.1 christos char msgbuf[2048]; 342 1.1 christos va_list ap; 343 1.1 christos 344 1.1 christos if (!isc_log_wouldlog(dns_lctx, level)) { 345 1.1 christos return; 346 1.1 christos } 347 1.1 christos 348 1.1 christos va_start(ap, fmt); 349 1.1 christos vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 350 1.1 christos va_end(ap); 351 1.1 christos 352 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, 353 1.1 christos DNS_LOGMODULE_DISPATCH, level, "dispatchmgr %p: %s", mgr, 354 1.1 christos msgbuf); 355 1.1 christos } 356 1.1 christos 357 1.1 christos static void 358 1.1 christos inc_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) { 359 1.1 christos if (mgr->stats != NULL) { 360 1.1 christos isc_stats_increment(mgr->stats, counter); 361 1.1 christos } 362 1.1 christos } 363 1.1 christos 364 1.1 christos static void 365 1.1 christos dec_stats(dns_dispatchmgr_t *mgr, isc_statscounter_t counter) { 366 1.1 christos if (mgr->stats != NULL) { 367 1.1 christos isc_stats_decrement(mgr->stats, counter); 368 1.1 christos } 369 1.1 christos } 370 1.1 christos 371 1.1 christos static void 372 1.1 christos dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) 373 1.1 christos ISC_FORMAT_PRINTF(3, 4); 374 1.1 christos 375 1.1 christos static void 376 1.1 christos dispatch_log(dns_dispatch_t *disp, int level, const char *fmt, ...) { 377 1.1 christos char msgbuf[2048]; 378 1.1 christos va_list ap; 379 1.1 christos 380 1.1 christos if (!isc_log_wouldlog(dns_lctx, level)) { 381 1.1 christos return; 382 1.1 christos } 383 1.1 christos 384 1.1 christos va_start(ap, fmt); 385 1.1 christos vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 386 1.1 christos va_end(ap); 387 1.1 christos 388 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, 389 1.1 christos DNS_LOGMODULE_DISPATCH, level, "dispatch %p: %s", disp, 390 1.1 christos msgbuf); 391 1.1 christos } 392 1.1 christos 393 1.1 christos static void 394 1.1 christos request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, 395 1.1 christos const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5); 396 1.1 christos 397 1.1 christos static void 398 1.1 christos request_log(dns_dispatch_t *disp, dns_dispentry_t *resp, int level, 399 1.1 christos const char *fmt, ...) { 400 1.1 christos char msgbuf[2048]; 401 1.1 christos char peerbuf[256]; 402 1.1 christos va_list ap; 403 1.1 christos 404 1.1 christos if (!isc_log_wouldlog(dns_lctx, level)) { 405 1.1 christos return; 406 1.1 christos } 407 1.1 christos 408 1.1 christos va_start(ap, fmt); 409 1.1 christos vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 410 1.1 christos va_end(ap); 411 1.1 christos 412 1.1 christos if (VALID_RESPONSE(resp)) { 413 1.1 christos isc_sockaddr_format(&resp->host, peerbuf, sizeof(peerbuf)); 414 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, 415 1.1 christos DNS_LOGMODULE_DISPATCH, level, 416 1.1 christos "dispatch %p response %p %s: %s", disp, resp, 417 1.1 christos peerbuf, msgbuf); 418 1.1 christos } else { 419 1.1 christos isc_log_write(dns_lctx, DNS_LOGCATEGORY_DISPATCH, 420 1.1 christos DNS_LOGMODULE_DISPATCH, level, 421 1.1 christos "dispatch %p req/resp %p: %s", disp, resp, 422 1.1 christos msgbuf); 423 1.1 christos } 424 1.1 christos } 425 1.1 christos 426 1.1 christos /* 427 1.1 christos * Return a hash of the destination and message id. 428 1.1 christos */ 429 1.1 christos static uint32_t 430 1.1 christos dns_hash(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, 431 1.1 christos in_port_t port) { 432 1.1 christos uint32_t ret; 433 1.1 christos 434 1.1 christos ret = isc_sockaddr_hash(dest, true); 435 1.1 christos ret ^= ((uint32_t)id << 16) | port; 436 1.1 christos ret %= qid->qid_nbuckets; 437 1.1 christos 438 1.1 christos INSIST(ret < qid->qid_nbuckets); 439 1.1 christos 440 1.1 christos return (ret); 441 1.1 christos } 442 1.1 christos 443 1.1 christos /* 444 1.1 christos * Find the first entry in 'qid'. Returns NULL if there are no entries. 445 1.1 christos */ 446 1.1 christos static dns_dispentry_t * 447 1.1 christos linear_first(dns_qid_t *qid) { 448 1.1 christos dns_dispentry_t *ret; 449 1.1 christos unsigned int bucket; 450 1.1 christos 451 1.1 christos bucket = 0; 452 1.1 christos 453 1.1 christos while (bucket < qid->qid_nbuckets) { 454 1.1 christos ret = ISC_LIST_HEAD(qid->qid_table[bucket]); 455 1.1 christos if (ret != NULL) { 456 1.1 christos return (ret); 457 1.1 christos } 458 1.1 christos bucket++; 459 1.1 christos } 460 1.1 christos 461 1.1 christos return (NULL); 462 1.1 christos } 463 1.1 christos 464 1.1 christos /* 465 1.1 christos * Find the next entry after 'resp' in 'qid'. Return NULL if there are 466 1.1 christos * no more entries. 467 1.1 christos */ 468 1.1 christos static dns_dispentry_t * 469 1.1 christos linear_next(dns_qid_t *qid, dns_dispentry_t *resp) { 470 1.1 christos dns_dispentry_t *ret; 471 1.1 christos unsigned int bucket; 472 1.1 christos 473 1.1 christos ret = ISC_LIST_NEXT(resp, link); 474 1.1 christos if (ret != NULL) { 475 1.1 christos return (ret); 476 1.1 christos } 477 1.1 christos 478 1.1 christos bucket = resp->bucket; 479 1.1 christos bucket++; 480 1.1 christos while (bucket < qid->qid_nbuckets) { 481 1.1 christos ret = ISC_LIST_HEAD(qid->qid_table[bucket]); 482 1.1 christos if (ret != NULL) { 483 1.1 christos return (ret); 484 1.1 christos } 485 1.1 christos bucket++; 486 1.1 christos } 487 1.1 christos 488 1.1 christos return (NULL); 489 1.1 christos } 490 1.1 christos 491 1.1 christos /* 492 1.1 christos * The dispatch must be locked. 493 1.1 christos */ 494 1.1 christos static bool 495 1.1 christos destroy_disp_ok(dns_dispatch_t *disp) { 496 1.1 christos if (disp->refcount != 0) { 497 1.1 christos return (false); 498 1.1 christos } 499 1.1 christos 500 1.1 christos if (disp->recv_pending != 0) { 501 1.1 christos return (false); 502 1.1 christos } 503 1.1 christos 504 1.1 christos if (!ISC_LIST_EMPTY(disp->activesockets)) { 505 1.1 christos return (false); 506 1.1 christos } 507 1.1 christos 508 1.1 christos if (disp->shutting_down == 0) { 509 1.1 christos return (false); 510 1.1 christos } 511 1.1 christos 512 1.1 christos return (true); 513 1.1 christos } 514 1.1 christos 515 1.1 christos /* 516 1.1 christos * Called when refcount reaches 0 (and safe to destroy). 517 1.1 christos * 518 1.1 christos * The dispatcher must be locked. 519 1.1 christos * The manager must not be locked. 520 1.1 christos */ 521 1.1 christos static void 522 1.1 christos destroy_disp(isc_task_t *task, isc_event_t *event) { 523 1.1 christos dns_dispatch_t *disp; 524 1.1 christos dns_dispatchmgr_t *mgr; 525 1.1 christos bool killmgr; 526 1.1 christos dispsocket_t *dispsocket; 527 1.1 christos int i; 528 1.1 christos 529 1.1 christos INSIST(event->ev_type == DNS_EVENT_DISPATCHCONTROL); 530 1.1 christos 531 1.1 christos UNUSED(task); 532 1.1 christos 533 1.1 christos disp = event->ev_arg; 534 1.1 christos mgr = disp->mgr; 535 1.1 christos 536 1.1 christos LOCK(&mgr->lock); 537 1.1 christos ISC_LIST_UNLINK(mgr->list, disp, link); 538 1.1 christos 539 1.1 christos dispatch_log(disp, LVL(90), 540 1.1 christos "shutting down; detaching from sock %p, task %p", 541 1.1 christos disp->socket, disp->task[0]); /* XXXX */ 542 1.1 christos 543 1.1 christos if (disp->sepool != NULL) { 544 1.1 christos isc_mem_destroy(&disp->sepool); 545 1.1 christos } 546 1.1 christos 547 1.1 christos if (disp->socket != NULL) { 548 1.1 christos isc_socket_detach(&disp->socket); 549 1.1 christos } 550 1.1 christos while ((dispsocket = ISC_LIST_HEAD(disp->inactivesockets)) != NULL) { 551 1.1 christos ISC_LIST_UNLINK(disp->inactivesockets, dispsocket, link); 552 1.1 christos destroy_dispsocket(disp, &dispsocket); 553 1.1 christos } 554 1.1 christos for (i = 0; i < disp->ntasks; i++) { 555 1.1 christos isc_task_detach(&disp->task[i]); 556 1.1 christos } 557 1.1 christos isc_event_free(&event); 558 1.1 christos 559 1.1 christos dispatch_free(&disp); 560 1.1 christos 561 1.1 christos killmgr = destroy_mgr_ok(mgr); 562 1.1 christos UNLOCK(&mgr->lock); 563 1.1 christos if (killmgr) { 564 1.1 christos destroy_mgr(&mgr); 565 1.1 christos } 566 1.1 christos } 567 1.1 christos 568 1.1 christos /*% 569 1.1 christos * Manipulate port table per dispatch: find an entry for a given port number, 570 1.1 christos * create a new entry, and decrement a given entry with possible clean-up. 571 1.1 christos */ 572 1.1 christos static dispportentry_t * 573 1.1 christos port_search(dns_dispatch_t *disp, in_port_t port) { 574 1.1 christos dispportentry_t *portentry; 575 1.1 christos 576 1.1 christos REQUIRE(disp->port_table != NULL); 577 1.1 christos 578 1.1 christos portentry = ISC_LIST_HEAD( 579 1.1 christos disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE]); 580 1.1 christos while (portentry != NULL) { 581 1.1 christos if (portentry->port == port) { 582 1.1 christos return (portentry); 583 1.1 christos } 584 1.1 christos portentry = ISC_LIST_NEXT(portentry, link); 585 1.1 christos } 586 1.1 christos 587 1.1 christos return (NULL); 588 1.1 christos } 589 1.1 christos 590 1.1 christos static dispportentry_t * 591 1.1 christos new_portentry(dns_dispatch_t *disp, in_port_t port) { 592 1.1 christos dispportentry_t *portentry; 593 1.1 christos dns_qid_t *qid; 594 1.1 christos 595 1.1 christos REQUIRE(disp->port_table != NULL); 596 1.1 christos 597 1.1 christos portentry = isc_mem_get(disp->mgr->mctx, sizeof(*portentry)); 598 1.1 christos 599 1.1 christos portentry->port = port; 600 1.1 christos isc_refcount_init(&portentry->refs, 1); 601 1.1 christos ISC_LINK_INIT(portentry, link); 602 1.1 christos qid = DNS_QID(disp); 603 1.1 christos LOCK(&qid->lock); 604 1.1 christos ISC_LIST_APPEND(disp->port_table[port % DNS_DISPATCH_PORTTABLESIZE], 605 1.1 christos portentry, link); 606 1.1 christos UNLOCK(&qid->lock); 607 1.1 christos 608 1.1 christos return (portentry); 609 1.1 christos } 610 1.1 christos 611 1.1 christos /*% 612 1.1 christos * The caller must hold the qid->lock. 613 1.1 christos */ 614 1.1 christos static void 615 1.1 christos deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) { 616 1.1 christos dispportentry_t *portentry = *portentryp; 617 1.1 christos *portentryp = NULL; 618 1.1 christos 619 1.1 christos REQUIRE(disp->port_table != NULL); 620 1.1 christos REQUIRE(portentry != NULL); 621 1.1 christos 622 1.1 christos if (isc_refcount_decrement(&portentry->refs) == 1) { 623 1.1 christos ISC_LIST_UNLINK(disp->port_table[portentry->port % 624 1.1 christos DNS_DISPATCH_PORTTABLESIZE], 625 1.1 christos portentry, link); 626 1.1 christos isc_mem_put(disp->mgr->mctx, portentry, sizeof(*portentry)); 627 1.1 christos } 628 1.1 christos } 629 1.1 christos 630 1.1 christos /*% 631 1.1 christos * Find a dispsocket for socket address 'dest', and port number 'port'. 632 1.1 christos * Return NULL if no such entry exists. Requires qid->lock to be held. 633 1.1 christos */ 634 1.1 christos static dispsocket_t * 635 1.1 christos socket_search(dns_qid_t *qid, const isc_sockaddr_t *dest, in_port_t port, 636 1.1 christos unsigned int bucket) { 637 1.1 christos dispsocket_t *dispsock; 638 1.1 christos 639 1.1 christos REQUIRE(VALID_QID(qid)); 640 1.1 christos REQUIRE(bucket < qid->qid_nbuckets); 641 1.1 christos 642 1.1 christos dispsock = ISC_LIST_HEAD(qid->sock_table[bucket]); 643 1.1 christos 644 1.1 christos while (dispsock != NULL) { 645 1.1 christos if (dispsock->portentry != NULL && 646 1.1 christos dispsock->portentry->port == port && 647 1.1 christos isc_sockaddr_equal(dest, &dispsock->host)) 648 1.1 christos { 649 1.1 christos return (dispsock); 650 1.1 christos } 651 1.1 christos dispsock = ISC_LIST_NEXT(dispsock, blink); 652 1.1 christos } 653 1.1 christos 654 1.1 christos return (NULL); 655 1.1 christos } 656 1.1 christos 657 1.1 christos /*% 658 1.1 christos * Make a new socket for a single dispatch with a random port number. 659 1.1 christos * The caller must hold the disp->lock 660 1.1 christos */ 661 1.1 christos static isc_result_t 662 1.1 christos get_dispsocket(dns_dispatch_t *disp, const isc_sockaddr_t *dest, 663 1.1 christos isc_socketmgr_t *sockmgr, dispsocket_t **dispsockp, 664 1.1 christos in_port_t *portp) { 665 1.1 christos int i; 666 1.1 christos dns_dispatchmgr_t *mgr = disp->mgr; 667 1.1 christos isc_socket_t *sock = NULL; 668 1.1 christos isc_result_t result = ISC_R_FAILURE; 669 1.1 christos in_port_t port; 670 1.1 christos isc_sockaddr_t localaddr; 671 1.1 christos unsigned int bucket = 0; 672 1.1 christos dispsocket_t *dispsock; 673 1.1 christos unsigned int nports; 674 1.1 christos in_port_t *ports; 675 1.1 christos isc_socket_options_t bindoptions; 676 1.1 christos dispportentry_t *portentry = NULL; 677 1.1 christos dns_qid_t *qid; 678 1.1 christos 679 1.1 christos if (isc_sockaddr_pf(&disp->local) == AF_INET) { 680 1.1 christos nports = disp->mgr->nv4ports; 681 1.1 christos ports = disp->mgr->v4ports; 682 1.1 christos } else { 683 1.1 christos nports = disp->mgr->nv6ports; 684 1.1 christos ports = disp->mgr->v6ports; 685 1.1 christos } 686 1.1 christos if (nports == 0) { 687 1.1 christos return (ISC_R_ADDRNOTAVAIL); 688 1.1 christos } 689 1.1 christos 690 1.1 christos dispsock = ISC_LIST_HEAD(disp->inactivesockets); 691 1.1 christos if (dispsock != NULL) { 692 1.1 christos ISC_LIST_UNLINK(disp->inactivesockets, dispsock, link); 693 1.1 christos sock = dispsock->socket; 694 1.1 christos dispsock->socket = NULL; 695 1.1 christos } else { 696 1.1 christos dispsock = isc_mem_get(mgr->mctx, sizeof(*dispsock)); 697 1.1 christos 698 1.1 christos disp->nsockets++; 699 1.1 christos dispsock->socket = NULL; 700 1.1 christos dispsock->disp = disp; 701 1.1 christos dispsock->resp = NULL; 702 1.1 christos dispsock->portentry = NULL; 703 1.1 christos dispsock->task = NULL; 704 1.1 christos isc_task_attach(disp->task[isc_random_uniform(disp->ntasks)], 705 1.1 christos &dispsock->task); 706 1.1 christos ISC_LINK_INIT(dispsock, link); 707 1.1 christos ISC_LINK_INIT(dispsock, blink); 708 1.1 christos dispsock->magic = DISPSOCK_MAGIC; 709 1.1 christos } 710 1.1 christos 711 1.1 christos /* 712 1.1 christos * Pick up a random UDP port and open a new socket with it. Avoid 713 1.1 christos * choosing ports that share the same destination because it will be 714 1.1 christos * very likely to fail in bind(2) or connect(2). 715 1.1 christos */ 716 1.1 christos localaddr = disp->local; 717 1.1 christos qid = DNS_QID(disp); 718 1.1 christos 719 1.1 christos for (i = 0; i < 64; i++) { 720 1.1 christos port = ports[isc_random_uniform(nports)]; 721 1.1 christos isc_sockaddr_setport(&localaddr, port); 722 1.1 christos 723 1.1 christos LOCK(&qid->lock); 724 1.1 christos bucket = dns_hash(qid, dest, 0, port); 725 1.1 christos if (socket_search(qid, dest, port, bucket) != NULL) { 726 1.1 christos UNLOCK(&qid->lock); 727 1.1 christos continue; 728 1.1 christos } 729 1.1 christos UNLOCK(&qid->lock); 730 1.1 christos bindoptions = 0; 731 1.1 christos portentry = port_search(disp, port); 732 1.1 christos 733 1.1 christos if (portentry != NULL) { 734 1.1 christos bindoptions |= ISC_SOCKET_REUSEADDRESS; 735 1.1 christos } 736 1.1 christos result = open_socket(sockmgr, &localaddr, bindoptions, &sock, 737 1.1 christos NULL, false); 738 1.1 christos if (result == ISC_R_SUCCESS) { 739 1.1 christos if (portentry == NULL) { 740 1.1 christos portentry = new_portentry(disp, port); 741 1.1 christos if (portentry == NULL) { 742 1.1 christos result = ISC_R_NOMEMORY; 743 1.1 christos break; 744 1.1 christos } 745 1.1 christos } else { 746 1.1 christos isc_refcount_increment(&portentry->refs); 747 1.1 christos } 748 1.1 christos break; 749 1.1 christos } else if (result == ISC_R_NOPERM) { 750 1.1 christos char buf[ISC_SOCKADDR_FORMATSIZE]; 751 1.1 christos isc_sockaddr_format(&localaddr, buf, sizeof(buf)); 752 1.1 christos dispatch_log(disp, ISC_LOG_WARNING, 753 1.1 christos "open_socket(%s) -> %s: continuing", buf, 754 1.1 christos isc_result_totext(result)); 755 1.1 christos } else if (result != ISC_R_ADDRINUSE) { 756 1.1 christos break; 757 1.1 christos } 758 1.1 christos } 759 1.1 christos 760 1.1 christos if (result == ISC_R_SUCCESS) { 761 1.1 christos dispsock->socket = sock; 762 1.1 christos dispsock->host = *dest; 763 1.1 christos dispsock->bucket = bucket; 764 1.1 christos LOCK(&qid->lock); 765 1.1 christos dispsock->portentry = portentry; 766 1.1 christos ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink); 767 1.1 christos UNLOCK(&qid->lock); 768 1.1 christos *dispsockp = dispsock; 769 1.1 christos *portp = port; 770 1.1 christos } else { 771 1.1 christos /* 772 1.1 christos * We could keep it in the inactive list, but since this should 773 1.1 christos * be an exceptional case and might be resource shortage, we'd 774 1.1 christos * rather destroy it. 775 1.1 christos */ 776 1.1 christos if (sock != NULL) { 777 1.1 christos isc_socket_detach(&sock); 778 1.1 christos } 779 1.1 christos destroy_dispsocket(disp, &dispsock); 780 1.1 christos } 781 1.1 christos 782 1.1 christos return (result); 783 1.1 christos } 784 1.1 christos 785 1.1 christos /*% 786 1.1 christos * Destroy a dedicated dispatch socket. 787 1.1 christos */ 788 1.1 christos static void 789 1.1 christos destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) { 790 1.1 christos dispsocket_t *dispsock; 791 1.1 christos dns_qid_t *qid = DNS_QID(disp); 792 1.1 christos 793 1.1 christos /* 794 1.1 christos * The dispatch must be locked. 795 1.1 christos */ 796 1.1 christos 797 1.1 christos REQUIRE(dispsockp != NULL && *dispsockp != NULL); 798 1.1 christos dispsock = *dispsockp; 799 1.1 christos *dispsockp = NULL; 800 1.1 christos REQUIRE(!ISC_LINK_LINKED(dispsock, link)); 801 1.1 christos 802 1.1 christos disp->nsockets--; 803 1.1 christos dispsock->magic = 0; 804 1.1 christos if (dispsock->portentry != NULL) { 805 1.1 christos /* socket_search() tests and dereferences portentry. */ 806 1.1 christos LOCK(&qid->lock); 807 1.1 christos deref_portentry(disp, &dispsock->portentry); 808 1.1 christos UNLOCK(&qid->lock); 809 1.1 christos } 810 1.1 christos if (dispsock->socket != NULL) { 811 1.1 christos isc_socket_detach(&dispsock->socket); 812 1.1 christos } 813 1.1 christos if (ISC_LINK_LINKED(dispsock, blink)) { 814 1.1 christos LOCK(&qid->lock); 815 1.1 christos ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, 816 1.1 christos blink); 817 1.1 christos UNLOCK(&qid->lock); 818 1.1 christos } 819 1.1 christos if (dispsock->task != NULL) { 820 1.1 christos isc_task_detach(&dispsock->task); 821 1.1 christos } 822 1.1 christos isc_mem_put(disp->mgr->mctx, dispsock, sizeof(*dispsock)); 823 1.1 christos } 824 1.1 christos 825 1.1 christos /*% 826 1.1 christos * Deactivate a dedicated dispatch socket. Move it to the inactive list for 827 1.1 christos * future reuse unless the total number of sockets are exceeding the maximum. 828 1.1 christos */ 829 1.1 christos static void 830 1.1 christos deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) { 831 1.1 christos isc_result_t result; 832 1.1 christos dns_qid_t *qid = DNS_QID(disp); 833 1.1 christos 834 1.1 christos /* 835 1.1 christos * The dispatch must be locked. 836 1.1 christos */ 837 1.1 christos ISC_LIST_UNLINK(disp->activesockets, dispsock, link); 838 1.1 christos if (dispsock->resp != NULL) { 839 1.1 christos INSIST(dispsock->resp->dispsocket == dispsock); 840 1.1 christos dispsock->resp->dispsocket = NULL; 841 1.1 christos } 842 1.1 christos 843 1.1 christos INSIST(dispsock->portentry != NULL); 844 1.1 christos /* socket_search() tests and dereferences portentry. */ 845 1.1 christos LOCK(&qid->lock); 846 1.1 christos deref_portentry(disp, &dispsock->portentry); 847 1.1 christos UNLOCK(&qid->lock); 848 1.1 christos 849 1.1 christos if (disp->nsockets > DNS_DISPATCH_POOLSOCKS) { 850 1.1 christos destroy_dispsocket(disp, &dispsock); 851 1.1 christos } else { 852 1.1 christos result = isc_socket_close(dispsock->socket); 853 1.1 christos 854 1.1 christos LOCK(&qid->lock); 855 1.1 christos ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock, 856 1.1 christos blink); 857 1.1 christos UNLOCK(&qid->lock); 858 1.1 christos 859 1.1 christos if (result == ISC_R_SUCCESS) { 860 1.1 christos ISC_LIST_APPEND(disp->inactivesockets, dispsock, link); 861 1.1 christos } else { 862 1.1 christos /* 863 1.1 christos * If the underlying system does not allow this 864 1.1 christos * optimization, destroy this temporary structure (and 865 1.1 christos * create a new one for a new transaction). 866 1.1 christos */ 867 1.1 christos INSIST(result == ISC_R_NOTIMPLEMENTED); 868 1.1 christos destroy_dispsocket(disp, &dispsock); 869 1.1 christos } 870 1.1 christos } 871 1.1 christos } 872 1.1 christos 873 1.1 christos /* 874 1.1 christos * Find an entry for query ID 'id', socket address 'dest', and port number 875 1.1 christos * 'port'. 876 1.1 christos * Return NULL if no such entry exists. 877 1.1 christos */ 878 1.1 christos static dns_dispentry_t * 879 1.1 christos entry_search(dns_qid_t *qid, const isc_sockaddr_t *dest, dns_messageid_t id, 880 1.1 christos in_port_t port, unsigned int bucket) { 881 1.1 christos dns_dispentry_t *res; 882 1.1 christos 883 1.1 christos REQUIRE(VALID_QID(qid)); 884 1.1 christos REQUIRE(bucket < qid->qid_nbuckets); 885 1.1 christos 886 1.1 christos res = ISC_LIST_HEAD(qid->qid_table[bucket]); 887 1.1 christos 888 1.1 christos while (res != NULL) { 889 1.1 christos if (res->id == id && isc_sockaddr_equal(dest, &res->host) && 890 1.1 christos res->port == port) 891 1.1 christos { 892 1.1 christos return (res); 893 1.1 christos } 894 1.1 christos res = ISC_LIST_NEXT(res, link); 895 1.1 christos } 896 1.1 christos 897 1.1 christos return (NULL); 898 1.1 christos } 899 1.1 christos 900 1.1 christos static void 901 1.1 christos free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len) { 902 1.1 christos unsigned int buffersize; 903 1.1 christos INSIST(buf != NULL && len != 0); 904 1.1 christos 905 1.1 christos switch (disp->socktype) { 906 1.1 christos case isc_sockettype_tcp: 907 1.1 christos INSIST(disp->tcpbuffers > 0); 908 1.1 christos disp->tcpbuffers--; 909 1.1 christos isc_mem_put(disp->mgr->mctx, buf, len); 910 1.1 christos break; 911 1.1 christos case isc_sockettype_udp: 912 1.1 christos LOCK(&disp->mgr->buffer_lock); 913 1.1 christos INSIST(disp->mgr->buffers > 0); 914 1.1 christos INSIST(len == disp->mgr->buffersize); 915 1.1 christos disp->mgr->buffers--; 916 1.1 christos buffersize = disp->mgr->buffersize; 917 1.1 christos UNLOCK(&disp->mgr->buffer_lock); 918 1.1 christos isc_mem_put(disp->mgr->mctx, buf, buffersize); 919 1.1 christos break; 920 1.1 christos default: 921 1.1 christos UNREACHABLE(); 922 1.1 christos } 923 1.1 christos } 924 1.1 christos 925 1.1 christos static void * 926 1.1 christos allocate_udp_buffer(dns_dispatch_t *disp) { 927 1.1 christos unsigned int buffersize; 928 1.1 christos 929 1.1 christos LOCK(&disp->mgr->buffer_lock); 930 1.1 christos if (disp->mgr->buffers >= disp->mgr->maxbuffers) { 931 1.1 christos UNLOCK(&disp->mgr->buffer_lock); 932 1.1 christos return (NULL); 933 1.1 christos } 934 1.1 christos buffersize = disp->mgr->buffersize; 935 1.1 christos disp->mgr->buffers++; 936 1.1 christos UNLOCK(&disp->mgr->buffer_lock); 937 1.1 christos 938 1.1 christos return (isc_mem_get(disp->mgr->mctx, buffersize)); 939 1.1 christos } 940 1.1 christos 941 1.1 christos static void 942 1.1 christos free_sevent(isc_event_t *ev) { 943 1.1 christos isc_mem_t *pool = ev->ev_destroy_arg; 944 1.1 christos isc_socketevent_t *sev = (isc_socketevent_t *)ev; 945 1.1 christos isc_mem_put(pool, sev, sizeof(*sev)); 946 1.1 christos } 947 1.1 christos 948 1.1 christos static isc_socketevent_t * 949 1.1 christos allocate_sevent(dns_dispatch_t *disp, isc_socket_t *sock, isc_eventtype_t type, 950 1.1 christos isc_taskaction_t action, const void *arg) { 951 1.1 christos isc_socketevent_t *ev; 952 1.1 christos void *deconst_arg; 953 1.1 christos 954 1.1 christos ev = isc_mem_get(disp->sepool, sizeof(*ev)); 955 1.1 christos DE_CONST(arg, deconst_arg); 956 1.1 christos ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, type, action, deconst_arg, 957 1.1 christos sock, free_sevent, disp->sepool); 958 1.1 christos ev->result = ISC_R_UNSET; 959 1.1 christos ISC_LINK_INIT(ev, ev_link); 960 1.1 christos ev->region.base = NULL; 961 1.1 christos ev->n = 0; 962 1.1 christos ev->offset = 0; 963 1.1 christos ev->attributes = 0; 964 1.1 christos 965 1.1 christos return (ev); 966 1.1 christos } 967 1.1 christos 968 1.1 christos static void 969 1.1 christos free_devent(dns_dispatch_t *disp, dns_dispatchevent_t *ev) { 970 1.1 christos if (disp->failsafe_ev == ev) { 971 1.1 christos INSIST(disp->shutdown_out == 1); 972 1.1 christos disp->shutdown_out = 0; 973 1.1 christos 974 1.1 christos return; 975 1.1 christos } 976 1.1 christos 977 1.1 christos isc_refcount_decrement(&disp->mgr->irefs); 978 1.1 christos isc_mem_put(disp->mgr->mctx, ev, sizeof(*ev)); 979 1.1 christos } 980 1.1 christos 981 1.1 christos static dns_dispatchevent_t * 982 1.1 christos allocate_devent(dns_dispatch_t *disp) { 983 1.1 christos dns_dispatchevent_t *ev; 984 1.1 christos 985 1.1 christos ev = isc_mem_get(disp->mgr->mctx, sizeof(*ev)); 986 1.1 christos isc_refcount_increment0(&disp->mgr->irefs); 987 1.1 christos ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, 0, NULL, NULL, NULL, NULL, 988 1.1 christos NULL); 989 1.1 christos 990 1.1 christos return (ev); 991 1.1 christos } 992 1.1 christos 993 1.1 christos static void 994 1.1 christos udp_exrecv(isc_task_t *task, isc_event_t *ev) { 995 1.1 christos dispsocket_t *dispsock = ev->ev_arg; 996 1.1 christos 997 1.1 christos UNUSED(task); 998 1.1 christos 999 1.1 christos REQUIRE(VALID_DISPSOCK(dispsock)); 1000 1.1 christos udp_recv(ev, dispsock->disp, dispsock); 1001 1.1 christos } 1002 1.1 christos 1003 1.1 christos static void 1004 1.1 christos udp_shrecv(isc_task_t *task, isc_event_t *ev) { 1005 1.1 christos dns_dispatch_t *disp = ev->ev_arg; 1006 1.1 christos 1007 1.1 christos UNUSED(task); 1008 1.1 christos 1009 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 1010 1.1 christos udp_recv(ev, disp, NULL); 1011 1.1 christos } 1012 1.1 christos 1013 1.1 christos /* 1014 1.1 christos * General flow: 1015 1.1 christos * 1016 1.1 christos * If I/O result == CANCELED or error, free the buffer. 1017 1.1 christos * 1018 1.1 christos * If query, free the buffer, restart. 1019 1.1 christos * 1020 1.1 christos * If response: 1021 1.1 christos * Allocate event, fill in details. 1022 1.1 christos * If cannot allocate, free buffer, restart. 1023 1.1 christos * find target. If not found, free buffer, restart. 1024 1.1 christos * if event queue is not empty, queue. else, send. 1025 1.1 christos * restart. 1026 1.1 christos */ 1027 1.1 christos static void 1028 1.1 christos udp_recv(isc_event_t *ev_in, dns_dispatch_t *disp, dispsocket_t *dispsock) { 1029 1.1 christos isc_socketevent_t *ev = (isc_socketevent_t *)ev_in; 1030 1.1 christos dns_messageid_t id; 1031 1.1 christos isc_result_t dres; 1032 1.1 christos isc_buffer_t source; 1033 1.1 christos unsigned int flags; 1034 1.1 christos dns_dispentry_t *resp = NULL; 1035 1.1 christos dns_dispatchevent_t *rev; 1036 1.1 christos unsigned int bucket; 1037 1.1 christos bool killit; 1038 1.1 christos bool queue_response; 1039 1.1 christos dns_dispatchmgr_t *mgr; 1040 1.1 christos dns_qid_t *qid; 1041 1.1 christos isc_netaddr_t netaddr; 1042 1.1 christos int match; 1043 1.1 christos int result; 1044 1.1 christos bool qidlocked = false; 1045 1.1 christos 1046 1.1 christos LOCK(&disp->lock); 1047 1.1 christos 1048 1.1 christos mgr = disp->mgr; 1049 1.1 christos qid = mgr->qid; 1050 1.1 christos 1051 1.1 christos LOCK(&disp->mgr->buffer_lock); 1052 1.1 christos dispatch_log(disp, LVL(90), 1053 1.1 christos "got packet: requests %d, buffers %d, recvs %d", 1054 1.1 christos disp->requests, disp->mgr->buffers, disp->recv_pending); 1055 1.1 christos UNLOCK(&disp->mgr->buffer_lock); 1056 1.1 christos 1057 1.1 christos if (dispsock == NULL && ev->ev_type == ISC_SOCKEVENT_RECVDONE) { 1058 1.1 christos /* 1059 1.1 christos * Unless the receive event was imported from a listening 1060 1.1 christos * interface, in which case the event type is 1061 1.1 christos * DNS_EVENT_IMPORTRECVDONE, receive operation must be pending. 1062 1.1 christos */ 1063 1.1 christos INSIST(disp->recv_pending != 0); 1064 1.1 christos disp->recv_pending = 0; 1065 1.1 christos } 1066 1.1 christos 1067 1.1 christos if (dispsock != NULL && 1068 1.1 christos (ev->result == ISC_R_CANCELED || dispsock->resp == NULL)) 1069 1.1 christos { 1070 1.1 christos /* 1071 1.1 christos * dispsock->resp can be NULL if this transaction was canceled 1072 1.1 christos * just after receiving a response. Since this socket is 1073 1.1 christos * exclusively used and there should be at most one receive 1074 1.1 christos * event the canceled event should have been no effect. So 1075 1.1 christos * we can (and should) deactivate the socket right now. 1076 1.1 christos */ 1077 1.1 christos deactivate_dispsocket(disp, dispsock); 1078 1.1 christos dispsock = NULL; 1079 1.1 christos } 1080 1.1 christos 1081 1.1 christos if (disp->shutting_down) { 1082 1.1 christos /* 1083 1.1 christos * This dispatcher is shutting down. 1084 1.1 christos */ 1085 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1086 1.1 christos 1087 1.1 christos isc_event_free(&ev_in); 1088 1.1 christos ev = NULL; 1089 1.1 christos 1090 1.1 christos killit = destroy_disp_ok(disp); 1091 1.1 christos UNLOCK(&disp->lock); 1092 1.1 christos if (killit) { 1093 1.1 christos isc_task_send(disp->task[0], &disp->ctlevent); 1094 1.1 christos } 1095 1.1 christos 1096 1.1 christos return; 1097 1.1 christos } 1098 1.1 christos 1099 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 1100 1.1 christos if (dispsock != NULL) { 1101 1.1 christos resp = dispsock->resp; 1102 1.1 christos id = resp->id; 1103 1.1 christos if (ev->result != ISC_R_SUCCESS) { 1104 1.1 christos /* 1105 1.1 christos * This is most likely a network error on a 1106 1.1 christos * connected socket. It makes no sense to 1107 1.1 christos * check the address or parse the packet, but it 1108 1.1 christos * will help to return the error to the caller. 1109 1.1 christos */ 1110 1.1 christos goto sendresponse; 1111 1.1 christos } 1112 1.1 christos } else { 1113 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1114 1.1 christos 1115 1.1 christos isc_event_free(&ev_in); 1116 1.1 christos UNLOCK(&disp->lock); 1117 1.1 christos return; 1118 1.1 christos } 1119 1.1 christos } else if (ev->result != ISC_R_SUCCESS) { 1120 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1121 1.1 christos 1122 1.1 christos if (ev->result != ISC_R_CANCELED) { 1123 1.1 christos dispatch_log(disp, ISC_LOG_ERROR, 1124 1.1 christos "odd socket result in udp_recv(): %s", 1125 1.1 christos isc_result_totext(ev->result)); 1126 1.1 christos } 1127 1.1 christos 1128 1.1 christos isc_event_free(&ev_in); 1129 1.1 christos UNLOCK(&disp->lock); 1130 1.1 christos return; 1131 1.1 christos } 1132 1.1 christos 1133 1.1 christos /* 1134 1.1 christos * If this is from a blackholed address, drop it. 1135 1.1 christos */ 1136 1.1 christos isc_netaddr_fromsockaddr(&netaddr, &ev->address); 1137 1.1 christos if (disp->mgr->blackhole != NULL && 1138 1.1 christos dns_acl_match(&netaddr, NULL, disp->mgr->blackhole, NULL, &match, 1139 1.1 christos NULL) == ISC_R_SUCCESS && 1140 1.1 christos match > 0) 1141 1.1 christos { 1142 1.1 christos if (isc_log_wouldlog(dns_lctx, LVL(10))) { 1143 1.1 christos char netaddrstr[ISC_NETADDR_FORMATSIZE]; 1144 1.1 christos isc_netaddr_format(&netaddr, netaddrstr, 1145 1.1 christos sizeof(netaddrstr)); 1146 1.1 christos dispatch_log(disp, LVL(10), "blackholed packet from %s", 1147 1.1 christos netaddrstr); 1148 1.1 christos } 1149 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1150 1.1 christos goto restart; 1151 1.1 christos } 1152 1.1 christos 1153 1.1 christos /* 1154 1.1 christos * Peek into the buffer to see what we can see. 1155 1.1 christos */ 1156 1.1 christos isc_buffer_init(&source, ev->region.base, ev->region.length); 1157 1.1 christos isc_buffer_add(&source, ev->n); 1158 1.1 christos dres = dns_message_peekheader(&source, &id, &flags); 1159 1.1 christos if (dres != ISC_R_SUCCESS) { 1160 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1161 1.1 christos dispatch_log(disp, LVL(10), "got garbage packet"); 1162 1.1 christos goto restart; 1163 1.1 christos } 1164 1.1 christos 1165 1.1 christos dispatch_log(disp, LVL(92), 1166 1.1 christos "got valid DNS message header, /QR %c, id %u", 1167 1.1 christos (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id); 1168 1.1 christos 1169 1.1 christos /* 1170 1.1 christos * Look at flags. If query, drop it. If response, 1171 1.1 christos * look to see where it goes. 1172 1.1 christos */ 1173 1.1 christos if ((flags & DNS_MESSAGEFLAG_QR) == 0) { 1174 1.1 christos /* query */ 1175 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1176 1.1 christos goto restart; 1177 1.1 christos } 1178 1.1 christos 1179 1.1 christos /* 1180 1.1 christos * Search for the corresponding response. If we are using an exclusive 1181 1.1 christos * socket, we've already identified it and we can skip the search; but 1182 1.1 christos * the ID and the address must match the expected ones. 1183 1.1 christos */ 1184 1.1 christos if (resp == NULL) { 1185 1.1 christos bucket = dns_hash(qid, &ev->address, id, disp->localport); 1186 1.1 christos LOCK(&qid->lock); 1187 1.1 christos qidlocked = true; 1188 1.1 christos resp = entry_search(qid, &ev->address, id, disp->localport, 1189 1.1 christos bucket); 1190 1.1 christos dispatch_log(disp, LVL(90), 1191 1.1 christos "search for response in bucket %d: %s", bucket, 1192 1.1 christos (resp == NULL ? "not found" : "found")); 1193 1.1 christos 1194 1.1 christos } else if (resp->id != id || 1195 1.1 christos !isc_sockaddr_equal(&ev->address, &resp->host)) 1196 1.1 christos { 1197 1.1 christos dispatch_log(disp, LVL(90), 1198 1.1 christos "response to an exclusive socket doesn't match"); 1199 1.1 christos inc_stats(mgr, dns_resstatscounter_mismatch); 1200 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1201 1.1 christos goto unlock; 1202 1.1 christos } 1203 1.1 christos 1204 1.1 christos if (resp == NULL) { 1205 1.1 christos inc_stats(mgr, dns_resstatscounter_mismatch); 1206 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1207 1.1 christos goto unlock; 1208 1.1 christos } 1209 1.1 christos 1210 1.1 christos /* 1211 1.1 christos * Now that we have the original dispatch the query was sent 1212 1.1 christos * from check that the address and port the response was 1213 1.1 christos * sent to make sense. 1214 1.1 christos */ 1215 1.1 christos if (disp != resp->disp) { 1216 1.1 christos isc_sockaddr_t a1; 1217 1.1 christos isc_sockaddr_t a2; 1218 1.1 christos 1219 1.1 christos /* 1220 1.1 christos * Check that the socket types and ports match. 1221 1.1 christos */ 1222 1.1 christos if (disp->socktype != resp->disp->socktype || 1223 1.1 christos isc_sockaddr_getport(&disp->local) != 1224 1.1 christos isc_sockaddr_getport(&resp->disp->local)) 1225 1.1 christos { 1226 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1227 1.1 christos goto unlock; 1228 1.1 christos } 1229 1.1 christos 1230 1.1 christos /* 1231 1.1 christos * If each dispatch is bound to a different address 1232 1.1 christos * then fail. 1233 1.1 christos * 1234 1.1 christos * Note under Linux a packet can be sent out via IPv4 socket 1235 1.1 christos * and the response be received via a IPv6 socket. 1236 1.1 christos * 1237 1.1 christos * Requests sent out via IPv6 should always come back in 1238 1.1 christos * via IPv6. 1239 1.1 christos */ 1240 1.1 christos if (isc_sockaddr_pf(&resp->disp->local) == PF_INET6 && 1241 1.1 christos isc_sockaddr_pf(&disp->local) != PF_INET6) 1242 1.1 christos { 1243 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1244 1.1 christos goto unlock; 1245 1.1 christos } 1246 1.1 christos isc_sockaddr_anyofpf(&a1, isc_sockaddr_pf(&resp->disp->local)); 1247 1.1 christos isc_sockaddr_anyofpf(&a2, isc_sockaddr_pf(&disp->local)); 1248 1.1 christos if (!isc_sockaddr_eqaddr(&disp->local, &resp->disp->local) && 1249 1.1 christos !isc_sockaddr_eqaddr(&a1, &resp->disp->local) && 1250 1.1 christos !isc_sockaddr_eqaddr(&a2, &disp->local)) 1251 1.1 christos { 1252 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1253 1.1 christos goto unlock; 1254 1.1 christos } 1255 1.1 christos } 1256 1.1 christos 1257 1.1 christos sendresponse: 1258 1.1 christos queue_response = resp->item_out; 1259 1.1 christos rev = allocate_devent(resp->disp); 1260 1.1 christos if (rev == NULL) { 1261 1.1 christos free_buffer(disp, ev->region.base, ev->region.length); 1262 1.1 christos goto unlock; 1263 1.1 christos } 1264 1.1 christos 1265 1.1 christos /* 1266 1.1 christos * At this point, rev contains the event we want to fill in, and 1267 1.1 christos * resp contains the information on the place to send it to. 1268 1.1 christos * Send the event off. 1269 1.1 christos */ 1270 1.1 christos isc_buffer_init(&rev->buffer, ev->region.base, ev->region.length); 1271 1.1 christos isc_buffer_add(&rev->buffer, ev->n); 1272 1.1 christos rev->result = ev->result; 1273 1.1 christos rev->id = id; 1274 1.1 christos rev->addr = ev->address; 1275 1.1 christos rev->pktinfo = ev->pktinfo; 1276 1.1 christos rev->attributes = ev->attributes; 1277 1.1 christos if (queue_response) { 1278 1.1 christos ISC_LIST_APPEND(resp->items, rev, ev_link); 1279 1.1 christos } else { 1280 1.1 christos ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, 1281 1.1 christos resp->action, resp->arg, resp, NULL, NULL); 1282 1.1 christos request_log(disp, resp, LVL(90), 1283 1.1 christos "[a] Sent event %p buffer %p len %d to task %p", 1284 1.1 christos rev, rev->buffer.base, rev->buffer.length, 1285 1.1 christos resp->task); 1286 1.1 christos resp->item_out = true; 1287 1.1 christos isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); 1288 1.1 christos } 1289 1.1 christos unlock: 1290 1.1 christos if (qidlocked) { 1291 1.1 christos UNLOCK(&qid->lock); 1292 1.1 christos } 1293 1.1 christos 1294 1.1 christos /* 1295 1.1 christos * Restart recv() to get the next packet. 1296 1.1 christos */ 1297 1.1 christos restart: 1298 1.1 christos result = startrecv(disp, dispsock); 1299 1.1 christos if (result != ISC_R_SUCCESS && dispsock != NULL) { 1300 1.1 christos /* 1301 1.1 christos * XXX: wired. There seems to be no recovery process other than 1302 1.1 christos * deactivate this socket anyway (since we cannot start 1303 1.1 christos * receiving, we won't be able to receive a cancel event 1304 1.1 christos * from the user). 1305 1.1 christos */ 1306 1.1 christos deactivate_dispsocket(disp, dispsock); 1307 1.1 christos } 1308 1.1 christos isc_event_free(&ev_in); 1309 1.1 christos UNLOCK(&disp->lock); 1310 1.1 christos } 1311 1.1 christos 1312 1.1 christos /* 1313 1.1 christos * General flow: 1314 1.1 christos * 1315 1.1 christos * If I/O result == CANCELED, EOF, or error, notify everyone as the 1316 1.1 christos * various queues drain. 1317 1.1 christos * 1318 1.1 christos * If query, restart. 1319 1.1 christos * 1320 1.1 christos * If response: 1321 1.1 christos * Allocate event, fill in details. 1322 1.1 christos * If cannot allocate, restart. 1323 1.1 christos * find target. If not found, restart. 1324 1.1 christos * if event queue is not empty, queue. else, send. 1325 1.1 christos * restart. 1326 1.1 christos */ 1327 1.1 christos static void 1328 1.1 christos tcp_recv(isc_task_t *task, isc_event_t *ev_in) { 1329 1.1 christos dns_dispatch_t *disp = ev_in->ev_arg; 1330 1.1 christos dns_tcpmsg_t *tcpmsg = &disp->tcpmsg; 1331 1.1 christos dns_messageid_t id; 1332 1.1 christos isc_result_t dres; 1333 1.1 christos unsigned int flags; 1334 1.1 christos dns_dispentry_t *resp; 1335 1.1 christos dns_dispatchevent_t *rev; 1336 1.1 christos unsigned int bucket; 1337 1.1 christos bool killit; 1338 1.1 christos bool queue_response; 1339 1.1 christos dns_qid_t *qid; 1340 1.1 christos int level; 1341 1.1 christos char buf[ISC_SOCKADDR_FORMATSIZE]; 1342 1.1 christos 1343 1.1 christos UNUSED(task); 1344 1.1 christos 1345 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 1346 1.1 christos 1347 1.1 christos qid = disp->qid; 1348 1.1 christos 1349 1.1 christos LOCK(&disp->lock); 1350 1.1 christos 1351 1.1 christos dispatch_log(disp, LVL(90), 1352 1.1 christos "got TCP packet: requests %d, buffers %d, recvs %d", 1353 1.1 christos disp->requests, disp->tcpbuffers, disp->recv_pending); 1354 1.1 christos 1355 1.1 christos INSIST(disp->recv_pending != 0); 1356 1.1 christos disp->recv_pending = 0; 1357 1.1 christos 1358 1.1 christos if (disp->refcount == 0) { 1359 1.1 christos /* 1360 1.1 christos * This dispatcher is shutting down. Force cancellation. 1361 1.1 christos */ 1362 1.1 christos tcpmsg->result = ISC_R_CANCELED; 1363 1.1 christos } 1364 1.1 christos 1365 1.1 christos if (tcpmsg->result != ISC_R_SUCCESS) { 1366 1.1 christos switch (tcpmsg->result) { 1367 1.1 christos case ISC_R_CANCELED: 1368 1.1 christos break; 1369 1.1 christos 1370 1.1 christos case ISC_R_EOF: 1371 1.1 christos dispatch_log(disp, LVL(90), "shutting down on EOF"); 1372 1.1 christos do_cancel(disp); 1373 1.1 christos break; 1374 1.1 christos 1375 1.1 christos case ISC_R_CONNECTIONRESET: 1376 1.1 christos level = ISC_LOG_INFO; 1377 1.1 christos goto logit; 1378 1.1 christos 1379 1.1 christos default: 1380 1.1 christos level = ISC_LOG_ERROR; 1381 1.1 christos logit: 1382 1.1 christos isc_sockaddr_format(&tcpmsg->address, buf, sizeof(buf)); 1383 1.1 christos dispatch_log(disp, level, 1384 1.1 christos "shutting down due to TCP " 1385 1.1 christos "receive error: %s: %s", 1386 1.1 christos buf, isc_result_totext(tcpmsg->result)); 1387 1.1 christos do_cancel(disp); 1388 1.1 christos break; 1389 1.1 christos } 1390 1.1 christos 1391 1.1 christos /* 1392 1.1 christos * The event is statically allocated in the tcpmsg 1393 1.1 christos * structure, and destroy_disp() frees the tcpmsg, so we must 1394 1.1 christos * free the event *before* calling destroy_disp(). 1395 1.1 christos */ 1396 1.1 christos isc_event_free(&ev_in); 1397 1.1 christos 1398 1.1 christos disp->shutting_down = 1; 1399 1.1 christos disp->shutdown_why = tcpmsg->result; 1400 1.1 christos 1401 1.1 christos /* 1402 1.1 christos * If the recv() was canceled pass the word on. 1403 1.1 christos */ 1404 1.1 christos killit = destroy_disp_ok(disp); 1405 1.1 christos UNLOCK(&disp->lock); 1406 1.1 christos if (killit) { 1407 1.1 christos isc_task_send(disp->task[0], &disp->ctlevent); 1408 1.1 christos } 1409 1.1 christos return; 1410 1.1 christos } 1411 1.1 christos 1412 1.1 christos dispatch_log(disp, LVL(90), "result %d, length == %d, addr = %p", 1413 1.1 christos tcpmsg->result, tcpmsg->buffer.length, 1414 1.1 christos tcpmsg->buffer.base); 1415 1.1 christos 1416 1.1 christos /* 1417 1.1 christos * Peek into the buffer to see what we can see. 1418 1.1 christos */ 1419 1.1 christos dres = dns_message_peekheader(&tcpmsg->buffer, &id, &flags); 1420 1.1 christos if (dres != ISC_R_SUCCESS) { 1421 1.1 christos dispatch_log(disp, LVL(10), "got garbage packet"); 1422 1.1 christos goto restart; 1423 1.1 christos } 1424 1.1 christos 1425 1.1 christos dispatch_log(disp, LVL(92), 1426 1.1 christos "got valid DNS message header, /QR %c, id %u", 1427 1.1 christos (((flags & DNS_MESSAGEFLAG_QR) != 0) ? '1' : '0'), id); 1428 1.1 christos 1429 1.1 christos /* 1430 1.1 christos * Allocate an event to send to the query or response client, and 1431 1.1 christos * allocate a new buffer for our use. 1432 1.1 christos */ 1433 1.1 christos 1434 1.1 christos /* 1435 1.1 christos * Look at flags. If query, drop it. If response, 1436 1.1 christos * look to see where it goes. 1437 1.1 christos */ 1438 1.1 christos if ((flags & DNS_MESSAGEFLAG_QR) == 0) { 1439 1.1 christos /* 1440 1.1 christos * Query. 1441 1.1 christos */ 1442 1.1 christos goto restart; 1443 1.1 christos } 1444 1.1 christos 1445 1.1 christos /* 1446 1.1 christos * Response. 1447 1.1 christos */ 1448 1.1 christos bucket = dns_hash(qid, &tcpmsg->address, id, disp->localport); 1449 1.1 christos LOCK(&qid->lock); 1450 1.1 christos resp = entry_search(qid, &tcpmsg->address, id, disp->localport, bucket); 1451 1.1 christos dispatch_log(disp, LVL(90), "search for response in bucket %d: %s", 1452 1.1 christos bucket, (resp == NULL ? "not found" : "found")); 1453 1.1 christos 1454 1.1 christos if (resp == NULL) { 1455 1.1 christos goto unlock; 1456 1.1 christos } 1457 1.1 christos queue_response = resp->item_out; 1458 1.1 christos rev = allocate_devent(disp); 1459 1.1 christos if (rev == NULL) { 1460 1.1 christos goto unlock; 1461 1.1 christos } 1462 1.1 christos 1463 1.1 christos /* 1464 1.1 christos * At this point, rev contains the event we want to fill in, and 1465 1.1 christos * resp contains the information on the place to send it to. 1466 1.1 christos * Send the event off. 1467 1.1 christos */ 1468 1.1 christos dns_tcpmsg_keepbuffer(tcpmsg, &rev->buffer); 1469 1.1 christos disp->tcpbuffers++; 1470 1.1 christos rev->result = ISC_R_SUCCESS; 1471 1.1 christos rev->id = id; 1472 1.1 christos rev->addr = tcpmsg->address; 1473 1.1 christos if (queue_response) { 1474 1.1 christos ISC_LIST_APPEND(resp->items, rev, ev_link); 1475 1.1 christos } else { 1476 1.1 christos ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, DNS_EVENT_DISPATCH, 1477 1.1 christos resp->action, resp->arg, resp, NULL, NULL); 1478 1.1 christos request_log(disp, resp, LVL(90), 1479 1.1 christos "[b] Sent event %p buffer %p len %d to task %p", 1480 1.1 christos rev, rev->buffer.base, rev->buffer.length, 1481 1.1 christos resp->task); 1482 1.1 christos resp->item_out = true; 1483 1.1 christos isc_task_send(resp->task, ISC_EVENT_PTR(&rev)); 1484 1.1 christos } 1485 1.1 christos unlock: 1486 1.1 christos UNLOCK(&qid->lock); 1487 1.1 christos 1488 1.1 christos /* 1489 1.1 christos * Restart recv() to get the next packet. 1490 1.1 christos */ 1491 1.1 christos restart: 1492 1.1 christos (void)startrecv(disp, NULL); 1493 1.1 christos 1494 1.1 christos isc_event_free(&ev_in); 1495 1.1 christos UNLOCK(&disp->lock); 1496 1.1 christos } 1497 1.1 christos 1498 1.1 christos /* 1499 1.1 christos * disp must be locked. 1500 1.1 christos */ 1501 1.1 christos static isc_result_t 1502 1.1 christos startrecv(dns_dispatch_t *disp, dispsocket_t *dispsock) { 1503 1.1 christos isc_result_t res; 1504 1.1 christos isc_region_t region; 1505 1.1 christos isc_socket_t *sock; 1506 1.1 christos 1507 1.1 christos if (disp->shutting_down == 1) { 1508 1.1 christos return (ISC_R_SUCCESS); 1509 1.1 christos } 1510 1.1 christos 1511 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) { 1512 1.1 christos return (ISC_R_SUCCESS); 1513 1.1 christos } 1514 1.1 christos 1515 1.1 christos if (disp->recv_pending != 0 && dispsock == NULL) { 1516 1.1 christos return (ISC_R_SUCCESS); 1517 1.1 christos } 1518 1.1 christos 1519 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && 1520 1.1 christos dispsock == NULL) 1521 1.1 christos { 1522 1.1 christos return (ISC_R_SUCCESS); 1523 1.1 christos } 1524 1.1 christos 1525 1.1 christos if (dispsock != NULL) { 1526 1.1 christos sock = dispsock->socket; 1527 1.1 christos } else { 1528 1.1 christos sock = disp->socket; 1529 1.1 christos } 1530 1.1 christos INSIST(sock != NULL); 1531 1.1 christos 1532 1.1 christos switch (disp->socktype) { 1533 1.1 christos /* 1534 1.1 christos * UDP reads are always maximal. 1535 1.1 christos */ 1536 1.1 christos case isc_sockettype_udp: 1537 1.1 christos region.length = disp->mgr->buffersize; 1538 1.1 christos region.base = allocate_udp_buffer(disp); 1539 1.1 christos if (region.base == NULL) { 1540 1.1 christos return (ISC_R_NOMEMORY); 1541 1.1 christos } 1542 1.1 christos if (dispsock != NULL) { 1543 1.1 christos isc_task_t *dt = dispsock->task; 1544 1.1 christos isc_socketevent_t *sev = allocate_sevent( 1545 1.1 christos disp, sock, ISC_SOCKEVENT_RECVDONE, udp_exrecv, 1546 1.1 christos dispsock); 1547 1.1 christos if (sev == NULL) { 1548 1.1 christos free_buffer(disp, region.base, region.length); 1549 1.1 christos return (ISC_R_NOMEMORY); 1550 1.1 christos } 1551 1.1 christos 1552 1.1 christos res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); 1553 1.1 christos if (res != ISC_R_SUCCESS) { 1554 1.1 christos free_buffer(disp, region.base, region.length); 1555 1.1 christos return (res); 1556 1.1 christos } 1557 1.1 christos } else { 1558 1.1 christos isc_task_t *dt = disp->task[0]; 1559 1.1 christos isc_socketevent_t *sev = allocate_sevent( 1560 1.1 christos disp, sock, ISC_SOCKEVENT_RECVDONE, udp_shrecv, 1561 1.1 christos disp); 1562 1.1 christos if (sev == NULL) { 1563 1.1 christos free_buffer(disp, region.base, region.length); 1564 1.1 christos return (ISC_R_NOMEMORY); 1565 1.1 christos } 1566 1.1 christos 1567 1.1 christos res = isc_socket_recv2(sock, ®ion, 1, dt, sev, 0); 1568 1.1 christos if (res != ISC_R_SUCCESS) { 1569 1.1 christos free_buffer(disp, region.base, region.length); 1570 1.1 christos disp->shutdown_why = res; 1571 1.1 christos disp->shutting_down = 1; 1572 1.1 christos do_cancel(disp); 1573 1.1 christos return (ISC_R_SUCCESS); /* recover by cancel */ 1574 1.1 christos } 1575 1.1 christos INSIST(disp->recv_pending == 0); 1576 1.1 christos disp->recv_pending = 1; 1577 1.1 christos } 1578 1.1 christos break; 1579 1.1 christos 1580 1.1 christos case isc_sockettype_tcp: 1581 1.1 christos res = dns_tcpmsg_readmessage(&disp->tcpmsg, disp->task[0], 1582 1.1 christos tcp_recv, disp); 1583 1.1 christos if (res != ISC_R_SUCCESS) { 1584 1.1 christos disp->shutdown_why = res; 1585 1.1 christos disp->shutting_down = 1; 1586 1.1 christos do_cancel(disp); 1587 1.1 christos return (ISC_R_SUCCESS); /* recover by cancel */ 1588 1.1 christos } 1589 1.1 christos INSIST(disp->recv_pending == 0); 1590 1.1 christos disp->recv_pending = 1; 1591 1.1 christos break; 1592 1.1 christos default: 1593 1.1 christos UNREACHABLE(); 1594 1.1 christos } 1595 1.1 christos 1596 1.1 christos return (ISC_R_SUCCESS); 1597 1.1 christos } 1598 1.1 christos 1599 1.1 christos /* 1600 1.1 christos * Mgr must be locked when calling this function. 1601 1.1 christos */ 1602 1.1 christos static bool 1603 1.1 christos destroy_mgr_ok(dns_dispatchmgr_t *mgr) { 1604 1.1 christos mgr_log(mgr, LVL(90), 1605 1.1 christos "destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, ", 1606 1.1 christos MGR_IS_SHUTTINGDOWN(mgr), !ISC_LIST_EMPTY(mgr->list)); 1607 1.1 christos if (!MGR_IS_SHUTTINGDOWN(mgr)) { 1608 1.1 christos return (false); 1609 1.1 christos } 1610 1.1 christos if (!ISC_LIST_EMPTY(mgr->list)) { 1611 1.1 christos return (false); 1612 1.1 christos } 1613 1.1 christos if (isc_refcount_current(&mgr->irefs) != 0) { 1614 1.1 christos return (false); 1615 1.1 christos } 1616 1.1 christos 1617 1.1 christos return (true); 1618 1.1 christos } 1619 1.1 christos 1620 1.1 christos /* 1621 1.1 christos * Mgr must be unlocked when calling this function. 1622 1.1 christos */ 1623 1.1 christos static void 1624 1.1 christos destroy_mgr(dns_dispatchmgr_t **mgrp) { 1625 1.1 christos dns_dispatchmgr_t *mgr; 1626 1.1 christos 1627 1.1 christos mgr = *mgrp; 1628 1.1 christos *mgrp = NULL; 1629 1.1 christos 1630 1.1 christos mgr->magic = 0; 1631 1.1 christos isc_mutex_destroy(&mgr->lock); 1632 1.1 christos mgr->state = 0; 1633 1.1 christos 1634 1.1 christos if (mgr->qid != NULL) { 1635 1.1 christos qid_destroy(mgr->mctx, &mgr->qid); 1636 1.1 christos } 1637 1.1 christos 1638 1.1 christos isc_mutex_destroy(&mgr->buffer_lock); 1639 1.1 christos 1640 1.1 christos if (mgr->blackhole != NULL) { 1641 1.1 christos dns_acl_detach(&mgr->blackhole); 1642 1.1 christos } 1643 1.1 christos 1644 1.1 christos if (mgr->stats != NULL) { 1645 1.1 christos isc_stats_detach(&mgr->stats); 1646 1.1 christos } 1647 1.1 christos 1648 1.1 christos if (mgr->v4ports != NULL) { 1649 1.1 christos isc_mem_put(mgr->mctx, mgr->v4ports, 1650 1.1 christos mgr->nv4ports * sizeof(in_port_t)); 1651 1.1 christos } 1652 1.1 christos if (mgr->v6ports != NULL) { 1653 1.1 christos isc_mem_put(mgr->mctx, mgr->v6ports, 1654 1.1 christos mgr->nv6ports * sizeof(in_port_t)); 1655 1.1 christos } 1656 1.1 christos isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(dns_dispatchmgr_t)); 1657 1.1 christos } 1658 1.1 christos 1659 1.1 christos static isc_result_t 1660 1.1 christos open_socket(isc_socketmgr_t *mgr, const isc_sockaddr_t *local, 1661 1.1 christos unsigned int options, isc_socket_t **sockp, 1662 1.1 christos isc_socket_t *dup_socket, bool duponly) { 1663 1.1 christos isc_socket_t *sock; 1664 1.1 christos isc_result_t result; 1665 1.1 christos 1666 1.1 christos sock = *sockp; 1667 1.1 christos if (sock != NULL) { 1668 1.1 christos result = isc_socket_open(sock); 1669 1.1 christos if (result != ISC_R_SUCCESS) { 1670 1.1 christos return (result); 1671 1.1 christos } 1672 1.1 christos } else if (dup_socket != NULL && 1673 1.1 christos (!isc_socket_hasreuseport() || duponly)) 1674 1.1 christos { 1675 1.1 christos result = isc_socket_dup(dup_socket, &sock); 1676 1.1 christos if (result != ISC_R_SUCCESS) { 1677 1.1 christos return (result); 1678 1.1 christos } 1679 1.1 christos 1680 1.1 christos isc_socket_setname(sock, "dispatcher", NULL); 1681 1.1 christos *sockp = sock; 1682 1.1 christos return (ISC_R_SUCCESS); 1683 1.1 christos } else { 1684 1.1 christos result = isc_socket_create(mgr, isc_sockaddr_pf(local), 1685 1.1 christos isc_sockettype_udp, &sock); 1686 1.1 christos if (result != ISC_R_SUCCESS) { 1687 1.1 christos return (result); 1688 1.1 christos } 1689 1.1 christos } 1690 1.1 christos 1691 1.1 christos isc_socket_setname(sock, "dispatcher", NULL); 1692 1.1 christos 1693 1.1 christos #ifndef ISC_ALLOW_MAPPED 1694 1.1 christos isc_socket_ipv6only(sock, true); 1695 1.1 christos #endif /* ifndef ISC_ALLOW_MAPPED */ 1696 1.1 christos result = isc_socket_bind(sock, local, options); 1697 1.1 christos if (result != ISC_R_SUCCESS) { 1698 1.1 christos if (*sockp == NULL) { 1699 1.1 christos isc_socket_detach(&sock); 1700 1.1 christos } else { 1701 1.1 christos isc_socket_close(sock); 1702 1.1 christos } 1703 1.1 christos return (result); 1704 1.1 christos } 1705 1.1 christos 1706 1.1 christos *sockp = sock; 1707 1.1 christos return (ISC_R_SUCCESS); 1708 1.1 christos } 1709 1.1 christos 1710 1.1 christos /*% 1711 1.1 christos * Create a temporary port list to set the initial default set of dispatch 1712 1.1 christos * ports: [1024, 65535]. This is almost meaningless as the application will 1713 1.1 christos * normally set the ports explicitly, but is provided to fill some minor corner 1714 1.1 christos * cases. 1715 1.1 christos */ 1716 1.1 christos static isc_result_t 1717 1.1 christos create_default_portset(isc_mem_t *mctx, isc_portset_t **portsetp) { 1718 1.1 christos isc_result_t result; 1719 1.1 christos 1720 1.1 christos result = isc_portset_create(mctx, portsetp); 1721 1.1 christos if (result != ISC_R_SUCCESS) { 1722 1.1 christos return (result); 1723 1.1 christos } 1724 1.1 christos isc_portset_addrange(*portsetp, 1024, 65535); 1725 1.1 christos 1726 1.1 christos return (ISC_R_SUCCESS); 1727 1.1 christos } 1728 1.1 christos 1729 1.1 christos /* 1730 1.1 christos * Publics. 1731 1.1 christos */ 1732 1.1 christos 1733 1.1 christos isc_result_t 1734 1.1 christos dns_dispatchmgr_create(isc_mem_t *mctx, dns_dispatchmgr_t **mgrp) { 1735 1.1 christos dns_dispatchmgr_t *mgr; 1736 1.1 christos isc_result_t result; 1737 1.1 christos isc_portset_t *v4portset = NULL; 1738 1.1 christos isc_portset_t *v6portset = NULL; 1739 1.1 christos 1740 1.1 christos REQUIRE(mctx != NULL); 1741 1.1 christos REQUIRE(mgrp != NULL && *mgrp == NULL); 1742 1.1 christos 1743 1.1 christos mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t)); 1744 1.1 christos *mgr = (dns_dispatchmgr_t){ 0 }; 1745 1.1 christos 1746 1.1 christos isc_mem_attach(mctx, &mgr->mctx); 1747 1.1 christos 1748 1.1 christos isc_mutex_init(&mgr->lock); 1749 1.1 christos isc_mutex_init(&mgr->buffer_lock); 1750 1.1 christos 1751 1.1 christos isc_refcount_init(&mgr->irefs, 0); 1752 1.1 christos 1753 1.1 christos ISC_LIST_INIT(mgr->list); 1754 1.1 christos 1755 1.1 christos mgr->magic = DNS_DISPATCHMGR_MAGIC; 1756 1.1 christos 1757 1.1 christos result = create_default_portset(mctx, &v4portset); 1758 1.1 christos if (result == ISC_R_SUCCESS) { 1759 1.1 christos result = create_default_portset(mctx, &v6portset); 1760 1.1 christos if (result == ISC_R_SUCCESS) { 1761 1.1 christos result = dns_dispatchmgr_setavailports(mgr, v4portset, 1762 1.1 christos v6portset); 1763 1.1 christos } 1764 1.1 christos } 1765 1.1 christos if (v4portset != NULL) { 1766 1.1 christos isc_portset_destroy(mctx, &v4portset); 1767 1.1 christos } 1768 1.1 christos if (v6portset != NULL) { 1769 1.1 christos isc_portset_destroy(mctx, &v6portset); 1770 1.1 christos } 1771 1.1 christos if (result != ISC_R_SUCCESS) { 1772 1.1 christos goto kill_dpool; 1773 1.1 christos } 1774 1.1 christos 1775 1.1 christos *mgrp = mgr; 1776 1.1 christos return (ISC_R_SUCCESS); 1777 1.1 christos 1778 1.1 christos kill_dpool: 1779 1.1 christos isc_mutex_destroy(&mgr->buffer_lock); 1780 1.1 christos isc_mutex_destroy(&mgr->lock); 1781 1.1 christos isc_mem_putanddetach(&mctx, mgr, sizeof(dns_dispatchmgr_t)); 1782 1.1 christos 1783 1.1 christos return (result); 1784 1.1 christos } 1785 1.1 christos 1786 1.1 christos void 1787 1.1 christos dns_dispatchmgr_setblackhole(dns_dispatchmgr_t *mgr, dns_acl_t *blackhole) { 1788 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 1789 1.1 christos if (mgr->blackhole != NULL) { 1790 1.1 christos dns_acl_detach(&mgr->blackhole); 1791 1.1 christos } 1792 1.1 christos dns_acl_attach(blackhole, &mgr->blackhole); 1793 1.1 christos } 1794 1.1 christos 1795 1.1 christos dns_acl_t * 1796 1.1 christos dns_dispatchmgr_getblackhole(dns_dispatchmgr_t *mgr) { 1797 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 1798 1.1 christos return (mgr->blackhole); 1799 1.1 christos } 1800 1.1 christos 1801 1.1 christos void 1802 1.1 christos dns_dispatchmgr_setblackportlist(dns_dispatchmgr_t *mgr, 1803 1.1 christos dns_portlist_t *portlist) { 1804 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 1805 1.1 christos UNUSED(portlist); 1806 1.1 christos 1807 1.1 christos /* This function is deprecated: use dns_dispatchmgr_setavailports(). */ 1808 1.1 christos return; 1809 1.1 christos } 1810 1.1 christos 1811 1.1 christos dns_portlist_t * 1812 1.1 christos dns_dispatchmgr_getblackportlist(dns_dispatchmgr_t *mgr) { 1813 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 1814 1.1 christos return (NULL); /* this function is deprecated */ 1815 1.1 christos } 1816 1.1 christos 1817 1.1 christos isc_result_t 1818 1.1 christos dns_dispatchmgr_setavailports(dns_dispatchmgr_t *mgr, isc_portset_t *v4portset, 1819 1.1 christos isc_portset_t *v6portset) { 1820 1.1 christos in_port_t *v4ports, *v6ports, p; 1821 1.1 christos unsigned int nv4ports, nv6ports, i4, i6; 1822 1.1 christos 1823 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 1824 1.1 christos 1825 1.1 christos nv4ports = isc_portset_nports(v4portset); 1826 1.1 christos nv6ports = isc_portset_nports(v6portset); 1827 1.1 christos 1828 1.1 christos v4ports = NULL; 1829 1.1 christos if (nv4ports != 0) { 1830 1.1 christos v4ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv4ports); 1831 1.1 christos } 1832 1.1 christos v6ports = NULL; 1833 1.1 christos if (nv6ports != 0) { 1834 1.1 christos v6ports = isc_mem_get(mgr->mctx, sizeof(in_port_t) * nv6ports); 1835 1.1 christos } 1836 1.1 christos 1837 1.1 christos p = 0; 1838 1.1 christos i4 = 0; 1839 1.1 christos i6 = 0; 1840 1.1 christos do { 1841 1.1 christos if (isc_portset_isset(v4portset, p)) { 1842 1.1 christos INSIST(i4 < nv4ports); 1843 1.1 christos v4ports[i4++] = p; 1844 1.1 christos } 1845 1.1 christos if (isc_portset_isset(v6portset, p)) { 1846 1.1 christos INSIST(i6 < nv6ports); 1847 1.1 christos v6ports[i6++] = p; 1848 1.1 christos } 1849 1.1 christos } while (p++ < 65535); 1850 1.1 christos INSIST(i4 == nv4ports && i6 == nv6ports); 1851 1.1 christos 1852 1.1 christos PORTBUFLOCK(mgr); 1853 1.1 christos if (mgr->v4ports != NULL) { 1854 1.1 christos isc_mem_put(mgr->mctx, mgr->v4ports, 1855 1.1 christos mgr->nv4ports * sizeof(in_port_t)); 1856 1.1 christos } 1857 1.1 christos mgr->v4ports = v4ports; 1858 1.1 christos mgr->nv4ports = nv4ports; 1859 1.1 christos 1860 1.1 christos if (mgr->v6ports != NULL) { 1861 1.1 christos isc_mem_put(mgr->mctx, mgr->v6ports, 1862 1.1 christos mgr->nv6ports * sizeof(in_port_t)); 1863 1.1 christos } 1864 1.1 christos mgr->v6ports = v6ports; 1865 1.1 christos mgr->nv6ports = nv6ports; 1866 1.1 christos PORTBUFUNLOCK(mgr); 1867 1.1 christos 1868 1.1 christos return (ISC_R_SUCCESS); 1869 1.1 christos } 1870 1.1 christos 1871 1.1 christos static isc_result_t 1872 1.1 christos dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, unsigned int buffersize, 1873 1.1 christos unsigned int maxbuffers, unsigned int maxrequests, 1874 1.1 christos unsigned int buckets, unsigned int increment) { 1875 1.1 christos isc_result_t result; 1876 1.1 christos 1877 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 1878 1.1 christos REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); 1879 1.1 christos REQUIRE(maxbuffers > 0); 1880 1.1 christos REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ 1881 1.1 christos REQUIRE(increment > buckets); 1882 1.1 christos UNUSED(maxrequests); 1883 1.1 christos 1884 1.1 christos /* 1885 1.1 christos * Keep some number of items around. This should be a config 1886 1.1 christos * option. For now, keep 8, but later keep at least two even 1887 1.1 christos * if the caller wants less. This allows us to ensure certain 1888 1.1 christos * things, like an event can be "freed" and the next allocation 1889 1.1 christos * will always succeed. 1890 1.1 christos * 1891 1.1 christos * Note that if limits are placed on anything here, we use one 1892 1.1 christos * event internally, so the actual limit should be "wanted + 1." 1893 1.1 christos * 1894 1.1 christos * XXXMLG 1895 1.1 christos */ 1896 1.1 christos 1897 1.1 christos if (maxbuffers < 8) { 1898 1.1 christos maxbuffers = 8; 1899 1.1 christos } 1900 1.1 christos 1901 1.1 christos LOCK(&mgr->buffer_lock); 1902 1.1 christos 1903 1.1 christos if (maxbuffers > mgr->maxbuffers) { 1904 1.1 christos mgr->maxbuffers = maxbuffers; 1905 1.1 christos } 1906 1.1 christos 1907 1.1 christos /* Create or adjust socket pool */ 1908 1.1 christos if (mgr->qid != NULL) { 1909 1.1 christos UNLOCK(&mgr->buffer_lock); 1910 1.1 christos return (ISC_R_SUCCESS); 1911 1.1 christos } 1912 1.1 christos 1913 1.1 christos result = qid_allocate(mgr, buckets, increment, &mgr->qid, true); 1914 1.1 christos if (result != ISC_R_SUCCESS) { 1915 1.1 christos goto cleanup; 1916 1.1 christos } 1917 1.1 christos 1918 1.1 christos mgr->buffersize = buffersize; 1919 1.1 christos mgr->maxbuffers = maxbuffers; 1920 1.1 christos UNLOCK(&mgr->buffer_lock); 1921 1.1 christos return (ISC_R_SUCCESS); 1922 1.1 christos 1923 1.1 christos cleanup: 1924 1.1 christos UNLOCK(&mgr->buffer_lock); 1925 1.1 christos return (result); 1926 1.1 christos } 1927 1.1 christos 1928 1.1 christos void 1929 1.1 christos dns_dispatchmgr_destroy(dns_dispatchmgr_t **mgrp) { 1930 1.1 christos dns_dispatchmgr_t *mgr; 1931 1.1 christos bool killit; 1932 1.1 christos 1933 1.1 christos REQUIRE(mgrp != NULL); 1934 1.1 christos REQUIRE(VALID_DISPATCHMGR(*mgrp)); 1935 1.1 christos 1936 1.1 christos mgr = *mgrp; 1937 1.1 christos *mgrp = NULL; 1938 1.1 christos 1939 1.1 christos LOCK(&mgr->lock); 1940 1.1 christos mgr->state |= MGR_SHUTTINGDOWN; 1941 1.1 christos killit = destroy_mgr_ok(mgr); 1942 1.1 christos UNLOCK(&mgr->lock); 1943 1.1 christos 1944 1.1 christos mgr_log(mgr, LVL(90), "destroy: killit=%d", killit); 1945 1.1 christos 1946 1.1 christos if (killit) { 1947 1.1 christos destroy_mgr(&mgr); 1948 1.1 christos } 1949 1.1 christos } 1950 1.1 christos 1951 1.1 christos void 1952 1.1 christos dns_dispatchmgr_setstats(dns_dispatchmgr_t *mgr, isc_stats_t *stats) { 1953 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 1954 1.1 christos REQUIRE(ISC_LIST_EMPTY(mgr->list)); 1955 1.1 christos REQUIRE(mgr->stats == NULL); 1956 1.1 christos 1957 1.1 christos isc_stats_attach(stats, &mgr->stats); 1958 1.1 christos } 1959 1.1 christos 1960 1.1 christos static int 1961 1.1 christos port_cmp(const void *key, const void *ent) { 1962 1.1 christos in_port_t p1 = *(const in_port_t *)key; 1963 1.1 christos in_port_t p2 = *(const in_port_t *)ent; 1964 1.1 christos 1965 1.1 christos if (p1 < p2) { 1966 1.1 christos return (-1); 1967 1.1 christos } else if (p1 == p2) { 1968 1.1 christos return (0); 1969 1.1 christos } else { 1970 1.1 christos return (1); 1971 1.1 christos } 1972 1.1 christos } 1973 1.1 christos 1974 1.1 christos static bool 1975 1.1 christos portavailable(dns_dispatchmgr_t *mgr, isc_socket_t *sock, 1976 1.1 christos isc_sockaddr_t *sockaddrp) { 1977 1.1 christos isc_sockaddr_t sockaddr; 1978 1.1 christos isc_result_t result; 1979 1.1 christos in_port_t *ports, port; 1980 1.1 christos unsigned int nports; 1981 1.1 christos bool available = false; 1982 1.1 christos 1983 1.1 christos REQUIRE(sock != NULL || sockaddrp != NULL); 1984 1.1 christos 1985 1.1 christos PORTBUFLOCK(mgr); 1986 1.1 christos if (sock != NULL) { 1987 1.1 christos sockaddrp = &sockaddr; 1988 1.1 christos result = isc_socket_getsockname(sock, sockaddrp); 1989 1.1 christos if (result != ISC_R_SUCCESS) { 1990 1.1 christos goto unlock; 1991 1.1 christos } 1992 1.1 christos } 1993 1.1 christos 1994 1.1 christos if (isc_sockaddr_pf(sockaddrp) == AF_INET) { 1995 1.1 christos ports = mgr->v4ports; 1996 1.1 christos nports = mgr->nv4ports; 1997 1.1 christos } else { 1998 1.1 christos ports = mgr->v6ports; 1999 1.1 christos nports = mgr->nv6ports; 2000 1.1 christos } 2001 1.1 christos if (ports == NULL) { 2002 1.1 christos goto unlock; 2003 1.1 christos } 2004 1.1 christos 2005 1.1 christos port = isc_sockaddr_getport(sockaddrp); 2006 1.1 christos if (bsearch(&port, ports, nports, sizeof(in_port_t), port_cmp) != NULL) 2007 1.1 christos { 2008 1.1 christos available = true; 2009 1.1 christos } 2010 1.1 christos 2011 1.1 christos unlock: 2012 1.1 christos PORTBUFUNLOCK(mgr); 2013 1.1 christos return (available); 2014 1.1 christos } 2015 1.1 christos 2016 1.1 christos #define ATTRMATCH(_a1, _a2, _mask) (((_a1) & (_mask)) == ((_a2) & (_mask))) 2017 1.1 christos 2018 1.1 christos static bool 2019 1.1 christos local_addr_match(dns_dispatch_t *disp, const isc_sockaddr_t *addr) { 2020 1.1 christos isc_sockaddr_t sockaddr; 2021 1.1 christos isc_result_t result; 2022 1.1 christos 2023 1.1 christos REQUIRE(disp->socket != NULL); 2024 1.1 christos 2025 1.1 christos if (addr == NULL) { 2026 1.1 christos return (true); 2027 1.1 christos } 2028 1.1 christos 2029 1.1 christos /* 2030 1.1 christos * Don't match wildcard ports unless the port is available in the 2031 1.1 christos * current configuration. 2032 1.1 christos */ 2033 1.1 christos if (isc_sockaddr_getport(addr) == 0 && 2034 1.1 christos isc_sockaddr_getport(&disp->local) == 0 && 2035 1.1 christos !portavailable(disp->mgr, disp->socket, NULL)) 2036 1.1 christos { 2037 1.1 christos return (false); 2038 1.1 christos } 2039 1.1 christos 2040 1.1 christos /* 2041 1.1 christos * Check if we match the binding <address,port>. 2042 1.1 christos * Wildcard ports match/fail here. 2043 1.1 christos */ 2044 1.1 christos if (isc_sockaddr_equal(&disp->local, addr)) { 2045 1.1 christos return (true); 2046 1.1 christos } 2047 1.1 christos if (isc_sockaddr_getport(addr) == 0) { 2048 1.1 christos return (false); 2049 1.1 christos } 2050 1.1 christos 2051 1.1 christos /* 2052 1.1 christos * Check if we match a bound wildcard port <address,port>. 2053 1.1 christos */ 2054 1.1 christos if (!isc_sockaddr_eqaddr(&disp->local, addr)) { 2055 1.1 christos return (false); 2056 1.1 christos } 2057 1.1 christos result = isc_socket_getsockname(disp->socket, &sockaddr); 2058 1.1 christos if (result != ISC_R_SUCCESS) { 2059 1.1 christos return (false); 2060 1.1 christos } 2061 1.1 christos 2062 1.1 christos return (isc_sockaddr_equal(&sockaddr, addr)); 2063 1.1 christos } 2064 1.1 christos 2065 1.1 christos /* 2066 1.1 christos * Requires mgr be locked. 2067 1.1 christos * 2068 1.1 christos * No dispatcher can be locked by this thread when calling this function. 2069 1.1 christos * 2070 1.1 christos * 2071 1.1 christos * NOTE: 2072 1.1 christos * If a matching dispatcher is found, it is locked after this function 2073 1.1 christos * returns, and must be unlocked by the caller. 2074 1.1 christos */ 2075 1.1 christos static isc_result_t 2076 1.1 christos dispatch_find(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *local, 2077 1.1 christos unsigned int attributes, unsigned int mask, 2078 1.1 christos dns_dispatch_t **dispp) { 2079 1.1 christos dns_dispatch_t *disp; 2080 1.1 christos isc_result_t result; 2081 1.1 christos 2082 1.1 christos /* 2083 1.1 christos * Make certain that we will not match a private or exclusive dispatch. 2084 1.1 christos */ 2085 1.1 christos attributes &= ~(DNS_DISPATCHATTR_PRIVATE | DNS_DISPATCHATTR_EXCLUSIVE); 2086 1.1 christos mask |= (DNS_DISPATCHATTR_PRIVATE | DNS_DISPATCHATTR_EXCLUSIVE); 2087 1.1 christos 2088 1.1 christos disp = ISC_LIST_HEAD(mgr->list); 2089 1.1 christos while (disp != NULL) { 2090 1.1 christos LOCK(&disp->lock); 2091 1.1 christos if ((disp->shutting_down == 0) && 2092 1.1 christos ATTRMATCH(disp->attributes, attributes, mask) && 2093 1.1 christos local_addr_match(disp, local)) 2094 1.1 christos { 2095 1.1 christos break; 2096 1.1 christos } 2097 1.1 christos UNLOCK(&disp->lock); 2098 1.1 christos disp = ISC_LIST_NEXT(disp, link); 2099 1.1 christos } 2100 1.1 christos 2101 1.1 christos if (disp == NULL) { 2102 1.1 christos result = ISC_R_NOTFOUND; 2103 1.1 christos goto out; 2104 1.1 christos } 2105 1.1 christos 2106 1.1 christos *dispp = disp; 2107 1.1 christos result = ISC_R_SUCCESS; 2108 1.1 christos out: 2109 1.1 christos 2110 1.1 christos return (result); 2111 1.1 christos } 2112 1.1 christos 2113 1.1 christos static isc_result_t 2114 1.1 christos qid_allocate(dns_dispatchmgr_t *mgr, unsigned int buckets, 2115 1.1 christos unsigned int increment, dns_qid_t **qidp, bool needsocktable) { 2116 1.1 christos dns_qid_t *qid; 2117 1.1 christos unsigned int i; 2118 1.1 christos 2119 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 2120 1.1 christos REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ 2121 1.1 christos REQUIRE(increment > buckets); 2122 1.1 christos REQUIRE(qidp != NULL && *qidp == NULL); 2123 1.1 christos 2124 1.1 christos qid = isc_mem_get(mgr->mctx, sizeof(*qid)); 2125 1.1 christos 2126 1.1 christos qid->qid_table = isc_mem_get(mgr->mctx, 2127 1.1 christos buckets * sizeof(dns_displist_t)); 2128 1.1 christos 2129 1.1 christos qid->sock_table = NULL; 2130 1.1 christos if (needsocktable) { 2131 1.1 christos qid->sock_table = isc_mem_get( 2132 1.1 christos mgr->mctx, buckets * sizeof(dispsocketlist_t)); 2133 1.1 christos } 2134 1.1 christos 2135 1.1 christos isc_mutex_init(&qid->lock); 2136 1.1 christos 2137 1.1 christos for (i = 0; i < buckets; i++) { 2138 1.1 christos ISC_LIST_INIT(qid->qid_table[i]); 2139 1.1 christos if (qid->sock_table != NULL) { 2140 1.1 christos ISC_LIST_INIT(qid->sock_table[i]); 2141 1.1 christos } 2142 1.1 christos } 2143 1.1 christos 2144 1.1 christos qid->qid_nbuckets = buckets; 2145 1.1 christos qid->qid_increment = increment; 2146 1.1 christos qid->magic = QID_MAGIC; 2147 1.1 christos *qidp = qid; 2148 1.1 christos return (ISC_R_SUCCESS); 2149 1.1 christos } 2150 1.1 christos 2151 1.1 christos static void 2152 1.1 christos qid_destroy(isc_mem_t *mctx, dns_qid_t **qidp) { 2153 1.1 christos dns_qid_t *qid; 2154 1.1 christos 2155 1.1 christos REQUIRE(qidp != NULL); 2156 1.1 christos qid = *qidp; 2157 1.1 christos *qidp = NULL; 2158 1.1 christos 2159 1.1 christos REQUIRE(VALID_QID(qid)); 2160 1.1 christos 2161 1.1 christos qid->magic = 0; 2162 1.1 christos isc_mem_put(mctx, qid->qid_table, 2163 1.1 christos qid->qid_nbuckets * sizeof(dns_displist_t)); 2164 1.1 christos if (qid->sock_table != NULL) { 2165 1.1 christos isc_mem_put(mctx, qid->sock_table, 2166 1.1 christos qid->qid_nbuckets * sizeof(dispsocketlist_t)); 2167 1.1 christos } 2168 1.1 christos isc_mutex_destroy(&qid->lock); 2169 1.1 christos isc_mem_put(mctx, qid, sizeof(*qid)); 2170 1.1 christos } 2171 1.1 christos 2172 1.1 christos /* 2173 1.1 christos * Allocate and set important limits. 2174 1.1 christos */ 2175 1.1 christos static isc_result_t 2176 1.1 christos dispatch_allocate(dns_dispatchmgr_t *mgr, unsigned int maxrequests, 2177 1.1 christos dns_dispatch_t **dispp) { 2178 1.1 christos dns_dispatch_t *disp; 2179 1.1 christos isc_result_t result; 2180 1.1 christos 2181 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 2182 1.1 christos REQUIRE(dispp != NULL && *dispp == NULL); 2183 1.1 christos 2184 1.1 christos /* 2185 1.1 christos * Set up the dispatcher, mostly. Don't bother setting some of 2186 1.1 christos * the options that are controlled by tcp vs. udp, etc. 2187 1.1 christos */ 2188 1.1 christos 2189 1.1 christos disp = isc_mem_get(mgr->mctx, sizeof(*disp)); 2190 1.1 christos isc_refcount_increment0(&mgr->irefs); 2191 1.1 christos 2192 1.1 christos disp->magic = 0; 2193 1.1 christos disp->mgr = mgr; 2194 1.1 christos disp->maxrequests = maxrequests; 2195 1.1 christos disp->attributes = 0; 2196 1.1 christos ISC_LINK_INIT(disp, link); 2197 1.1 christos disp->refcount = 1; 2198 1.1 christos disp->recv_pending = 0; 2199 1.1 christos memset(&disp->local, 0, sizeof(disp->local)); 2200 1.1 christos memset(&disp->peer, 0, sizeof(disp->peer)); 2201 1.1 christos disp->localport = 0; 2202 1.1 christos disp->shutting_down = 0; 2203 1.1 christos disp->shutdown_out = 0; 2204 1.1 christos disp->connected = 0; 2205 1.1 christos disp->tcpmsg_valid = 0; 2206 1.1 christos disp->shutdown_why = ISC_R_UNEXPECTED; 2207 1.1 christos disp->requests = 0; 2208 1.1 christos disp->tcpbuffers = 0; 2209 1.1 christos disp->qid = NULL; 2210 1.1 christos ISC_LIST_INIT(disp->activesockets); 2211 1.1 christos ISC_LIST_INIT(disp->inactivesockets); 2212 1.1 christos disp->nsockets = 0; 2213 1.1 christos disp->port_table = NULL; 2214 1.1 christos disp->dscp = -1; 2215 1.1 christos 2216 1.1 christos isc_mutex_init(&disp->lock); 2217 1.1 christos 2218 1.1 christos disp->failsafe_ev = allocate_devent(disp); 2219 1.1 christos if (disp->failsafe_ev == NULL) { 2220 1.1 christos result = ISC_R_NOMEMORY; 2221 1.1 christos goto kill_lock; 2222 1.1 christos } 2223 1.1 christos 2224 1.1 christos disp->magic = DISPATCH_MAGIC; 2225 1.1 christos 2226 1.1 christos *dispp = disp; 2227 1.1 christos return (ISC_R_SUCCESS); 2228 1.1 christos 2229 1.1 christos /* 2230 1.1 christos * error returns 2231 1.1 christos */ 2232 1.1 christos kill_lock: 2233 1.1 christos isc_mutex_destroy(&disp->lock); 2234 1.1 christos isc_refcount_decrement(&mgr->irefs); 2235 1.1 christos isc_mem_put(mgr->mctx, disp, sizeof(*disp)); 2236 1.1 christos 2237 1.1 christos return (result); 2238 1.1 christos } 2239 1.1 christos 2240 1.1 christos /* 2241 1.1 christos * MUST be unlocked, and not used by anything. 2242 1.1 christos */ 2243 1.1 christos static void 2244 1.1 christos dispatch_free(dns_dispatch_t **dispp) { 2245 1.1 christos dns_dispatch_t *disp; 2246 1.1 christos dns_dispatchmgr_t *mgr; 2247 1.1 christos 2248 1.1 christos REQUIRE(VALID_DISPATCH(*dispp)); 2249 1.1 christos disp = *dispp; 2250 1.1 christos *dispp = NULL; 2251 1.1 christos 2252 1.1 christos mgr = disp->mgr; 2253 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 2254 1.1 christos 2255 1.1 christos if (disp->tcpmsg_valid) { 2256 1.1 christos dns_tcpmsg_invalidate(&disp->tcpmsg); 2257 1.1 christos disp->tcpmsg_valid = 0; 2258 1.1 christos } 2259 1.1 christos 2260 1.1 christos INSIST(disp->tcpbuffers == 0); 2261 1.1 christos INSIST(disp->requests == 0); 2262 1.1 christos INSIST(disp->recv_pending == 0); 2263 1.1 christos INSIST(ISC_LIST_EMPTY(disp->activesockets)); 2264 1.1 christos INSIST(ISC_LIST_EMPTY(disp->inactivesockets)); 2265 1.1 christos 2266 1.1 christos isc_refcount_decrement(&mgr->irefs); 2267 1.1 christos isc_mem_put(mgr->mctx, disp->failsafe_ev, sizeof(*disp->failsafe_ev)); 2268 1.1 christos disp->failsafe_ev = NULL; 2269 1.1 christos 2270 1.1 christos if (disp->qid != NULL) { 2271 1.1 christos qid_destroy(mgr->mctx, &disp->qid); 2272 1.1 christos } 2273 1.1 christos 2274 1.1 christos if (disp->port_table != NULL) { 2275 1.1 christos for (int i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { 2276 1.1 christos INSIST(ISC_LIST_EMPTY(disp->port_table[i])); 2277 1.1 christos } 2278 1.1 christos isc_mem_put(mgr->mctx, disp->port_table, 2279 1.1 christos sizeof(disp->port_table[0]) * 2280 1.1 christos DNS_DISPATCH_PORTTABLESIZE); 2281 1.1 christos } 2282 1.1 christos 2283 1.1 christos disp->mgr = NULL; 2284 1.1 christos isc_mutex_destroy(&disp->lock); 2285 1.1 christos disp->magic = 0; 2286 1.1 christos isc_refcount_decrement(&mgr->irefs); 2287 1.1 christos isc_mem_put(mgr->mctx, disp, sizeof(*disp)); 2288 1.1 christos } 2289 1.1 christos 2290 1.1 christos isc_result_t 2291 1.1 christos dns_dispatch_createtcp(dns_dispatchmgr_t *mgr, isc_socket_t *sock, 2292 1.1 christos isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, 2293 1.1 christos const isc_sockaddr_t *destaddr, unsigned int buffersize, 2294 1.1 christos unsigned int maxbuffers, unsigned int maxrequests, 2295 1.1 christos unsigned int buckets, unsigned int increment, 2296 1.1 christos unsigned int attributes, dns_dispatch_t **dispp) { 2297 1.1 christos isc_result_t result; 2298 1.1 christos dns_dispatch_t *disp; 2299 1.1 christos 2300 1.1 christos UNUSED(maxbuffers); 2301 1.1 christos UNUSED(buffersize); 2302 1.1 christos 2303 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 2304 1.1 christos REQUIRE(isc_socket_gettype(sock) == isc_sockettype_tcp); 2305 1.1 christos REQUIRE((attributes & DNS_DISPATCHATTR_TCP) != 0); 2306 1.1 christos REQUIRE((attributes & DNS_DISPATCHATTR_UDP) == 0); 2307 1.1 christos 2308 1.1 christos if (destaddr == NULL) { 2309 1.1 christos attributes |= DNS_DISPATCHATTR_PRIVATE; /* XXXMLG */ 2310 1.1 christos } 2311 1.1 christos 2312 1.1 christos LOCK(&mgr->lock); 2313 1.1 christos 2314 1.1 christos /* 2315 1.1 christos * dispatch_allocate() checks mgr for us. 2316 1.1 christos * qid_allocate() checks buckets and increment for us. 2317 1.1 christos */ 2318 1.1 christos disp = NULL; 2319 1.1 christos result = dispatch_allocate(mgr, maxrequests, &disp); 2320 1.1 christos if (result != ISC_R_SUCCESS) { 2321 1.1 christos UNLOCK(&mgr->lock); 2322 1.1 christos return (result); 2323 1.1 christos } 2324 1.1 christos 2325 1.1 christos result = qid_allocate(mgr, buckets, increment, &disp->qid, false); 2326 1.1 christos if (result != ISC_R_SUCCESS) { 2327 1.1 christos goto deallocate_dispatch; 2328 1.1 christos } 2329 1.1 christos 2330 1.1 christos disp->socktype = isc_sockettype_tcp; 2331 1.1 christos disp->socket = NULL; 2332 1.1 christos isc_socket_attach(sock, &disp->socket); 2333 1.1 christos 2334 1.1 christos disp->sepool = NULL; 2335 1.1 christos 2336 1.1 christos disp->ntasks = 1; 2337 1.1 christos disp->task[0] = NULL; 2338 1.1 christos result = isc_task_create(taskmgr, 50, &disp->task[0]); 2339 1.1 christos if (result != ISC_R_SUCCESS) { 2340 1.1 christos goto kill_socket; 2341 1.1 christos } 2342 1.1 christos 2343 1.1 christos disp->ctlevent = 2344 1.1 christos isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, 2345 1.1 christos destroy_disp, disp, sizeof(isc_event_t)); 2346 1.1 christos 2347 1.1 christos isc_task_setname(disp->task[0], "tcpdispatch", disp); 2348 1.1 christos 2349 1.1 christos dns_tcpmsg_init(mgr->mctx, disp->socket, &disp->tcpmsg); 2350 1.1 christos disp->tcpmsg_valid = 1; 2351 1.1 christos 2352 1.1 christos disp->attributes = attributes; 2353 1.1 christos 2354 1.1 christos if (localaddr == NULL) { 2355 1.1 christos if (destaddr != NULL) { 2356 1.1 christos switch (isc_sockaddr_pf(destaddr)) { 2357 1.1 christos case AF_INET: 2358 1.1 christos isc_sockaddr_any(&disp->local); 2359 1.1 christos break; 2360 1.1 christos case AF_INET6: 2361 1.1 christos isc_sockaddr_any6(&disp->local); 2362 1.1 christos break; 2363 1.1 christos } 2364 1.1 christos } 2365 1.1 christos } else { 2366 1.1 christos disp->local = *localaddr; 2367 1.1 christos } 2368 1.1 christos 2369 1.1 christos if (destaddr != NULL) { 2370 1.1 christos disp->peer = *destaddr; 2371 1.1 christos } 2372 1.1 christos 2373 1.1 christos /* 2374 1.1 christos * Append it to the dispatcher list. 2375 1.1 christos */ 2376 1.1 christos ISC_LIST_APPEND(mgr->list, disp, link); 2377 1.1 christos UNLOCK(&mgr->lock); 2378 1.1 christos 2379 1.1 christos mgr_log(mgr, LVL(90), "created TCP dispatcher %p", disp); 2380 1.1 christos dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); 2381 1.1 christos *dispp = disp; 2382 1.1 christos 2383 1.1 christos return (ISC_R_SUCCESS); 2384 1.1 christos 2385 1.1 christos kill_socket: 2386 1.1 christos isc_socket_detach(&disp->socket); 2387 1.1 christos deallocate_dispatch: 2388 1.1 christos dispatch_free(&disp); 2389 1.1 christos 2390 1.1 christos UNLOCK(&mgr->lock); 2391 1.1 christos 2392 1.1 christos return (result); 2393 1.1 christos } 2394 1.1 christos 2395 1.1 christos isc_result_t 2396 1.1 christos dns_dispatch_gettcp(dns_dispatchmgr_t *mgr, const isc_sockaddr_t *destaddr, 2397 1.1 christos const isc_sockaddr_t *localaddr, bool *connected, 2398 1.1 christos dns_dispatch_t **dispp) { 2399 1.1 christos dns_dispatch_t *disp; 2400 1.1 christos isc_result_t result; 2401 1.1 christos isc_sockaddr_t peeraddr; 2402 1.1 christos isc_sockaddr_t sockname; 2403 1.1 christos unsigned int attributes, mask; 2404 1.1 christos bool match = false; 2405 1.1 christos 2406 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 2407 1.1 christos REQUIRE(destaddr != NULL); 2408 1.1 christos REQUIRE(dispp != NULL && *dispp == NULL); 2409 1.1 christos 2410 1.1 christos /* First pass */ 2411 1.1 christos attributes = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_CONNECTED; 2412 1.1 christos mask = DNS_DISPATCHATTR_TCP | DNS_DISPATCHATTR_PRIVATE | 2413 1.1 christos DNS_DISPATCHATTR_EXCLUSIVE | DNS_DISPATCHATTR_CONNECTED; 2414 1.1 christos 2415 1.1 christos LOCK(&mgr->lock); 2416 1.1 christos disp = ISC_LIST_HEAD(mgr->list); 2417 1.1 christos while (disp != NULL && !match) { 2418 1.1 christos LOCK(&disp->lock); 2419 1.1 christos if ((disp->shutting_down == 0) && 2420 1.1 christos ATTRMATCH(disp->attributes, attributes, mask) && 2421 1.1 christos (localaddr == NULL || 2422 1.1 christos isc_sockaddr_eqaddr(localaddr, &disp->local))) 2423 1.1 christos { 2424 1.1 christos result = isc_socket_getsockname(disp->socket, 2425 1.1 christos &sockname); 2426 1.1 christos if (result == ISC_R_SUCCESS) { 2427 1.1 christos result = isc_socket_getpeername(disp->socket, 2428 1.1 christos &peeraddr); 2429 1.1 christos } 2430 1.1 christos if (result == ISC_R_SUCCESS && 2431 1.1 christos isc_sockaddr_equal(destaddr, &peeraddr) && 2432 1.1 christos (localaddr == NULL || 2433 1.1 christos isc_sockaddr_eqaddr(localaddr, &sockname))) 2434 1.1 christos { 2435 1.1 christos /* attach */ 2436 1.1 christos disp->refcount++; 2437 1.1 christos *dispp = disp; 2438 1.1 christos match = true; 2439 1.1 christos if (connected != NULL) { 2440 1.1 christos *connected = true; 2441 1.1 christos } 2442 1.1 christos } 2443 1.1 christos } 2444 1.1 christos UNLOCK(&disp->lock); 2445 1.1 christos disp = ISC_LIST_NEXT(disp, link); 2446 1.1 christos } 2447 1.1 christos if (match || connected == NULL) { 2448 1.1 christos UNLOCK(&mgr->lock); 2449 1.1 christos return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND); 2450 1.1 christos } 2451 1.1 christos 2452 1.1 christos /* Second pass, only if connected != NULL */ 2453 1.1 christos attributes = DNS_DISPATCHATTR_TCP; 2454 1.1 christos 2455 1.1 christos disp = ISC_LIST_HEAD(mgr->list); 2456 1.1 christos while (disp != NULL && !match) { 2457 1.1 christos LOCK(&disp->lock); 2458 1.1 christos if ((disp->shutting_down == 0) && 2459 1.1 christos ATTRMATCH(disp->attributes, attributes, mask) && 2460 1.1 christos (localaddr == NULL || 2461 1.1 christos isc_sockaddr_eqaddr(localaddr, &disp->local)) && 2462 1.1 christos isc_sockaddr_equal(destaddr, &disp->peer)) 2463 1.1 christos { 2464 1.1 christos /* attach */ 2465 1.1 christos disp->refcount++; 2466 1.1 christos *dispp = disp; 2467 1.1 christos match = true; 2468 1.1 christos } 2469 1.1 christos UNLOCK(&disp->lock); 2470 1.1 christos disp = ISC_LIST_NEXT(disp, link); 2471 1.1 christos } 2472 1.1 christos UNLOCK(&mgr->lock); 2473 1.1 christos return (match ? ISC_R_SUCCESS : ISC_R_NOTFOUND); 2474 1.1 christos } 2475 1.1 christos 2476 1.1 christos isc_result_t 2477 1.1 christos dns_dispatch_getudp_dup(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, 2478 1.1 christos isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, 2479 1.1 christos unsigned int buffersize, unsigned int maxbuffers, 2480 1.1 christos unsigned int maxrequests, unsigned int buckets, 2481 1.1 christos unsigned int increment, unsigned int attributes, 2482 1.1 christos unsigned int mask, dns_dispatch_t **dispp, 2483 1.1 christos dns_dispatch_t *dup_dispatch) { 2484 1.1 christos isc_result_t result; 2485 1.1 christos dns_dispatch_t *disp = NULL; 2486 1.1 christos 2487 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 2488 1.1 christos REQUIRE(sockmgr != NULL); 2489 1.1 christos REQUIRE(localaddr != NULL); 2490 1.1 christos REQUIRE(taskmgr != NULL); 2491 1.1 christos REQUIRE(buffersize >= 512 && buffersize < (64 * 1024)); 2492 1.1 christos REQUIRE(maxbuffers > 0); 2493 1.1 christos REQUIRE(buckets < 2097169); /* next prime > 65536 * 32 */ 2494 1.1 christos REQUIRE(increment > buckets); 2495 1.1 christos REQUIRE(dispp != NULL && *dispp == NULL); 2496 1.1 christos REQUIRE((attributes & DNS_DISPATCHATTR_TCP) == 0); 2497 1.1 christos 2498 1.1 christos result = dns_dispatchmgr_setudp(mgr, buffersize, maxbuffers, 2499 1.1 christos maxrequests, buckets, increment); 2500 1.1 christos if (result != ISC_R_SUCCESS) { 2501 1.1 christos return (result); 2502 1.1 christos } 2503 1.1 christos 2504 1.1 christos LOCK(&mgr->lock); 2505 1.1 christos 2506 1.1 christos if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 2507 1.1 christos REQUIRE(isc_sockaddr_getport(localaddr) == 0); 2508 1.1 christos goto createudp; 2509 1.1 christos } 2510 1.1 christos 2511 1.1 christos /* 2512 1.1 christos * See if we have a dispatcher that matches. 2513 1.1 christos */ 2514 1.1 christos if (dup_dispatch == NULL) { 2515 1.1 christos result = dispatch_find(mgr, localaddr, attributes, mask, &disp); 2516 1.1 christos if (result == ISC_R_SUCCESS) { 2517 1.1 christos disp->refcount++; 2518 1.1 christos 2519 1.1 christos if (disp->maxrequests < maxrequests) { 2520 1.1 christos disp->maxrequests = maxrequests; 2521 1.1 christos } 2522 1.1 christos 2523 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 2524 1.1 christos 0 && 2525 1.1 christos (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) 2526 1.1 christos { 2527 1.1 christos disp->attributes |= DNS_DISPATCHATTR_NOLISTEN; 2528 1.1 christos if (disp->recv_pending != 0) { 2529 1.1 christos isc_socket_cancel(disp->socket, 2530 1.1 christos disp->task[0], 2531 1.1 christos ISC_SOCKCANCEL_RECV); 2532 1.1 christos } 2533 1.1 christos } 2534 1.1 christos 2535 1.1 christos UNLOCK(&disp->lock); 2536 1.1 christos UNLOCK(&mgr->lock); 2537 1.1 christos 2538 1.1 christos *dispp = disp; 2539 1.1 christos 2540 1.1 christos return (ISC_R_SUCCESS); 2541 1.1 christos } 2542 1.1 christos } 2543 1.1 christos 2544 1.1 christos createudp: 2545 1.1 christos /* 2546 1.1 christos * Nope, create one. 2547 1.1 christos */ 2548 1.1 christos result = dispatch_createudp( 2549 1.1 christos mgr, sockmgr, taskmgr, localaddr, maxrequests, attributes, 2550 1.1 christos &disp, dup_dispatch == NULL ? NULL : dup_dispatch->socket); 2551 1.1 christos 2552 1.1 christos if (result != ISC_R_SUCCESS) { 2553 1.1 christos UNLOCK(&mgr->lock); 2554 1.1 christos return (result); 2555 1.1 christos } 2556 1.1 christos 2557 1.1 christos UNLOCK(&mgr->lock); 2558 1.1 christos *dispp = disp; 2559 1.1 christos 2560 1.1 christos return (ISC_R_SUCCESS); 2561 1.1 christos } 2562 1.1 christos 2563 1.1 christos isc_result_t 2564 1.1 christos dns_dispatch_getudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, 2565 1.1 christos isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, 2566 1.1 christos unsigned int buffersize, unsigned int maxbuffers, 2567 1.1 christos unsigned int maxrequests, unsigned int buckets, 2568 1.1 christos unsigned int increment, unsigned int attributes, 2569 1.1 christos unsigned int mask, dns_dispatch_t **dispp) { 2570 1.1 christos return (dns_dispatch_getudp_dup(mgr, sockmgr, taskmgr, localaddr, 2571 1.1 christos buffersize, maxbuffers, maxrequests, 2572 1.1 christos buckets, increment, attributes, mask, 2573 1.1 christos dispp, NULL)); 2574 1.1 christos } 2575 1.1 christos 2576 1.1 christos /* 2577 1.1 christos * mgr should be locked. 2578 1.1 christos */ 2579 1.1 christos 2580 1.1 christos #ifndef DNS_DISPATCH_HELD 2581 1.1 christos #define DNS_DISPATCH_HELD 20U 2582 1.1 christos #endif /* ifndef DNS_DISPATCH_HELD */ 2583 1.1 christos 2584 1.1 christos static isc_result_t 2585 1.1 christos get_udpsocket(dns_dispatchmgr_t *mgr, dns_dispatch_t *disp, 2586 1.1 christos isc_socketmgr_t *sockmgr, const isc_sockaddr_t *localaddr, 2587 1.1 christos isc_socket_t **sockp, isc_socket_t *dup_socket, bool duponly) { 2588 1.1 christos unsigned int i, j; 2589 1.1 christos isc_socket_t *held[DNS_DISPATCH_HELD]; 2590 1.1 christos isc_sockaddr_t localaddr_bound; 2591 1.1 christos isc_socket_t *sock = NULL; 2592 1.1 christos isc_result_t result = ISC_R_SUCCESS; 2593 1.1 christos bool anyport; 2594 1.1 christos 2595 1.1 christos INSIST(sockp != NULL && *sockp == NULL); 2596 1.1 christos 2597 1.1 christos localaddr_bound = *localaddr; 2598 1.1 christos anyport = (isc_sockaddr_getport(localaddr) == 0); 2599 1.1 christos 2600 1.1 christos if (anyport) { 2601 1.1 christos unsigned int nports; 2602 1.1 christos in_port_t *ports; 2603 1.1 christos 2604 1.1 christos /* 2605 1.1 christos * If no port is specified, we first try to pick up a random 2606 1.1 christos * port by ourselves. 2607 1.1 christos */ 2608 1.1 christos if (isc_sockaddr_pf(localaddr) == AF_INET) { 2609 1.1 christos nports = disp->mgr->nv4ports; 2610 1.1 christos ports = disp->mgr->v4ports; 2611 1.1 christos } else { 2612 1.1 christos nports = disp->mgr->nv6ports; 2613 1.1 christos ports = disp->mgr->v6ports; 2614 1.1 christos } 2615 1.1 christos if (nports == 0) { 2616 1.1 christos return (ISC_R_ADDRNOTAVAIL); 2617 1.1 christos } 2618 1.1 christos 2619 1.1 christos for (i = 0; i < 1024; i++) { 2620 1.1 christos in_port_t prt; 2621 1.1 christos 2622 1.1 christos prt = ports[isc_random_uniform(nports)]; 2623 1.1 christos isc_sockaddr_setport(&localaddr_bound, prt); 2624 1.1 christos result = open_socket(sockmgr, &localaddr_bound, 0, 2625 1.1 christos &sock, NULL, false); 2626 1.1 christos /* 2627 1.1 christos * Continue if the port chosen is already in use 2628 1.1 christos * or the OS has reserved it. 2629 1.1 christos */ 2630 1.1 christos if (result == ISC_R_NOPERM || result == ISC_R_ADDRINUSE) 2631 1.1 christos { 2632 1.1 christos continue; 2633 1.1 christos } 2634 1.1 christos disp->localport = prt; 2635 1.1 christos *sockp = sock; 2636 1.1 christos return (result); 2637 1.1 christos } 2638 1.1 christos 2639 1.1 christos /* 2640 1.1 christos * If this fails 1024 times, we then ask the kernel for 2641 1.1 christos * choosing one. 2642 1.1 christos */ 2643 1.1 christos } else { 2644 1.1 christos /* Allow to reuse address for non-random ports. */ 2645 1.1 christos result = open_socket(sockmgr, localaddr, 2646 1.1 christos ISC_SOCKET_REUSEADDRESS, &sock, dup_socket, 2647 1.1 christos duponly); 2648 1.1 christos 2649 1.1 christos if (result == ISC_R_SUCCESS) { 2650 1.1 christos *sockp = sock; 2651 1.1 christos } 2652 1.1 christos 2653 1.1 christos return (result); 2654 1.1 christos } 2655 1.1 christos 2656 1.1 christos memset(held, 0, sizeof(held)); 2657 1.1 christos i = 0; 2658 1.1 christos 2659 1.1 christos for (j = 0; j < 0xffffU; j++) { 2660 1.1 christos result = open_socket(sockmgr, localaddr, 0, &sock, NULL, false); 2661 1.1 christos if (result != ISC_R_SUCCESS) { 2662 1.1 christos goto end; 2663 1.1 christos } else if (portavailable(mgr, sock, NULL)) { 2664 1.1 christos break; 2665 1.1 christos } 2666 1.1 christos if (held[i] != NULL) { 2667 1.1 christos isc_socket_detach(&held[i]); 2668 1.1 christos } 2669 1.1 christos held[i++] = sock; 2670 1.1 christos sock = NULL; 2671 1.1 christos if (i == DNS_DISPATCH_HELD) { 2672 1.1 christos i = 0; 2673 1.1 christos } 2674 1.1 christos } 2675 1.1 christos if (j == 0xffffU) { 2676 1.1 christos mgr_log(mgr, ISC_LOG_ERROR, 2677 1.1 christos "avoid-v%s-udp-ports: unable to allocate " 2678 1.1 christos "an available port", 2679 1.1 christos isc_sockaddr_pf(localaddr) == AF_INET ? "4" : "6"); 2680 1.1 christos result = ISC_R_FAILURE; 2681 1.1 christos goto end; 2682 1.1 christos } 2683 1.1 christos *sockp = sock; 2684 1.1 christos 2685 1.1 christos end: 2686 1.1 christos for (i = 0; i < DNS_DISPATCH_HELD; i++) { 2687 1.1 christos if (held[i] != NULL) { 2688 1.1 christos isc_socket_detach(&held[i]); 2689 1.1 christos } 2690 1.1 christos } 2691 1.1 christos 2692 1.1 christos return (result); 2693 1.1 christos } 2694 1.1 christos 2695 1.1 christos static isc_result_t 2696 1.1 christos dispatch_createudp(dns_dispatchmgr_t *mgr, isc_socketmgr_t *sockmgr, 2697 1.1 christos isc_taskmgr_t *taskmgr, const isc_sockaddr_t *localaddr, 2698 1.1 christos unsigned int maxrequests, unsigned int attributes, 2699 1.1 christos dns_dispatch_t **dispp, isc_socket_t *dup_socket) { 2700 1.1 christos isc_result_t result; 2701 1.1 christos dns_dispatch_t *disp; 2702 1.1 christos isc_socket_t *sock = NULL; 2703 1.1 christos int i = 0; 2704 1.1 christos bool duponly = ((attributes & DNS_DISPATCHATTR_CANREUSE) == 0); 2705 1.1 christos 2706 1.1 christos /* This is an attribute needed only at creation time */ 2707 1.1 christos attributes &= ~DNS_DISPATCHATTR_CANREUSE; 2708 1.1 christos /* 2709 1.1 christos * dispatch_allocate() checks mgr for us. 2710 1.1 christos */ 2711 1.1 christos disp = NULL; 2712 1.1 christos result = dispatch_allocate(mgr, maxrequests, &disp); 2713 1.1 christos if (result != ISC_R_SUCCESS) { 2714 1.1 christos return (result); 2715 1.1 christos } 2716 1.1 christos 2717 1.1 christos disp->socktype = isc_sockettype_udp; 2718 1.1 christos 2719 1.1 christos if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0) { 2720 1.1 christos result = get_udpsocket(mgr, disp, sockmgr, localaddr, &sock, 2721 1.1 christos dup_socket, duponly); 2722 1.1 christos if (result != ISC_R_SUCCESS) { 2723 1.1 christos goto deallocate_dispatch; 2724 1.1 christos } 2725 1.1 christos 2726 1.1 christos if (isc_log_wouldlog(dns_lctx, 90)) { 2727 1.1 christos char addrbuf[ISC_SOCKADDR_FORMATSIZE]; 2728 1.1 christos 2729 1.1 christos isc_sockaddr_format(localaddr, addrbuf, 2730 1.1 christos ISC_SOCKADDR_FORMATSIZE); 2731 1.1 christos mgr_log(mgr, LVL(90), 2732 1.1 christos "dns_dispatch_createudp: Created" 2733 1.1 christos " UDP dispatch for %s with socket fd %d", 2734 1.1 christos addrbuf, isc_socket_getfd(sock)); 2735 1.1 christos } 2736 1.1 christos } else { 2737 1.1 christos isc_sockaddr_t sa_any; 2738 1.1 christos 2739 1.1 christos /* 2740 1.1 christos * For dispatches using exclusive sockets with a specific 2741 1.1 christos * source address, we only check if the specified address is 2742 1.1 christos * available on the system. Query sockets will be created later 2743 1.1 christos * on demand. 2744 1.1 christos */ 2745 1.1 christos isc_sockaddr_anyofpf(&sa_any, isc_sockaddr_pf(localaddr)); 2746 1.1 christos if (!isc_sockaddr_eqaddr(&sa_any, localaddr)) { 2747 1.1 christos result = open_socket(sockmgr, localaddr, 0, &sock, NULL, 2748 1.1 christos false); 2749 1.1 christos if (sock != NULL) { 2750 1.1 christos isc_socket_detach(&sock); 2751 1.1 christos } 2752 1.1 christos if (result != ISC_R_SUCCESS) { 2753 1.1 christos goto deallocate_dispatch; 2754 1.1 christos } 2755 1.1 christos } 2756 1.1 christos 2757 1.1 christos disp->port_table = isc_mem_get( 2758 1.1 christos mgr->mctx, sizeof(disp->port_table[0]) * 2759 1.1 christos DNS_DISPATCH_PORTTABLESIZE); 2760 1.1 christos for (i = 0; i < DNS_DISPATCH_PORTTABLESIZE; i++) { 2761 1.1 christos ISC_LIST_INIT(disp->port_table[i]); 2762 1.1 christos } 2763 1.1 christos } 2764 1.1 christos disp->socket = sock; 2765 1.1 christos disp->local = *localaddr; 2766 1.1 christos 2767 1.1 christos if ((attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 2768 1.1 christos disp->ntasks = MAX_INTERNAL_TASKS; 2769 1.1 christos } else { 2770 1.1 christos disp->ntasks = 1; 2771 1.1 christos } 2772 1.1 christos for (i = 0; i < disp->ntasks; i++) { 2773 1.1 christos disp->task[i] = NULL; 2774 1.1 christos result = isc_task_create(taskmgr, 0, &disp->task[i]); 2775 1.1 christos if (result != ISC_R_SUCCESS) { 2776 1.1 christos while (--i >= 0) { 2777 1.1 christos isc_task_shutdown(disp->task[i]); 2778 1.1 christos isc_task_detach(&disp->task[i]); 2779 1.1 christos } 2780 1.1 christos goto kill_socket; 2781 1.1 christos } 2782 1.1 christos isc_task_setname(disp->task[i], "udpdispatch", disp); 2783 1.1 christos } 2784 1.1 christos 2785 1.1 christos disp->ctlevent = 2786 1.1 christos isc_event_allocate(mgr->mctx, disp, DNS_EVENT_DISPATCHCONTROL, 2787 1.1 christos destroy_disp, disp, sizeof(isc_event_t)); 2788 1.1 christos 2789 1.1 christos disp->sepool = NULL; 2790 1.1 christos isc_mem_create(&disp->sepool); 2791 1.1 christos isc_mem_setname(disp->sepool, "disp_sepool", NULL); 2792 1.1 christos 2793 1.1 christos attributes &= ~DNS_DISPATCHATTR_TCP; 2794 1.1 christos attributes |= DNS_DISPATCHATTR_UDP; 2795 1.1 christos disp->attributes = attributes; 2796 1.1 christos 2797 1.1 christos /* 2798 1.1 christos * Append it to the dispatcher list. 2799 1.1 christos */ 2800 1.1 christos ISC_LIST_APPEND(mgr->list, disp, link); 2801 1.1 christos 2802 1.1 christos mgr_log(mgr, LVL(90), "created UDP dispatcher %p", disp); 2803 1.1 christos dispatch_log(disp, LVL(90), "created task %p", disp->task[0]); /* XXX */ 2804 1.1 christos if (disp->socket != NULL) { 2805 1.1 christos dispatch_log(disp, LVL(90), "created socket %p", disp->socket); 2806 1.1 christos } 2807 1.1 christos 2808 1.1 christos *dispp = disp; 2809 1.1 christos 2810 1.1 christos return (result); 2811 1.1 christos 2812 1.1 christos /* 2813 1.1 christos * Error returns. 2814 1.1 christos */ 2815 1.1 christos kill_socket: 2816 1.1 christos if (disp->socket != NULL) { 2817 1.1 christos isc_socket_detach(&disp->socket); 2818 1.1 christos } 2819 1.1 christos deallocate_dispatch: 2820 1.1 christos dispatch_free(&disp); 2821 1.1 christos 2822 1.1 christos return (result); 2823 1.1 christos } 2824 1.1 christos 2825 1.1 christos void 2826 1.1 christos dns_dispatch_attach(dns_dispatch_t *disp, dns_dispatch_t **dispp) { 2827 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 2828 1.1 christos REQUIRE(dispp != NULL && *dispp == NULL); 2829 1.1 christos 2830 1.1 christos LOCK(&disp->lock); 2831 1.1 christos disp->refcount++; 2832 1.1 christos UNLOCK(&disp->lock); 2833 1.1 christos 2834 1.1 christos *dispp = disp; 2835 1.1 christos } 2836 1.1 christos 2837 1.1 christos /* 2838 1.1 christos * It is important to lock the manager while we are deleting the dispatch, 2839 1.1 christos * since dns_dispatch_getudp will call dispatch_find, which returns to 2840 1.1 christos * the caller a dispatch but does not attach to it until later. _getudp 2841 1.1 christos * locks the manager, however, so locking it here will keep us from attaching 2842 1.1 christos * to a dispatcher that is in the process of going away. 2843 1.1 christos */ 2844 1.1 christos void 2845 1.1 christos dns_dispatch_detach(dns_dispatch_t **dispp) { 2846 1.1 christos dns_dispatch_t *disp; 2847 1.1 christos dispsocket_t *dispsock; 2848 1.1 christos bool killit; 2849 1.1 christos 2850 1.1 christos REQUIRE(dispp != NULL && VALID_DISPATCH(*dispp)); 2851 1.1 christos 2852 1.1 christos disp = *dispp; 2853 1.1 christos *dispp = NULL; 2854 1.1 christos 2855 1.1 christos LOCK(&disp->lock); 2856 1.1 christos 2857 1.1 christos INSIST(disp->refcount > 0); 2858 1.1 christos disp->refcount--; 2859 1.1 christos if (disp->refcount == 0) { 2860 1.1 christos if (disp->recv_pending > 0) { 2861 1.1 christos isc_socket_cancel(disp->socket, disp->task[0], 2862 1.1 christos ISC_SOCKCANCEL_RECV); 2863 1.1 christos } 2864 1.1 christos for (dispsock = ISC_LIST_HEAD(disp->activesockets); 2865 1.1 christos dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) 2866 1.1 christos { 2867 1.1 christos isc_socket_cancel(dispsock->socket, dispsock->task, 2868 1.1 christos ISC_SOCKCANCEL_RECV); 2869 1.1 christos } 2870 1.1 christos disp->shutting_down = 1; 2871 1.1 christos } 2872 1.1 christos 2873 1.1 christos dispatch_log(disp, LVL(90), "detach: refcount %d", disp->refcount); 2874 1.1 christos 2875 1.1 christos killit = destroy_disp_ok(disp); 2876 1.1 christos UNLOCK(&disp->lock); 2877 1.1 christos if (killit) { 2878 1.1 christos isc_task_send(disp->task[0], &disp->ctlevent); 2879 1.1 christos } 2880 1.1 christos } 2881 1.1 christos 2882 1.1 christos isc_result_t 2883 1.1 christos dns_dispatch_addresponse(dns_dispatch_t *disp, unsigned int options, 2884 1.1 christos const isc_sockaddr_t *dest, isc_task_t *task, 2885 1.1 christos isc_taskaction_t action, void *arg, 2886 1.1 christos dns_messageid_t *idp, dns_dispentry_t **resp, 2887 1.1 christos isc_socketmgr_t *sockmgr) { 2888 1.1 christos dns_dispentry_t *res; 2889 1.1 christos unsigned int bucket; 2890 1.1 christos in_port_t localport = 0; 2891 1.1 christos dns_messageid_t id; 2892 1.1 christos int i; 2893 1.1 christos bool ok; 2894 1.1 christos dns_qid_t *qid; 2895 1.1 christos dispsocket_t *dispsocket = NULL; 2896 1.1 christos isc_result_t result; 2897 1.1 christos 2898 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 2899 1.1 christos REQUIRE(task != NULL); 2900 1.1 christos REQUIRE(dest != NULL); 2901 1.1 christos REQUIRE(resp != NULL && *resp == NULL); 2902 1.1 christos REQUIRE(idp != NULL); 2903 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 2904 1.1 christos REQUIRE(sockmgr != NULL); 2905 1.1 christos } 2906 1.1 christos 2907 1.1 christos LOCK(&disp->lock); 2908 1.1 christos 2909 1.1 christos if (disp->shutting_down == 1) { 2910 1.1 christos UNLOCK(&disp->lock); 2911 1.1 christos return (ISC_R_SHUTTINGDOWN); 2912 1.1 christos } 2913 1.1 christos 2914 1.1 christos if (disp->requests >= disp->maxrequests) { 2915 1.1 christos UNLOCK(&disp->lock); 2916 1.1 christos return (ISC_R_QUOTA); 2917 1.1 christos } 2918 1.1 christos 2919 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0 && 2920 1.1 christos disp->nsockets > DNS_DISPATCH_SOCKSQUOTA) 2921 1.1 christos { 2922 1.1 christos dispsocket_t *oldestsocket; 2923 1.1 christos dns_dispentry_t *oldestresp; 2924 1.1 christos dns_dispatchevent_t *rev; 2925 1.1 christos 2926 1.1 christos /* 2927 1.1 christos * Kill oldest outstanding query if the number of sockets 2928 1.1 christos * exceeds the quota to keep the room for new queries. 2929 1.1 christos */ 2930 1.1 christos oldestsocket = ISC_LIST_HEAD(disp->activesockets); 2931 1.1 christos oldestresp = oldestsocket->resp; 2932 1.1 christos if (oldestresp != NULL && !oldestresp->item_out) { 2933 1.1 christos rev = allocate_devent(oldestresp->disp); 2934 1.1 christos if (rev != NULL) { 2935 1.1 christos rev->buffer.base = NULL; 2936 1.1 christos rev->result = ISC_R_CANCELED; 2937 1.1 christos rev->id = oldestresp->id; 2938 1.1 christos ISC_EVENT_INIT(rev, sizeof(*rev), 0, NULL, 2939 1.1 christos DNS_EVENT_DISPATCH, 2940 1.1 christos oldestresp->action, 2941 1.1 christos oldestresp->arg, oldestresp, 2942 1.1 christos NULL, NULL); 2943 1.1 christos oldestresp->item_out = true; 2944 1.1 christos isc_task_send(oldestresp->task, 2945 1.1 christos ISC_EVENT_PTR(&rev)); 2946 1.1 christos inc_stats(disp->mgr, 2947 1.1 christos dns_resstatscounter_dispabort); 2948 1.1 christos } 2949 1.1 christos } 2950 1.1 christos 2951 1.1 christos /* 2952 1.1 christos * Move this entry to the tail so that it won't (easily) be 2953 1.1 christos * examined before actually being canceled. 2954 1.1 christos */ 2955 1.1 christos ISC_LIST_UNLINK(disp->activesockets, oldestsocket, link); 2956 1.1 christos ISC_LIST_APPEND(disp->activesockets, oldestsocket, link); 2957 1.1 christos } 2958 1.1 christos 2959 1.1 christos qid = DNS_QID(disp); 2960 1.1 christos 2961 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 2962 1.1 christos /* 2963 1.1 christos * Get a separate UDP socket with a random port number. 2964 1.1 christos */ 2965 1.1 christos result = get_dispsocket(disp, dest, sockmgr, &dispsocket, 2966 1.1 christos &localport); 2967 1.1 christos if (result != ISC_R_SUCCESS) { 2968 1.1 christos UNLOCK(&disp->lock); 2969 1.1 christos inc_stats(disp->mgr, dns_resstatscounter_dispsockfail); 2970 1.1 christos return (result); 2971 1.1 christos } 2972 1.1 christos } else { 2973 1.1 christos localport = disp->localport; 2974 1.1 christos } 2975 1.1 christos 2976 1.1 christos /* 2977 1.1 christos * Try somewhat hard to find an unique ID unless FIXEDID is set 2978 1.1 christos * in which case we use the id passed in via *idp. 2979 1.1 christos */ 2980 1.1 christos LOCK(&qid->lock); 2981 1.1 christos if ((options & DNS_DISPATCHOPT_FIXEDID) != 0) { 2982 1.1 christos id = *idp; 2983 1.1 christos } else { 2984 1.1 christos id = (dns_messageid_t)isc_random16(); 2985 1.1 christos } 2986 1.1 christos ok = false; 2987 1.1 christos i = 0; 2988 1.1 christos do { 2989 1.1 christos bucket = dns_hash(qid, dest, id, localport); 2990 1.1 christos if (entry_search(qid, dest, id, localport, bucket) == NULL) { 2991 1.1 christos ok = true; 2992 1.1 christos break; 2993 1.1 christos } 2994 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_FIXEDID) != 0) { 2995 1.1 christos break; 2996 1.1 christos } 2997 1.1 christos id += qid->qid_increment; 2998 1.1 christos id &= 0x0000ffff; 2999 1.1 christos } while (i++ < 64); 3000 1.1 christos UNLOCK(&qid->lock); 3001 1.1 christos 3002 1.1 christos if (!ok) { 3003 1.1 christos UNLOCK(&disp->lock); 3004 1.1 christos return (ISC_R_NOMORE); 3005 1.1 christos } 3006 1.1 christos 3007 1.1 christos res = isc_mem_get(disp->mgr->mctx, sizeof(*res)); 3008 1.1 christos isc_refcount_increment0(&disp->mgr->irefs); 3009 1.1 christos 3010 1.1 christos disp->refcount++; 3011 1.1 christos disp->requests++; 3012 1.1 christos res->task = NULL; 3013 1.1 christos isc_task_attach(task, &res->task); 3014 1.1 christos res->disp = disp; 3015 1.1 christos res->id = id; 3016 1.1 christos res->port = localport; 3017 1.1 christos res->bucket = bucket; 3018 1.1 christos res->host = *dest; 3019 1.1 christos res->action = action; 3020 1.1 christos res->arg = arg; 3021 1.1 christos res->dispsocket = dispsocket; 3022 1.1 christos if (dispsocket != NULL) { 3023 1.1 christos dispsocket->resp = res; 3024 1.1 christos } 3025 1.1 christos res->item_out = false; 3026 1.1 christos ISC_LIST_INIT(res->items); 3027 1.1 christos ISC_LINK_INIT(res, link); 3028 1.1 christos res->magic = RESPONSE_MAGIC; 3029 1.1 christos 3030 1.1 christos LOCK(&qid->lock); 3031 1.1 christos ISC_LIST_APPEND(qid->qid_table[bucket], res, link); 3032 1.1 christos UNLOCK(&qid->lock); 3033 1.1 christos 3034 1.1 christos inc_stats(disp->mgr, (qid == disp->mgr->qid) 3035 1.1 christos ? dns_resstatscounter_disprequdp 3036 1.1 christos : dns_resstatscounter_dispreqtcp); 3037 1.1 christos 3038 1.1 christos request_log(disp, res, LVL(90), "attached to task %p", res->task); 3039 1.1 christos 3040 1.1 christos if (((disp->attributes & DNS_DISPATCHATTR_UDP) != 0) || 3041 1.1 christos ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) != 0)) 3042 1.1 christos { 3043 1.1 christos result = startrecv(disp, dispsocket); 3044 1.1 christos if (result != ISC_R_SUCCESS) { 3045 1.1 christos LOCK(&qid->lock); 3046 1.1 christos ISC_LIST_UNLINK(qid->qid_table[bucket], res, link); 3047 1.1 christos UNLOCK(&qid->lock); 3048 1.1 christos 3049 1.1 christos if (dispsocket != NULL) { 3050 1.1 christos destroy_dispsocket(disp, &dispsocket); 3051 1.1 christos } 3052 1.1 christos 3053 1.1 christos disp->refcount--; 3054 1.1 christos disp->requests--; 3055 1.1 christos 3056 1.1 christos dec_stats(disp->mgr, 3057 1.1 christos (qid == disp->mgr->qid) 3058 1.1 christos ? dns_resstatscounter_disprequdp 3059 1.1 christos : dns_resstatscounter_dispreqtcp); 3060 1.1 christos 3061 1.1 christos UNLOCK(&disp->lock); 3062 1.1 christos isc_task_detach(&res->task); 3063 1.1 christos isc_refcount_decrement(&disp->mgr->irefs); 3064 1.1 christos isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); 3065 1.1 christos return (result); 3066 1.1 christos } 3067 1.1 christos } 3068 1.1 christos 3069 1.1 christos if (dispsocket != NULL) { 3070 1.1 christos ISC_LIST_APPEND(disp->activesockets, dispsocket, link); 3071 1.1 christos } 3072 1.1 christos 3073 1.1 christos UNLOCK(&disp->lock); 3074 1.1 christos 3075 1.1 christos *idp = id; 3076 1.1 christos *resp = res; 3077 1.1 christos 3078 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) != 0) { 3079 1.1 christos INSIST(res->dispsocket != NULL); 3080 1.1 christos } 3081 1.1 christos 3082 1.1 christos return (ISC_R_SUCCESS); 3083 1.1 christos } 3084 1.1 christos 3085 1.1 christos void 3086 1.1 christos dns_dispatch_starttcp(dns_dispatch_t *disp) { 3087 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3088 1.1 christos 3089 1.1 christos dispatch_log(disp, LVL(90), "starttcp %p", disp->task[0]); 3090 1.1 christos 3091 1.1 christos LOCK(&disp->lock); 3092 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_CONNECTED) == 0) { 3093 1.1 christos disp->attributes |= DNS_DISPATCHATTR_CONNECTED; 3094 1.1 christos (void)startrecv(disp, NULL); 3095 1.1 christos } 3096 1.1 christos UNLOCK(&disp->lock); 3097 1.1 christos } 3098 1.1 christos 3099 1.1 christos isc_result_t 3100 1.1 christos dns_dispatch_getnext(dns_dispentry_t *resp, dns_dispatchevent_t **sockevent) { 3101 1.1 christos dns_dispatch_t *disp; 3102 1.1 christos dns_dispatchevent_t *ev; 3103 1.1 christos 3104 1.1 christos REQUIRE(VALID_RESPONSE(resp)); 3105 1.1 christos REQUIRE(sockevent != NULL && *sockevent != NULL); 3106 1.1 christos 3107 1.1 christos disp = resp->disp; 3108 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3109 1.1 christos 3110 1.1 christos ev = *sockevent; 3111 1.1 christos *sockevent = NULL; 3112 1.1 christos 3113 1.1 christos LOCK(&disp->lock); 3114 1.1 christos 3115 1.1 christos REQUIRE(resp->item_out); 3116 1.1 christos resp->item_out = false; 3117 1.1 christos 3118 1.1 christos if (ev->buffer.base != NULL) { 3119 1.1 christos free_buffer(disp, ev->buffer.base, ev->buffer.length); 3120 1.1 christos } 3121 1.1 christos free_devent(disp, ev); 3122 1.1 christos 3123 1.1 christos if (disp->shutting_down == 1) { 3124 1.1 christos UNLOCK(&disp->lock); 3125 1.1 christos return (ISC_R_SHUTTINGDOWN); 3126 1.1 christos } 3127 1.1 christos ev = ISC_LIST_HEAD(resp->items); 3128 1.1 christos if (ev != NULL) { 3129 1.1 christos ISC_LIST_UNLINK(resp->items, ev, ev_link); 3130 1.1 christos ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH, 3131 1.1 christos resp->action, resp->arg, resp, NULL, NULL); 3132 1.1 christos request_log(disp, resp, LVL(90), 3133 1.1 christos "[c] Sent event %p buffer %p len %d to task %p", ev, 3134 1.1 christos ev->buffer.base, ev->buffer.length, resp->task); 3135 1.1 christos resp->item_out = true; 3136 1.1 christos isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); 3137 1.1 christos } 3138 1.1 christos UNLOCK(&disp->lock); 3139 1.1 christos return (ISC_R_SUCCESS); 3140 1.1 christos } 3141 1.1 christos 3142 1.1 christos void 3143 1.1 christos dns_dispatch_removeresponse(dns_dispentry_t **resp, 3144 1.1 christos dns_dispatchevent_t **sockevent) { 3145 1.1 christos dns_dispatchmgr_t *mgr; 3146 1.1 christos dns_dispatch_t *disp; 3147 1.1 christos dns_dispentry_t *res; 3148 1.1 christos dispsocket_t *dispsock; 3149 1.1 christos dns_dispatchevent_t *ev; 3150 1.1 christos unsigned int bucket; 3151 1.1 christos bool killit; 3152 1.1 christos unsigned int n; 3153 1.1 christos isc_eventlist_t events; 3154 1.1 christos dns_qid_t *qid; 3155 1.1 christos 3156 1.1 christos REQUIRE(resp != NULL); 3157 1.1 christos REQUIRE(VALID_RESPONSE(*resp)); 3158 1.1 christos 3159 1.1 christos res = *resp; 3160 1.1 christos *resp = NULL; 3161 1.1 christos 3162 1.1 christos disp = res->disp; 3163 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3164 1.1 christos mgr = disp->mgr; 3165 1.1 christos REQUIRE(VALID_DISPATCHMGR(mgr)); 3166 1.1 christos 3167 1.1 christos qid = DNS_QID(disp); 3168 1.1 christos 3169 1.1 christos if (sockevent != NULL) { 3170 1.1 christos REQUIRE(*sockevent != NULL); 3171 1.1 christos ev = *sockevent; 3172 1.1 christos *sockevent = NULL; 3173 1.1 christos } else { 3174 1.1 christos ev = NULL; 3175 1.1 christos } 3176 1.1 christos 3177 1.1 christos LOCK(&disp->lock); 3178 1.1 christos 3179 1.1 christos INSIST(disp->requests > 0); 3180 1.1 christos disp->requests--; 3181 1.1 christos dec_stats(disp->mgr, (qid == disp->mgr->qid) 3182 1.1 christos ? dns_resstatscounter_disprequdp 3183 1.1 christos : dns_resstatscounter_dispreqtcp); 3184 1.1 christos INSIST(disp->refcount > 0); 3185 1.1 christos disp->refcount--; 3186 1.1 christos if (disp->refcount == 0) { 3187 1.1 christos if (disp->recv_pending > 0) { 3188 1.1 christos isc_socket_cancel(disp->socket, disp->task[0], 3189 1.1 christos ISC_SOCKCANCEL_RECV); 3190 1.1 christos } 3191 1.1 christos for (dispsock = ISC_LIST_HEAD(disp->activesockets); 3192 1.1 christos dispsock != NULL; dispsock = ISC_LIST_NEXT(dispsock, link)) 3193 1.1 christos { 3194 1.1 christos isc_socket_cancel(dispsock->socket, dispsock->task, 3195 1.1 christos ISC_SOCKCANCEL_RECV); 3196 1.1 christos } 3197 1.1 christos disp->shutting_down = 1; 3198 1.1 christos } 3199 1.1 christos 3200 1.1 christos bucket = res->bucket; 3201 1.1 christos 3202 1.1 christos LOCK(&qid->lock); 3203 1.1 christos ISC_LIST_UNLINK(qid->qid_table[bucket], res, link); 3204 1.1 christos UNLOCK(&qid->lock); 3205 1.1 christos 3206 1.1 christos if (ev == NULL && res->item_out) { 3207 1.1 christos /* 3208 1.1 christos * We've posted our event, but the caller hasn't gotten it 3209 1.1 christos * yet. Take it back. 3210 1.1 christos */ 3211 1.1 christos ISC_LIST_INIT(events); 3212 1.1 christos n = isc_task_unsend(res->task, res, DNS_EVENT_DISPATCH, NULL, 3213 1.1 christos &events); 3214 1.1 christos /* 3215 1.1 christos * We had better have gotten it back. 3216 1.1 christos */ 3217 1.1 christos INSIST(n == 1); 3218 1.1 christos ev = (dns_dispatchevent_t *)ISC_LIST_HEAD(events); 3219 1.1 christos } 3220 1.1 christos 3221 1.1 christos if (ev != NULL) { 3222 1.1 christos REQUIRE(res->item_out); 3223 1.1 christos res->item_out = false; 3224 1.1 christos if (ev->buffer.base != NULL) { 3225 1.1 christos free_buffer(disp, ev->buffer.base, ev->buffer.length); 3226 1.1 christos } 3227 1.1 christos free_devent(disp, ev); 3228 1.1 christos } 3229 1.1 christos 3230 1.1 christos request_log(disp, res, LVL(90), "detaching from task %p", res->task); 3231 1.1 christos isc_task_detach(&res->task); 3232 1.1 christos 3233 1.1 christos if (res->dispsocket != NULL) { 3234 1.1 christos isc_socket_cancel(res->dispsocket->socket, 3235 1.1 christos res->dispsocket->task, ISC_SOCKCANCEL_RECV); 3236 1.1 christos res->dispsocket->resp = NULL; 3237 1.1 christos } 3238 1.1 christos 3239 1.1 christos /* 3240 1.1 christos * Free any buffered responses as well 3241 1.1 christos */ 3242 1.1 christos ev = ISC_LIST_HEAD(res->items); 3243 1.1 christos while (ev != NULL) { 3244 1.1 christos ISC_LIST_UNLINK(res->items, ev, ev_link); 3245 1.1 christos if (ev->buffer.base != NULL) { 3246 1.1 christos free_buffer(disp, ev->buffer.base, ev->buffer.length); 3247 1.1 christos } 3248 1.1 christos free_devent(disp, ev); 3249 1.1 christos ev = ISC_LIST_HEAD(res->items); 3250 1.1 christos } 3251 1.1 christos res->magic = 0; 3252 1.1 christos isc_refcount_decrement(&disp->mgr->irefs); 3253 1.1 christos isc_mem_put(disp->mgr->mctx, res, sizeof(*res)); 3254 1.1 christos if (disp->shutting_down == 1) { 3255 1.1 christos do_cancel(disp); 3256 1.1 christos } else { 3257 1.1 christos (void)startrecv(disp, NULL); 3258 1.1 christos } 3259 1.1 christos 3260 1.1 christos killit = destroy_disp_ok(disp); 3261 1.1 christos UNLOCK(&disp->lock); 3262 1.1 christos if (killit) { 3263 1.1 christos isc_task_send(disp->task[0], &disp->ctlevent); 3264 1.1 christos } 3265 1.1 christos } 3266 1.1 christos 3267 1.1 christos /* 3268 1.1 christos * disp must be locked. 3269 1.1 christos */ 3270 1.1 christos static void 3271 1.1 christos do_cancel(dns_dispatch_t *disp) { 3272 1.1 christos dns_dispatchevent_t *ev; 3273 1.1 christos dns_dispentry_t *resp; 3274 1.1 christos dns_qid_t *qid; 3275 1.1 christos 3276 1.1 christos if (disp->shutdown_out == 1) { 3277 1.1 christos return; 3278 1.1 christos } 3279 1.1 christos 3280 1.1 christos qid = DNS_QID(disp); 3281 1.1 christos 3282 1.1 christos /* 3283 1.1 christos * Search for the first response handler without packets outstanding 3284 1.1 christos * unless a specific handler is given. 3285 1.1 christos */ 3286 1.1 christos LOCK(&qid->lock); 3287 1.1 christos for (resp = linear_first(qid); resp != NULL && resp->item_out; 3288 1.1 christos /* Empty. */) 3289 1.1 christos { 3290 1.1 christos resp = linear_next(qid, resp); 3291 1.1 christos } 3292 1.1 christos 3293 1.1 christos /* 3294 1.1 christos * No one to send the cancel event to, so nothing to do. 3295 1.1 christos */ 3296 1.1 christos if (resp == NULL) { 3297 1.1 christos goto unlock; 3298 1.1 christos } 3299 1.1 christos 3300 1.1 christos /* 3301 1.1 christos * Send the shutdown failsafe event to this resp. 3302 1.1 christos */ 3303 1.1 christos ev = disp->failsafe_ev; 3304 1.1 christos ISC_EVENT_INIT(ev, sizeof(*ev), 0, NULL, DNS_EVENT_DISPATCH, 3305 1.1 christos resp->action, resp->arg, resp, NULL, NULL); 3306 1.1 christos ev->result = disp->shutdown_why; 3307 1.1 christos ev->buffer.base = NULL; 3308 1.1 christos ev->buffer.length = 0; 3309 1.1 christos disp->shutdown_out = 1; 3310 1.1 christos request_log(disp, resp, LVL(10), "cancel: failsafe event %p -> task %p", 3311 1.1 christos ev, resp->task); 3312 1.1 christos resp->item_out = true; 3313 1.1 christos isc_task_send(resp->task, ISC_EVENT_PTR(&ev)); 3314 1.1 christos unlock: 3315 1.1 christos UNLOCK(&qid->lock); 3316 1.1 christos } 3317 1.1 christos 3318 1.1 christos isc_socket_t * 3319 1.1 christos dns_dispatch_getsocket(dns_dispatch_t *disp) { 3320 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3321 1.1 christos 3322 1.1 christos return (disp->socket); 3323 1.1 christos } 3324 1.1 christos 3325 1.1 christos isc_socket_t * 3326 1.1 christos dns_dispatch_getentrysocket(dns_dispentry_t *resp) { 3327 1.1 christos REQUIRE(VALID_RESPONSE(resp)); 3328 1.1 christos 3329 1.1 christos if (resp->dispsocket != NULL) { 3330 1.1 christos return (resp->dispsocket->socket); 3331 1.1 christos } else { 3332 1.1 christos return (NULL); 3333 1.1 christos } 3334 1.1 christos } 3335 1.1 christos 3336 1.1 christos isc_result_t 3337 1.1 christos dns_dispatch_getlocaladdress(dns_dispatch_t *disp, isc_sockaddr_t *addrp) { 3338 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3339 1.1 christos REQUIRE(addrp != NULL); 3340 1.1 christos 3341 1.1 christos if (disp->socktype == isc_sockettype_udp) { 3342 1.1 christos *addrp = disp->local; 3343 1.1 christos return (ISC_R_SUCCESS); 3344 1.1 christos } 3345 1.1 christos return (ISC_R_NOTIMPLEMENTED); 3346 1.1 christos } 3347 1.1 christos 3348 1.1 christos void 3349 1.1 christos dns_dispatch_cancel(dns_dispatch_t *disp) { 3350 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3351 1.1 christos 3352 1.1 christos LOCK(&disp->lock); 3353 1.1 christos 3354 1.1 christos if (disp->shutting_down == 1) { 3355 1.1 christos UNLOCK(&disp->lock); 3356 1.1 christos return; 3357 1.1 christos } 3358 1.1 christos 3359 1.1 christos disp->shutdown_why = ISC_R_CANCELED; 3360 1.1 christos disp->shutting_down = 1; 3361 1.1 christos do_cancel(disp); 3362 1.1 christos 3363 1.1 christos UNLOCK(&disp->lock); 3364 1.1 christos 3365 1.1 christos return; 3366 1.1 christos } 3367 1.1 christos 3368 1.1 christos unsigned int 3369 1.1 christos dns_dispatch_getattributes(dns_dispatch_t *disp) { 3370 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3371 1.1 christos 3372 1.1 christos /* 3373 1.1 christos * We don't bother locking disp here; it's the caller's responsibility 3374 1.1 christos * to use only non volatile flags. 3375 1.1 christos */ 3376 1.1 christos return (disp->attributes); 3377 1.1 christos } 3378 1.1 christos 3379 1.1 christos void 3380 1.1 christos dns_dispatch_changeattributes(dns_dispatch_t *disp, unsigned int attributes, 3381 1.1 christos unsigned int mask) { 3382 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3383 1.1 christos /* Exclusive attribute can only be set on creation */ 3384 1.1 christos REQUIRE((attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0); 3385 1.1 christos /* Also, a dispatch with randomport specified cannot start listening */ 3386 1.1 christos REQUIRE((disp->attributes & DNS_DISPATCHATTR_EXCLUSIVE) == 0 || 3387 1.1 christos (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0); 3388 1.1 christos 3389 1.1 christos /* XXXMLG 3390 1.1 christos * Should check for valid attributes here! 3391 1.1 christos */ 3392 1.1 christos 3393 1.1 christos LOCK(&disp->lock); 3394 1.1 christos 3395 1.1 christos if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) { 3396 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) != 0 && 3397 1.1 christos (attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) 3398 1.1 christos { 3399 1.1 christos disp->attributes &= ~DNS_DISPATCHATTR_NOLISTEN; 3400 1.1 christos (void)startrecv(disp, NULL); 3401 1.1 christos } else if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 3402 1.1 christos 0 && 3403 1.1 christos (attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) 3404 1.1 christos { 3405 1.1 christos disp->attributes |= DNS_DISPATCHATTR_NOLISTEN; 3406 1.1 christos if (disp->recv_pending != 0) { 3407 1.1 christos isc_socket_cancel(disp->socket, disp->task[0], 3408 1.1 christos ISC_SOCKCANCEL_RECV); 3409 1.1 christos } 3410 1.1 christos } 3411 1.1 christos } 3412 1.1 christos 3413 1.1 christos disp->attributes &= ~mask; 3414 1.1 christos disp->attributes |= (attributes & mask); 3415 1.1 christos UNLOCK(&disp->lock); 3416 1.1 christos } 3417 1.1 christos 3418 1.1 christos void 3419 1.1 christos dns_dispatch_importrecv(dns_dispatch_t *disp, isc_event_t *event) { 3420 1.1 christos void *buf; 3421 1.1 christos isc_socketevent_t *sevent, *newsevent; 3422 1.1 christos 3423 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3424 1.1 christos REQUIRE(event != NULL); 3425 1.1 christos 3426 1.1 christos if ((disp->attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) { 3427 1.1 christos return; 3428 1.1 christos } 3429 1.1 christos 3430 1.1 christos sevent = (isc_socketevent_t *)event; 3431 1.1 christos INSIST(sevent->n <= disp->mgr->buffersize); 3432 1.1 christos 3433 1.1 christos newsevent = (isc_socketevent_t *)isc_event_allocate( 3434 1.1 christos disp->mgr->mctx, NULL, DNS_EVENT_IMPORTRECVDONE, udp_shrecv, 3435 1.1 christos disp, sizeof(isc_socketevent_t)); 3436 1.1 christos 3437 1.1 christos buf = allocate_udp_buffer(disp); 3438 1.1 christos if (buf == NULL) { 3439 1.1 christos isc_event_free(ISC_EVENT_PTR(&newsevent)); 3440 1.1 christos return; 3441 1.1 christos } 3442 1.1 christos memmove(buf, sevent->region.base, sevent->n); 3443 1.1 christos newsevent->region.base = buf; 3444 1.1 christos newsevent->region.length = disp->mgr->buffersize; 3445 1.1 christos newsevent->n = sevent->n; 3446 1.1 christos newsevent->result = sevent->result; 3447 1.1 christos newsevent->address = sevent->address; 3448 1.1 christos newsevent->timestamp = sevent->timestamp; 3449 1.1 christos newsevent->pktinfo = sevent->pktinfo; 3450 1.1 christos newsevent->attributes = sevent->attributes; 3451 1.1 christos 3452 1.1 christos isc_task_send(disp->task[0], ISC_EVENT_PTR(&newsevent)); 3453 1.1 christos } 3454 1.1 christos 3455 1.1 christos dns_dispatch_t * 3456 1.1 christos dns_dispatchset_get(dns_dispatchset_t *dset) { 3457 1.1 christos dns_dispatch_t *disp; 3458 1.1 christos 3459 1.1 christos /* check that dispatch set is configured */ 3460 1.1 christos if (dset == NULL || dset->ndisp == 0) { 3461 1.1 christos return (NULL); 3462 1.1 christos } 3463 1.1 christos 3464 1.1 christos LOCK(&dset->lock); 3465 1.1 christos disp = dset->dispatches[dset->cur]; 3466 1.1 christos dset->cur++; 3467 1.1 christos if (dset->cur == dset->ndisp) { 3468 1.1 christos dset->cur = 0; 3469 1.1 christos } 3470 1.1 christos UNLOCK(&dset->lock); 3471 1.1 christos 3472 1.1 christos return (disp); 3473 1.1 christos } 3474 1.1 christos 3475 1.1 christos isc_result_t 3476 1.1 christos dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, 3477 1.1 christos isc_taskmgr_t *taskmgr, dns_dispatch_t *source, 3478 1.1 christos dns_dispatchset_t **dsetp, int n) { 3479 1.1 christos isc_result_t result; 3480 1.1 christos dns_dispatchset_t *dset; 3481 1.1 christos dns_dispatchmgr_t *mgr; 3482 1.1 christos int i, j; 3483 1.1 christos 3484 1.1 christos REQUIRE(VALID_DISPATCH(source)); 3485 1.1 christos REQUIRE((source->attributes & DNS_DISPATCHATTR_UDP) != 0); 3486 1.1 christos REQUIRE(dsetp != NULL && *dsetp == NULL); 3487 1.1 christos 3488 1.1 christos mgr = source->mgr; 3489 1.1 christos 3490 1.1 christos dset = isc_mem_get(mctx, sizeof(dns_dispatchset_t)); 3491 1.1 christos memset(dset, 0, sizeof(*dset)); 3492 1.1 christos 3493 1.1 christos isc_mutex_init(&dset->lock); 3494 1.1 christos 3495 1.1 christos dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n); 3496 1.1 christos 3497 1.1 christos isc_mem_attach(mctx, &dset->mctx); 3498 1.1 christos dset->ndisp = n; 3499 1.1 christos dset->cur = 0; 3500 1.1 christos 3501 1.1 christos dset->dispatches[0] = NULL; 3502 1.1 christos dns_dispatch_attach(source, &dset->dispatches[0]); 3503 1.1 christos 3504 1.1 christos LOCK(&mgr->lock); 3505 1.1 christos for (i = 1; i < n; i++) { 3506 1.1 christos dset->dispatches[i] = NULL; 3507 1.1 christos result = dispatch_createudp( 3508 1.1 christos mgr, sockmgr, taskmgr, &source->local, 3509 1.1 christos source->maxrequests, source->attributes, 3510 1.1 christos &dset->dispatches[i], source->socket); 3511 1.1 christos if (result != ISC_R_SUCCESS) { 3512 1.1 christos goto fail; 3513 1.1 christos } 3514 1.1 christos } 3515 1.1 christos 3516 1.1 christos UNLOCK(&mgr->lock); 3517 1.1 christos *dsetp = dset; 3518 1.1 christos 3519 1.1 christos return (ISC_R_SUCCESS); 3520 1.1 christos 3521 1.1 christos fail: 3522 1.1 christos UNLOCK(&mgr->lock); 3523 1.1 christos 3524 1.1 christos for (j = 0; j < i; j++) { 3525 1.1 christos dns_dispatch_detach(&(dset->dispatches[j])); 3526 1.1 christos } 3527 1.1 christos isc_mem_put(mctx, dset->dispatches, sizeof(dns_dispatch_t *) * n); 3528 1.1 christos if (dset->mctx == mctx) { 3529 1.1 christos isc_mem_detach(&dset->mctx); 3530 1.1 christos } 3531 1.1 christos 3532 1.1 christos isc_mutex_destroy(&dset->lock); 3533 1.1 christos isc_mem_put(mctx, dset, sizeof(dns_dispatchset_t)); 3534 1.1 christos return (result); 3535 1.1 christos } 3536 1.1 christos 3537 1.1 christos void 3538 1.1 christos dns_dispatchset_cancelall(dns_dispatchset_t *dset, isc_task_t *task) { 3539 1.1 christos int i; 3540 1.1 christos 3541 1.1 christos REQUIRE(dset != NULL); 3542 1.1 christos 3543 1.1 christos for (i = 0; i < dset->ndisp; i++) { 3544 1.1 christos isc_socket_t *sock; 3545 1.1 christos sock = dns_dispatch_getsocket(dset->dispatches[i]); 3546 1.1 christos isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); 3547 1.1 christos } 3548 1.1 christos } 3549 1.1 christos 3550 1.1 christos void 3551 1.1 christos dns_dispatchset_destroy(dns_dispatchset_t **dsetp) { 3552 1.1 christos dns_dispatchset_t *dset; 3553 1.1 christos int i; 3554 1.1 christos 3555 1.1 christos REQUIRE(dsetp != NULL && *dsetp != NULL); 3556 1.1 christos 3557 1.1 christos dset = *dsetp; 3558 1.1 christos *dsetp = NULL; 3559 1.1 christos for (i = 0; i < dset->ndisp; i++) { 3560 1.1 christos dns_dispatch_detach(&(dset->dispatches[i])); 3561 1.1 christos } 3562 1.1 christos isc_mem_put(dset->mctx, dset->dispatches, 3563 1.1 christos sizeof(dns_dispatch_t *) * dset->ndisp); 3564 1.1 christos isc_mutex_destroy(&dset->lock); 3565 1.1 christos isc_mem_putanddetach(&dset->mctx, dset, sizeof(dns_dispatchset_t)); 3566 1.1 christos } 3567 1.1 christos 3568 1.1 christos void 3569 1.1 christos dns_dispatch_setdscp(dns_dispatch_t *disp, isc_dscp_t dscp) { 3570 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3571 1.1 christos disp->dscp = dscp; 3572 1.1 christos } 3573 1.1 christos 3574 1.1 christos isc_dscp_t 3575 1.1 christos dns_dispatch_getdscp(dns_dispatch_t *disp) { 3576 1.1 christos REQUIRE(VALID_DISPATCH(disp)); 3577 1.1 christos return (disp->dscp); 3578 1.1 christos } 3579 1.1 christos 3580 1.1 christos #if 0 3581 1.1 christos void 3582 1.1 christos dns_dispatchmgr_dump(dns_dispatchmgr_t *mgr) { 3583 1.1 christos dns_dispatch_t *disp; 3584 1.1 christos char foo[1024]; 3585 1.1 christos 3586 1.1 christos disp = ISC_LIST_HEAD(mgr->list); 3587 1.1 christos while (disp != NULL) { 3588 1.1 christos isc_sockaddr_format(&disp->local, foo, sizeof(foo)); 3589 1.1 christos printf("\tdispatch %p, addr %s\n", disp, foo); 3590 1.1 christos disp = ISC_LIST_NEXT(disp, link); 3591 1.1 christos } 3592 1.1 christos } 3593 1.1 christos #endif /* if 0 */ 3594