diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c index b405de55ee..ac0479f4d5 100644 --- a/bin/named/interfacemgr.c +++ b/bin/named/interfacemgr.c @@ -150,7 +150,8 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, */ ifp->udpdispatch = NULL; result = dns_dispatch_create(mgr->mctx, ifp->udpsocket, ifp->task, - 4096, 50, 50, 17, 19, &ifp->udpdispatch); + 4096, 50, 50, 17, 19, NULL, + &ifp->udpdispatch); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "UDP dns_dispatch_create(): %s", diff --git a/bin/tests/dispatch_tcp_test.c b/bin/tests/dispatch_tcp_test.c index 03a78c0d94..8be667023a 100644 --- a/bin/tests/dispatch_tcp_test.c +++ b/bin/tests/dispatch_tcp_test.c @@ -107,7 +107,7 @@ my_accept(isc_task_t *task, isc_event_t *ev_in) */ disp = NULL; RUNTIME_CHECK(dns_dispatch_create(mctx, ev->newsocket, task, - 512, 6, 1024, 17, 19, &disp) + 512, 6, 1024, 17, 19, NULL, &disp) == ISC_R_SUCCESS); resp = NULL; diff --git a/bin/tests/dispatch_test.c b/bin/tests/dispatch_test.c index 6a2d1be625..f84dd74413 100644 --- a/bin/tests/dispatch_test.c +++ b/bin/tests/dispatch_test.c @@ -405,7 +405,8 @@ main(int argc, char *argv[]) */ disp = NULL; RUNTIME_CHECK(dns_dispatch_create(mctx, s0, t0, 512, 6, 1024, - 17, 19, &disp) == ISC_R_SUCCESS); + 17, 19, NULL, &disp) + == ISC_R_SUCCESS); RUNTIME_CHECK(isc_mutex_init(&client_lock) == ISC_R_SUCCESS); RUNTIME_CHECK(isc_mutex_lock(&client_lock) == ISC_R_SUCCESS); diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c index a350ad9ef7..4962ed6767 100644 --- a/lib/dns/dispatch.c +++ b/lib/dns/dispatch.c @@ -45,7 +45,7 @@ struct dns_dispentry { unsigned int magic; - dns_messageid_t id; + isc_uint32_t id; unsigned int bucket; isc_sockaddr_t host; isc_task_t *task; @@ -87,6 +87,7 @@ struct dns_dispatch { ISC_LIST(dns_dispentry_t) rq_handlers; /* request handler list */ ISC_LIST(dns_dispatchevent_t) rq_events; /* holder for rq events */ dns_tcpmsg_t tcpmsg; /* for tcp streams */ + dns_dispatchmethods_t methods; /* methods to use */ isc_lfsr_t qid_lfsr1; /* state generator info */ isc_lfsr_t qid_lfsr2; /* state generator info */ unsigned int qid_nbuckets; /* hash table size */ @@ -112,8 +113,8 @@ static void destroy(dns_dispatch_t *); static void udp_recv(isc_task_t *, isc_event_t *); static void tcp_recv(isc_task_t *, isc_event_t *); static inline void startrecv(dns_dispatch_t *); -static dns_messageid_t randomid(dns_dispatch_t *); -static unsigned int hash(dns_dispatch_t *, isc_sockaddr_t *, dns_messageid_t); +static isc_uint32_t dns_randomid(dns_dispatch_t *); +static isc_uint32_t dns_hash(dns_dispatch_t *, isc_sockaddr_t *, isc_uint32_t); static void free_buffer(dns_dispatch_t *disp, void *buf, unsigned int len); static void *allocate_buffer(dns_dispatch_t *disp, unsigned int len); static inline void free_event(dns_dispatch_t *disp, dns_dispatchevent_t *ev); @@ -138,16 +139,38 @@ reseed_lfsr(isc_lfsr_t *lfsr, void *arg) /* * Return an unpredictable message ID. */ -static inline dns_messageid_t -randomid(dns_dispatch_t *disp) +static isc_uint32_t +dns_randomid(dns_dispatch_t *disp) { isc_uint32_t id; id = isc_lfsr_generate32(&disp->qid_lfsr1, &disp->qid_lfsr2); - return ((dns_messageid_t)(id & 0x0000ffff)); + return (id & 0x0000ffffU); } +/* + * Return a hash of the destination and message id. + */ +static isc_uint32_t +dns_hash(dns_dispatch_t *disp, isc_sockaddr_t *dest, isc_uint32_t id) +{ + unsigned int ret; + + ret = isc_sockaddr_hash(dest, ISC_TRUE); + ret ^= (id & 0x0000ffff); /* important to mask off garbage bits */ + ret %= disp->qid_nbuckets; + + INSIST(ret < disp->qid_nbuckets); + + return (ret); +} + +static dns_dispatchmethods_t dns_wire_methods = { + dns_randomid, + dns_hash +}; + static dns_dispentry_t * linear_first(dns_dispatch_t *disp) { @@ -187,23 +210,6 @@ linear_next(dns_dispatch_t *disp, dns_dispentry_t *resp) return (NULL); } -/* - * Return a hash of the destination and message id. - */ -static unsigned int -hash(dns_dispatch_t *disp, isc_sockaddr_t *dest, dns_messageid_t id) -{ - unsigned int ret; - - ret = isc_sockaddr_hash(dest, ISC_TRUE); - ret ^= (id & 0x0000ffff); /* important to mask off garbage bits */ - ret %= disp->qid_nbuckets; - - INSIST(ret < disp->qid_nbuckets); - - return (ret); -} - /* * Called when refcount reaches 0 (and safe to destroy) */ @@ -476,7 +482,7 @@ udp_recv(isc_task_t *task, isc_event_t *ev_in) /* query */ } else { /* response */ - bucket = hash(disp, &ev->address, id); + bucket = disp->methods.hash(disp, &ev->address, id); resp = bucket_search(disp, &ev->address, id, bucket); XDEBUG(("Search for response in bucket %d: %s\n", bucket, (resp == NULL ? "NOT FOUND" : "FOUND"))); @@ -662,7 +668,7 @@ tcp_recv(isc_task_t *task, isc_event_t *ev_in) /* query */ } else { /* response */ - bucket = hash(disp, &tcpmsg->address, id); + bucket = disp->methods.hash(disp, &tcpmsg->address, id); resp = bucket_search(disp, &tcpmsg->address, id, bucket); XDEBUG(("Search for response in bucket %d: %s\n", bucket, (resp == NULL ? "NOT FOUND" : "FOUND"))); @@ -785,6 +791,7 @@ dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, unsigned int maxbuffersize, unsigned int maxbuffers, unsigned int maxrequests, unsigned int buckets, unsigned int increment, + dns_dispatchmethods_t *methods, dns_dispatch_t **dispp) { dns_dispatch_t *disp; @@ -831,6 +838,11 @@ dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, ISC_LIST_INIT(disp->rq_handlers); ISC_LIST_INIT(disp->rq_events); + if (methods == NULL) + disp->methods = dns_wire_methods; + else + disp->methods = *methods; + disp->qid_table = isc_mem_get(disp->mctx, buckets * sizeof(dns_displist_t)); if (disp->qid_table == NULL) { @@ -1023,8 +1035,8 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest, /* * Try somewhat hard to find an unique ID. */ - id = randomid(disp); - bucket = hash(disp, dest, id); + id = disp->methods.randomid(disp); + bucket = disp->methods.hash(disp, dest, id); ok = ISC_FALSE; for (i = 0 ; i < 64 ; i++) { if (bucket_search(disp, dest, id, bucket) == NULL) { @@ -1033,7 +1045,7 @@ dns_dispatch_addresponse(dns_dispatch_t *disp, isc_sockaddr_t *dest, } id += disp->qid_increment; id &= 0x0000ffff; - bucket = hash(disp, dest, id); + bucket = disp->methods.hash(disp, dest, id); } if (!ok) { diff --git a/lib/dns/include/dns/dispatch.h b/lib/dns/include/dns/dispatch.h index 35d80a97b6..ea975448b6 100644 --- a/lib/dns/include/dns/dispatch.h +++ b/lib/dns/include/dns/dispatch.h @@ -82,16 +82,32 @@ ISC_LANG_BEGINDECLS struct dns_dispatchevent { ISC_EVENT_COMMON(dns_dispatchevent_t); /* standard event common */ isc_result_t result; /* result code */ - isc_int16_t id; /* message id */ + isc_int32_t id; /* message id */ isc_sockaddr_t addr; /* address recv'd from */ isc_buffer_t buffer; /* data buffer */ }; +/* + * Functions to: + * + * Return if a packet is a query or a response, + * Hash IDs, + * Generate a new random ID, + * Compare entries (IDs) for equality, + */ +struct dns_dispatchmethods { + isc_uint32_t (*randomid)(dns_dispatch_t *); + isc_uint32_t (*hash)(dns_dispatch_t *, isc_sockaddr_t *, + isc_uint32_t); +}; +typedef struct dns_dispatchmethods dns_dispatchmethods_t; + isc_result_t dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, unsigned int maxbuffersize, unsigned int maxbuffers, unsigned int maxrequests, unsigned int buckets, unsigned int increment, + dns_dispatchmethods_t *methods, dns_dispatch_t **dispp); /* * Create a new dns_dispatch and attach it to the provided isc_socket_t. @@ -108,6 +124,10 @@ dns_dispatch_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task, * "increment" is used in a collision avoidance function, and needs to be * a prime > buckets, and not 2. * + * "methods" be NULL for normal DNS wire format, or all elements in that + * structure be filled in with function pointers to control dispatch + * behavior. + * * Requires: * * mctx is a valid memory context. diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 87e4524fee..99c77db96d 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -593,7 +593,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, if (result != ISC_R_SUCCESS) goto cleanup_query; result = dns_dispatch_create(res->mctx, socket, task, - 4096, 2, 1, 1, 3, + 4096, 2, 1, 1, 3, NULL, &query->dispatch); /* * Regardless of whether dns_dispatch_create() succeeded or @@ -3296,7 +3296,7 @@ dns_resolver_create(dns_view_t *view, } result = dns_dispatch_create(res->mctx, res->udpsocket4, res->buckets[0].task, 4096, - 1000, 32768, 16411, 16433, + 1000, 32768, 16411, 16433, NULL, &res->dispatch4); if (result != ISC_R_SUCCESS) goto cleanup_udpsocket4; @@ -3318,7 +3318,7 @@ dns_resolver_create(dns_view_t *view, goto cleanup_dispatch4; result = dns_dispatch_create(res->mctx, res->udpsocket6, res->buckets[0].task, 4096, - 1000, 32768, 16411, 16433, + 1000, 32768, 16411, 16433, NULL, &res->dispatch6); if (result != ISC_R_SUCCESS) goto cleanup_udpsocket6;