dispatch.c revision db30f4bdcb66afb7eb1ab0c6882cc70be9a53d79
/*
* Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2003 Internet Software Consortium.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dispatch.c,v 1.138 2008/04/03 02:01:08 marka Exp $ */
/*! \file */
#include <config.h>
#include <stdlib.h>
#include <unistd.h>
#include <dns/dispatch.h>
#include <dns/portlist.h>
/* transaction ID */
typedef struct dns_tid {
} dns_tid_t;
typedef struct dns_qid {
unsigned int magic;
unsigned int qid_nbuckets; /*%< hash table size */
unsigned int qid_increment; /*%< id increment on collision */
} dns_qid_t;
struct dns_dispatchmgr {
/* Unlocked. */
unsigned int magic;
/* Locked by "lock". */
unsigned int state;
/* locked by buffer lock */
unsigned int buffers; /*%< allocated buffers */
unsigned int buffersize; /*%< size of each buffer */
unsigned int maxbuffers; /*%< max buffers */
/* Locked internally. */
};
#define MGR_SHUTTINGDOWN 0x00000001U
struct dns_dispentry {
unsigned int magic;
unsigned int bucket;
void *arg;
};
#define INVALID_BUCKET (0xffffdead)
struct dns_dispatch {
/* Unlocked. */
unsigned int magic; /*%< magic */
unsigned int maxrequests; /*%< max requests */
/*% Locked by mgr->lock. */
/* Locked by "lock". */
unsigned int attributes;
unsigned int refcount; /*%< number of users */
unsigned int shutting_down : 1,
shutdown_out : 1,
connected : 1,
tcpmsg_valid : 1,
unsigned int requests; /*%< how many requests we have */
unsigned int tcpbuffers; /*%< allocated buffers */
};
/*
* Statics.
*/
dns_messageid_t, unsigned int);
static void startrecv(dns_dispatch_t *);
unsigned int maxrequests,
unsigned int attributes,
dns_dispatch_t **dispp);
#define LVL(x) ISC_LOG_DEBUG(x)
static void
static void
char msgbuf[2048];
return;
}
static void
static void
char msgbuf[2048];
return;
}
static void
static void
{
char msgbuf[2048];
char peerbuf[256];
return;
if (VALID_RESPONSE(resp)) {
} else {
msgbuf);
}
}
/*
* Return an unpredictable non-reserved UDP port. We share the QID
* framework for this purpose.
*/
static in_port_t
isc_uint16_t p;
/* XXX: should the range be configurable? */
}
/*
* Return an unpredictable message ID.
*/
static dns_messageid_t
return ((dns_messageid_t)id);
}
/*
* Return a hash of the destination and message id.
*/
static isc_uint32_t
unsigned int ret;
return (ret);
}
/*
* Find the first entry in 'qid'. Returns NULL if there are no entries.
*/
static dns_dispentry_t *
unsigned int bucket;
bucket = 0;
return (ret);
bucket++;
}
return (NULL);
}
/*
* Find the next entry after 'resp' in 'qid'. Return NULL if there are
* no more entries.
*/
static dns_dispentry_t *
unsigned int bucket;
return (ret);
bucket++;
return (ret);
bucket++;
}
return (NULL);
}
/*
* The dispatch must be locked.
*/
static isc_boolean_t
{
return (ISC_FALSE);
if (disp->recv_pending != 0)
return (ISC_FALSE);
if (disp->shutting_down == 0)
return (ISC_FALSE);
return (ISC_TRUE);
}
/*
* Called when refcount reaches 0 (and safe to destroy).
*
* The dispatcher must not be locked.
* The manager must be locked.
*/
static void
"shutting down; detaching from sock %p, task %p",
if (killmgr)
destroy_mgr(&mgr);
}
/*
* Find an entry for query ID 'id' and socket address 'dest' in 'qid'.
* Return NULL if no such entry exists.
*/
static dns_dispentry_t *
unsigned int bucket)
{
return (res);
}
return (NULL);
}
static void
case isc_sockettype_tcp:
disp->tcpbuffers--;
break;
case isc_sockettype_udp:
break;
default:
INSIST(0);
break;
}
}
static void *
void *temp;
return (temp);
}
static inline void
disp->shutdown_out = 0;
return;
}
}
static inline dns_dispatchevent_t *
return (NULL);
return (ev);
}
/*
* General flow:
*
* If I/O result == CANCELED or error, free the buffer.
*
* If query, free the buffer, restart.
*
* If response:
* Allocate event, fill in details.
* If cannot allocate, free buffer, restart.
* find target. If not found, free buffer, restart.
* if event queue is not empty, queue. else, send.
* restart.
*/
static void
unsigned int flags;
unsigned int bucket;
int match;
"got packet: requests %d, buffers %d, recvs %d",
/*
* Unless the receive event was imported from a listening
* interface, in which case the event type is
* DNS_EVENT_IMPORTRECVDONE, receive operation must be pending.
*/
disp->recv_pending = 0;
}
if (disp->shutting_down) {
/*
* This dispatcher is shutting down.
*/
if (killit)
return;
}
"odd socket result in udp_recv(): %s",
return;
}
/*
* If this is from a blackholed address, drop it.
*/
match > 0)
{
char netaddrstr[ISC_NETADDR_FORMATSIZE];
sizeof(netaddrstr));
"blackholed packet from %s",
}
goto restart;
}
/*
* Peek into the buffer to see what we can see.
*/
if (dres != ISC_R_SUCCESS) {
goto restart;
}
"got valid DNS message header, /QR %c, id %u",
/*
* Look at flags. If query, drop it. If response,
* look to see where it goes.
*/
if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
/* query */
goto restart;
}
/* response */
"search for response in bucket %d: %s",
goto unlock;
}
/*
* Now that we have the original dispatch the query was sent
* from check that the address and port the response was
* sent to make sense.
*/
/*
* Check that the socket types and ports match.
*/
goto unlock;
}
/*
* If both dispatches are bound to an address then fail as
* the addresses can't be equal (enforced by the IP stack).
*
* Note under Linux a packet can be sent out via IPv4 socket
* and the response be received via a IPv6 socket.
*
* Requests sent out via IPv6 should always come back in
* via IPv6.
*/
goto unlock;
}
goto unlock;
}
}
goto unlock;
}
/*
* At this point, rev contains the event we want to fill in, and
* resp contains the information on the place to send it to.
* Send the event off.
*/
if (queue_response) {
} else {
"[a] Sent event %p buffer %p len %d to task %p",
}
/*
* Restart recv() to get the next packet.
*/
}
/*
* General flow:
*
* If I/O result == CANCELED, EOF, or error, notify everyone as the
* various queues drain.
*
* If query, restart.
*
* If response:
* Allocate event, fill in details.
* If cannot allocate, restart.
* find target. If not found, restart.
* if event queue is not empty, queue. else, send.
* restart.
*/
static void
unsigned int flags;
unsigned int bucket;
int level;
char buf[ISC_SOCKADDR_FORMATSIZE];
"got TCP packet: requests %d, buffers %d, recvs %d",
disp->recv_pending = 0;
/*
* This dispatcher is shutting down. Force cancelation.
*/
}
case ISC_R_CANCELED:
break;
case ISC_R_EOF:
break;
case ISC_R_CONNECTIONRESET:
goto logit;
default:
"receive error: %s: %s", buf,
break;
}
/*
* The event is statically allocated in the tcpmsg
* structure, and destroy_disp() frees the tcpmsg, so we must
* free the event *before* calling destroy_disp().
*/
/*
* If the recv() was canceled pass the word on.
*/
if (killit)
return;
}
/*
* Peek into the buffer to see what we can see.
*/
if (dres != ISC_R_SUCCESS) {
goto restart;
}
"got valid DNS message header, /QR %c, id %u",
/*
* Allocate an event to send to the query or response client, and
* allocate a new buffer for our use.
*/
/*
* Look at flags. If query, drop it. If response,
* look to see where it goes.
*/
if ((flags & DNS_MESSAGEFLAG_QR) == 0) {
/*
* Query.
*/
goto restart;
}
/*
* Response.
*/
"search for response in bucket %d: %s",
goto unlock;
goto unlock;
/*
* At this point, rev contains the event we want to fill in, and
* resp contains the information on the place to send it to.
* Send the event off.
*/
disp->tcpbuffers++;
if (queue_response) {
} else {
"[b] Sent event %p buffer %p len %d to task %p",
}
/*
* Restart recv() to get the next packet.
*/
}
/*
* disp must be locked.
*/
static void
return;
return;
if (disp->recv_pending != 0)
return;
return;
/*
* UDP reads are always maximal.
*/
case isc_sockettype_udp:
return;
if (res != ISC_R_SUCCESS) {
return;
}
break;
case isc_sockettype_tcp:
if (res != ISC_R_SUCCESS) {
return;
}
break;
default:
INSIST(0);
break;
}
}
/*
* Mgr must be locked when calling this function.
*/
static isc_boolean_t
"destroy_mgr_ok: shuttingdown=%d, listnonempty=%d, "
"epool=%d, rpool=%d, dpool=%d",
if (!MGR_IS_SHUTTINGDOWN(mgr))
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_FALSE);
return (ISC_TRUE);
}
/*
* Mgr must be unlocked when calling this function.
*/
static void
}
static isc_result_t
{
if (result != ISC_R_SUCCESS)
return (result);
#ifndef ISC_ALLOW_MAPPED
#endif
if (result != ISC_R_SUCCESS) {
return (result);
}
return (ISC_R_SUCCESS);
}
/*
* Publics.
*/
{
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS)
goto deallocate;
if (result != ISC_R_SUCCESS)
goto kill_lock;
if (result != ISC_R_SUCCESS)
goto kill_buffer_lock;
goto kill_pool_lock;
}
goto kill_epool;
}
goto kill_rpool;
}
mgr->buffersize = 0;
mgr->maxbuffers = 0;
return (ISC_R_SUCCESS);
return (result);
}
void
}
}
void
{
}
}
static isc_result_t
unsigned int buffersize, unsigned int maxbuffers,
{
REQUIRE(maxbuffers > 0);
/*
* Keep some number of items around. This should be a config
* option. For now, keep 8, but later keep at least two even
* if the caller wants less. This allows us to ensure certain
* things, like an event can be "freed" and the next allocation
* will always succeed.
*
* Note that if limits are placed on anything here, we use one
* event internally, so the actual limit should be "wanted + 1."
*
* XXXMLG
*/
if (maxbuffers < 8)
maxbuffers = 8;
return (ISC_R_SUCCESS);
}
return (ISC_R_NOMEMORY);
}
if (result != ISC_R_SUCCESS)
goto cleanup;
return (ISC_R_SUCCESS);
return (ISC_R_NOMEMORY);
}
void
if (killit)
destroy_mgr(&mgr);
}
static isc_boolean_t
{
return (ISC_FALSE);
if (result != ISC_R_SUCCESS)
return (ISC_FALSE);
}
return (ISC_TRUE);
return (ISC_FALSE);
}
static isc_boolean_t
return (ISC_TRUE);
/*
* Don't match wildcard ports against newly blacklisted ports.
*/
isc_sockaddr_getport(addr) == 0 &&
return (ISC_FALSE);
/*
* Check if we match the binding <address,port>.
*/
return (ISC_TRUE);
if (isc_sockaddr_getport(addr) == 0)
return (ISC_FALSE);
/*
* Check if we match a bound wildcard port <address,port>.
*/
return (ISC_FALSE);
if (result != ISC_R_SUCCESS)
return (ISC_FALSE);
}
/*
* Requires mgr be locked.
*
* No dispatcher can be locked by this thread when calling this function.
*
*
* NOTE:
* If a matching dispatcher is found, it is locked after this function
* returns, and must be unlocked by the caller.
*/
static isc_result_t
unsigned int attributes, unsigned int mask,
{
/*
* Make certain that we will not match a private dispatch.
*/
if ((disp->shutting_down == 0)
break;
}
goto out;
}
out:
return (result);
}
static isc_result_t
{
unsigned int i;
return (ISC_R_NOMEMORY);
buckets * sizeof(dns_displist_t));
return (ISC_R_NOMEMORY);
}
if (result != ISC_R_SUCCESS) {
buckets * sizeof(dns_displist_t));
return (ISC_R_NOMEMORY);
}
if (result != ISC_R_SUCCESS) {
buckets * sizeof(dns_displist_t));
return (result);
}
for (i = 0; i < buckets; i++)
return (ISC_R_SUCCESS);
}
static void
}
/*
* Allocate and set important limits.
*/
static isc_result_t
{
/*
* Set up the dispatcher, mostly. Don't bother setting some of
* the options that are controlled by tcp vs. udp, etc.
*/
return (ISC_R_NOMEMORY);
disp->attributes = 0;
disp->recv_pending = 0;
disp->shutting_down = 0;
disp->shutdown_out = 0;
disp->tcpmsg_valid = 0;
disp->tcpbuffers = 0;
if (result != ISC_R_SUCCESS)
goto deallocate;
goto kill_lock;
}
return (ISC_R_SUCCESS);
/*
* error returns
*/
return (result);
}
/*
* MUST be unlocked, and not used by anthing.
*/
static void
{
if (disp->tcpmsg_valid) {
disp->tcpmsg_valid = 0;
}
}
unsigned int maxbuffers, unsigned int maxrequests,
{
/*
* dispatch_allocate() checks mgr for us.
* qid_allocate() checks buckets and increment for us.
*/
if (result != ISC_R_SUCCESS) {
return (result);
}
if (result != ISC_R_SUCCESS)
goto deallocate_dispatch;
if (result != ISC_R_SUCCESS)
goto kill_socket;
sizeof(isc_event_t));
goto kill_task;
}
/*
* Append it to the dispatcher list.
*/
return (ISC_R_SUCCESS);
/*
* Error returns.
*/
return (result);
}
unsigned int buffersize,
unsigned int maxbuffers, unsigned int maxrequests,
unsigned int attributes, unsigned int mask,
{
REQUIRE(maxbuffers > 0);
if (result != ISC_R_SUCCESS)
return (result);
if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) {
goto createudp;
}
/*
* See if we have a dispatcher that matches.
*/
if (result == ISC_R_SUCCESS) {
(attributes & DNS_DISPATCHATTR_NOLISTEN) != 0)
{
if (disp->recv_pending != 0)
}
return (ISC_R_SUCCESS);
}
/*
* Nope, create one.
*/
if (result != ISC_R_SUCCESS) {
return (result);
}
return (ISC_R_SUCCESS);
}
/*
* mgr should be locked.
*/
#ifndef DNS_DISPATCH_HELD
#define DNS_DISPATCH_HELD 20U
#endif
static isc_result_t
unsigned int maxrequests,
unsigned int attributes,
{
unsigned int i = 0, j = 0, k = 0;
/*
* dispatch_allocate() checks mgr for us.
*/
if (result != ISC_R_SUCCESS)
return (result);
/*
* Try to allocate a socket that is not on the blacklist.
* Hold up to DNS_DISPATCH_HELD sockets to prevent the OS
* from returning the same port to us too quickly.
*/
if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) != 0) {
if (++k == 1024)
goto getsocket;
}
if (result == ISC_R_ADDRINUSE) {
if (++k == 1024)
goto getsocket;
}
} else
if (result != ISC_R_SUCCESS)
goto deallocate_dispatch;
if ((attributes & DNS_DISPATCHATTR_RANDOMPORT) == 0 &&
isc_sockaddr_getport(localaddr) == 0 &&
{
isc_socket_detach(&held[i]);
if (i == DNS_DISPATCH_HELD)
i = 0;
if (j++ == 0xffffU) {
"unable to allocate a non-blacklisted port",
"4" : "6");
goto deallocate_dispatch;
}
goto getsocket;
}
if (result != ISC_R_SUCCESS)
goto kill_socket;
sizeof(isc_event_t));
goto kill_task;
}
/*
* Append it to the dispatcher list.
*/
goto cleanheld;
/*
* Error returns.
*/
for (i = 0; i < DNS_DISPATCH_HELD; i++)
isc_socket_detach(&held[i]);
return (result);
}
void
}
/*
* It is important to lock the manager while we are deleting the dispatch,
* since dns_dispatch_getudp will call dispatch_find, which returns to
* the caller a dispatch but does not attach to it until later. _getudp
* locks the manager, however, so locking it here will keep us from attaching
* to a dispatcher that is in the process of going away.
*/
void
if (disp->recv_pending > 0)
}
if (killit)
}
{
unsigned int bucket;
int i;
return (ISC_R_SHUTTINGDOWN);
}
return (ISC_R_QUOTA);
}
/*
* Try somewhat hard to find an unique ID.
*/
for (i = 0; i < 64; i++) {
break;
}
id &= 0x0000ffff;
}
if (!ok) {
return (ISC_R_NOMORE);
}
return (ISC_R_NOMEMORY);
}
return (ISC_R_SUCCESS);
}
void
}
void
{
unsigned int bucket;
unsigned int n;
} else {
}
if (disp->recv_pending > 0)
}
/*
* We've posted our event, but the caller hasn't gotten it
* yet. Take it back.
*/
/*
* We had better have gotten it back.
*/
INSIST(n == 1);
}
}
/*
* Free any buffered requests as well
*/
}
else
if (killit)
}
static void
return;
/*
* Search for the first response handler without packets outstanding.
*/
/* Empty. */)
/*
* No one to send the cancel event to, so nothing to do.
*/
goto unlock;
/*
* Send the shutdown failsafe event to this resp.
*/
"cancel: failsafe event %p -> task %p",
}
}
return (ISC_R_SUCCESS);
}
return (ISC_R_NOTIMPLEMENTED);
}
void
return;
}
return;
}
void
unsigned int attributes, unsigned int mask)
{
/* XXXMLG
* Should check for valid attributes here!
*/
if ((mask & DNS_DISPATCHATTR_NOLISTEN) != 0) {
(attributes & DNS_DISPATCHATTR_NOLISTEN) == 0) {
== 0 &&
(attributes & DNS_DISPATCHATTR_NOLISTEN) != 0) {
if (disp->recv_pending != 0)
}
}
}
void
void *buf;
newsevent = (isc_socketevent_t *)
disp, sizeof(isc_socketevent_t));
return;
return;
}
}
#if 0
void
char foo[1024];
}
}
#endif
/*
* Allow the user to pick one of two ID randomization algorithms.
*
* The first algorithm is an adaptation of the sequence shuffling
* algorithm discovered by Carter Bays and S. D. Durham [ACM Trans. Math.
* Software 2 (1976), 59-64], as documented as Algorithm B in Chapter
* 3.2.2 in Volume 2 of Knuth's "The Art of Computer Programming". We use
* a randomly selected linear congruential random number generator with a
* modulus of 2^16, whose increment is a randomly picked odd number, and
* whose multiplier is picked from a set which meets the following
* criteria:
* Is of the form 8*n+5, which ensures "high potency" according to
* principle iii in the summary chapter 3.6. This form also has a
* gcd(a-1,m) of 4 which is good according to principle iv.
*
* Is between 0.01 and 0.99 times the modulus as specified by
* principle iv.
*
* Passes the spectral test "with flying colors" (ut >= 1) in
* dimensions 2 through 6 as calculated by Algorithm S in Chapter
* 3.3.4 and the ratings calculated by formula 35 in section E.
*
* Of the multipliers that pass this test, pick the set that is
* best according to the theoretical bounds of the serial
* correlation test. This was calculated using a simplified
* version of Knuth's Theorem K in Chapter 3.3.3.
*
* These criteria may not be important for this use, but we might as well
* pick from the best generators since there are so many possible ones and
* we don't have that many random bits to do the picking.
*
* We use a modulus of 2^16 instead of something bigger so that we will
* tend to cycle through all the possible IDs before repeating any,
* however the shuffling will perturb this somewhat. Theoretically there
* is no minimimum interval between two uses of the same ID, but in
* practice it seems to be >64000.
*
* Our adaptatation of Algorithm B mixes the hash state which has
* captured various random events into the shuffler to perturb the
* sequence.
*
* One disadvantage of this algorithm is that if the generator parameters
* were to be guessed, it would be possible to mount a limited brute force
* attack on the ID space since the IDs are only shuffled within a limited
* range.
*
* The second algorithm uses the same random number generator to populate
* a pool of 65536 IDs. The hash state is used to pick an ID from a window
* of 4096 IDs in this pool, then the chosen ID is swapped with the ID
* at the beginning of the window and the window position is advanced.
* This means that the interval between uses of the ID will be no less
* than 65536-4096. The ID sequence in the pool will become more random
* over time.
*
* For both algorithms, two more linear congruential random number generators
* are selected. The ID from the first part of algorithm is used to seed
* the first of these generators, and its output is used to seed the second.
* The strategy is use these generators as 1 to 1 hashes to obfuscate the
* properties of the generator used in the first part of either algorithm.
*
* The first algorithm may be suitable for use in a client resolver since
* its memory requirements are fairly low and it's pretty random out of
* the box. It is somewhat succeptible to a limited brute force attack,
* so the second algorithm is probably preferable for a longer running
* program that issues a large number of queries and has time to randomize
* the pool.
*/
/*
* Pick one of the next 4096 IDs in the pool.
* There is a tradeoff here between randomness and how often and ID is reused.
*/
#define TID_HASHSHIFT 3
#define TID_HASHROTATE(v) \
static isc_uint32_t tid_hash_state;
/*
* Keep a running hash of various bits of data that we'll use to
* stir the ID pool or perturb the ID generator
*/
static void
unsigned char *p = data;
/*
* Hash function similar to the one we use for hashing names.
* We don't fold case or toss the upper bit here, though.
* This hash doesn't do much interesting when fed binary zeros,
* so there may be a better hash function.
* This function doesn't need to be very strong since we're
* only using it to stir the pool, but it should be reasonably
* fast.
*/
/*
* We don't care about locking access to tid_hash_state.
* In fact races make the result even more non deteministic.
*/
while (len-- > 0U) {
tid_hash_state += *p++;
}
}
/*
* Table of good linear congruential multipliers for modulus 2^16
* in order of increasing serial correlation bounds (so trim from
* the end).
*/
static const isc_uint16_t tid_multiplier_table[] = {
17565, 25013, 11733, 19877, 23989, 23997, 24997, 25421,
26781, 27413, 35901, 35917, 35973, 36229, 38317, 38437,
39941, 40493, 41853, 46317, 50581, 51429, 53453, 53805,
11317, 11789, 12045, 12413, 14277, 14821, 14917, 18989,
19821, 23005, 23533, 23573, 23693, 27549, 27709, 28461,
29365, 35605, 37693, 37757, 38309, 41285, 45261, 47061,
47269, 48133, 48597, 50277, 50717, 50757, 50805, 51341,
51413, 51581, 51597, 53445, 11493, 14229, 20365, 20653,
23485, 25541, 27429, 29421, 30173, 35445, 35653, 36789,
36797, 37109, 37157, 37669, 38661, 39773, 40397, 41837,
41877, 45293, 47277, 47845, 49853, 51085, 51349, 54085,
56933, 8877, 8973, 9885, 11365, 11813, 13581, 13589,
13613, 14109, 14317, 15765, 15789, 16925, 17069, 17205,
17621, 17941, 19077, 19381, 20245, 22845, 23733, 24869,
25453, 27213, 28381, 28965, 29245, 29997, 30733, 30901,
34877, 35485, 35613, 36133, 36661, 36917, 38597, 40285,
40693, 41413, 41541, 41637, 42053, 42349, 45245, 45469,
46493, 48205, 48613, 50861, 51861, 52877, 53933, 54397,
55669, 56453, 56965, 58021, 7757, 7781, 8333, 9661,
12229, 14373, 14453, 17549, 18141, 19085, 20773, 23701,
24205, 24333, 25261, 25317, 27181, 30117, 30477, 34757,
34885, 35565, 35885, 36541, 37957, 39733, 39813, 41157,
41893, 42317, 46621, 48117, 48181, 49525, 55261, 55389,
56845, 7045, 7749, 7965, 8469, 9133, 9549, 9789,
10173, 11181, 11285, 12253, 13453, 13533, 13757, 14477,
15053, 16901, 17213, 17269, 17525, 17629, 18605, 19013,
19829, 19933, 20069, 20093, 23261, 23333, 24949, 25309,
27613, 28453, 28709, 29301, 29541, 34165, 34413, 37301,
37773, 38045, 38405, 41077, 41781, 41925, 42717, 44437,
44525, 44613, 45933, 45941, 47077, 50077, 50893, 52117,
5293, 55069, 55989, 58125, 59205, 6869, 14685, 15453,
16821, 17045, 17613, 18437, 21029, 22773, 22909, 25445,
25757, 26541, 30709, 30909, 31093, 31149, 37069, 37725,
37925, 38949, 39637, 39701, 40765, 40861, 42965, 44813,
45077, 45733, 47045, 50093, 52861, 52957, 54181, 56325,
56365, 56381, 56877, 57013, 5741, 58101, 58669, 8613,
10045, 10261, 10653, 10733, 11461, 12261, 14069, 15877,
17757, 21165, 23885, 24701, 26429, 26645, 27925, 28765,
29197, 30189, 31293, 39781, 39909, 40365, 41229, 41453,
41653, 42165, 42365, 47421, 48029, 48085, 52773, 5573,
57037, 57637, 58341, 58357, 58901, 6357, 7789, 9093,
10125, 10709, 10765, 11957, 12469, 13437, 13509, 14773,
15437, 15773, 17813, 18829, 19565, 20237, 23461, 23685,
23725, 23941, 24877, 25461, 26405, 29509, 30285, 35181,
37229, 37893, 38565, 40293, 44189, 44581, 45701, 47381,
47589, 48557, 4941, 51069, 5165, 52797, 53149, 5341,
56301, 56765, 58581, 59493, 59677, 6085, 6349, 8293,
8501, 8517, 11597, 11709, 12589, 12693, 13517, 14909,
17397, 18085, 21101, 21269, 22717, 25237, 25661, 29189,
30101, 31397, 33933, 34213, 34661, 35533, 36493, 37309,
40037, 4189, 42909, 44309, 44357, 44389, 4541, 45461,
46445, 48237, 54149, 55301, 55853, 56621, 56717, 56901,
5813, 58437, 12493, 15365, 15989, 17829, 18229, 19341,
21013, 21357, 22925, 24885, 26053, 27581, 28221, 28485,
30605, 30613, 30789, 35437, 36285, 37189, 3941, 41797,
4269, 42901, 43293, 44645, 45221, 46893, 4893, 50301,
50325, 5189, 52109, 53517, 54053, 54485, 5525, 55949,
56973, 59069, 59421, 60733, 61253, 6421, 6701, 6709,
7101, 8669, 15797, 19221, 19837, 20133, 20957, 21293,
21461, 22461, 29085, 29861, 30869, 34973, 36469, 37565,
38125, 38829, 39469, 40061, 40117, 44093, 47429, 48341,
50597, 51757, 5541, 57629, 58405, 59621, 59693, 59701,
61837, 7061, 10421, 11949, 15405, 20861, 25397, 25509,
25893, 26037, 28629, 28869, 29605, 30213, 34205, 35637,
36365, 37285, 3773, 39117, 4021, 41061, 42653, 44509,
4461, 44829, 4725, 5125, 52269, 56469, 59085, 5917,
60973, 8349, 17725, 18637, 19773, 20293, 21453, 22533,
24285, 26333, 26997, 31501, 34541, 34805, 37509, 38477,
41333, 44125, 46285, 46997, 47637, 48173, 4925, 50253,
50381, 50917, 51205, 51325, 52165, 52229, 5253, 5269,
53509, 56253, 56341, 5821, 58373, 60301, 61653, 61973,
62373, 8397, 11981, 14341, 14509, 15077, 22261, 22429,
24261, 28165, 28685, 30661, 34021, 34445, 39149, 3917,
43013, 43317, 44053, 44101, 4533, 49541, 49981, 5277,
54477, 56357, 57261, 57765, 58573, 59061, 60197, 61197,
62189, 7725, 8477, 9565, 10229, 11437, 14613, 14709,
16813, 20029, 20677, 31445, 3165, 31957, 3229, 33541,
36645, 3805, 38973, 3965, 4029, 44293, 44557, 46245,
48917, 4909, 51749, 53709, 55733, 56445, 5925, 6093,
61053, 62637, 8661, 9109, 10821, 11389, 13813, 14325,
15501, 16149, 18845, 22669, 26437, 29869, 31837, 33709,
33973, 34173, 3677, 3877, 3981, 39885, 42117, 4421,
44221, 44245, 44693, 46157, 47309, 5005, 51461, 52037,
55333, 55693, 56277, 58949, 6205, 62141, 62469, 6293,
10101, 12509, 14029, 17997, 20469, 21149, 25221, 27109,
2773, 2877, 29405, 31493, 31645, 4077, 42005, 42077,
42469, 42501, 44013, 48653, 49349, 4997, 50101, 55405,
56957, 58037, 59429, 60749, 61797, 62381, 62837, 6605,
10541, 23981, 24533, 2701, 27333, 27341, 31197, 33805,
3621, 37381, 3749, 3829, 38533, 42613, 44381, 45901,
48517, 51269, 57725, 59461, 60045, 62029, 13805, 14013,
15461, 16069, 16157, 18573, 2309, 23501, 28645, 3077,
31541, 36357, 36877, 3789, 39429, 39805, 47685, 47949,
49413, 5485, 56757, 57549, 57805, 58317, 59549, 62213,
62613, 62853, 62933, 8909, 12941, 16677, 20333, 21541,
24429, 26077, 26421, 2885, 31269, 33381, 3661, 40925,
42925, 45173, 4525, 4709, 53133, 55941, 57413, 57797,
62125, 62237, 62733, 6773, 12317, 13197, 16533, 16933,
18245, 2213, 2477, 29757, 33293, 35517, 40133, 40749,
4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421,
21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253,
36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013,
60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781,
10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493,
4661, 49941, 62757, 7853, 8149, 8573, 11029, 13421,
21549, 22709, 22725, 24629, 2469, 26125, 2669, 34253,
36709, 41013, 45597, 46637, 52285, 52333, 54685, 59013,
60997, 61189, 61981, 62605, 62821, 7077, 7525, 8781,
10861, 15277, 2205, 22077, 28517, 28949, 32109, 33493,
3685, 39197, 39869, 42621, 44997, 48565, 5221, 57381,
61749, 62317, 63245, 63381, 23149, 2549, 28661, 31653,
33885, 36341, 37053, 39517, 42805, 45853, 48997, 59349,
60053, 62509, 63069, 6525, 1893, 20181, 2365, 24893,
27397, 31357, 32277, 33357, 34437, 36677, 37661, 43469,
43917, 50997, 53869, 5653, 13221, 16741, 17893, 2157,
28653, 31789, 35301, 35821, 61613, 62245, 12405, 14517,
17453, 18421, 3149, 3205, 40341, 4109, 43941, 46869,
48837, 50621, 57405, 60509, 62877, 8157, 12933, 12957,
16501, 19533, 3461, 36829, 52357, 58189, 58293, 63053,
17109, 1933, 32157, 37701, 59005, 61621, 13029, 15085,
16493, 32317, 35093, 5061, 51557, 62221, 20765, 24613,
2629, 30861, 33197, 33749, 35365, 37933, 40317, 48045,
56229, 61157, 63797, 7917, 17965, 1917, 1973, 20301,
2253, 33157, 58629, 59861, 61085, 63909, 8141, 9221,
14757, 1581, 21637, 26557, 33869, 34285, 35733, 40933,
42517, 43501, 53653, 61885, 63805, 7141, 21653, 54973,
31189, 60061, 60341, 63357, 16045, 2053, 26069, 33997,
43901, 54565, 63837, 8949, 17909, 18693, 32349, 33125,
37293, 48821, 49053, 51309, 64037, 7117, 1445, 20405,
23085, 26269, 26293, 27349, 32381, 33141, 34525, 36461,
37581, 43525, 4357, 43877, 5069, 55197, 63965, 9845,
12093, 2197, 2229, 32165, 33469, 40981, 42397, 8749,
10853, 1453, 18069, 21693, 30573, 36261, 37421, 42533
};
#define TID_MULT_TABLE_SIZE \
((sizeof tid_multiplier_table) / \
(sizeof tid_multiplier_table[0]))
#define TID_SHUFFLE_ONLY 1
#define TID_USE_POOL 2
static isc_uint16_t
isc_uint16_t j;
(tid_hash_state)) & 0xFFFF;
if (tid->tid_usepool) {
if (pick != 0) {
/* Swap two IDs to stir the pool */
}
/* increment the base pointer into the pool */
else
} else {
/*
* This is the original Algorithm B
* j = ((u_long)
* QUERID_SHUFFLE_TABLE_SIZE * tid_state2) >> 16;
*
* We'll perturb it with some random stuff ...
*/
j = ((isc_uint32_t) TID_SHUFFLE_TABLE_SIZE *
}
/* Now lets obfuscate ... */
return (id);
}
static isc_result_t
int i;
isc_time_now(&now);
/* Initialize the state */
/*
* Select our random number generators and initial seed.
* We could really use more random bits at this point,
* but we'll try to make a silk purse out of a sows ear ...
*/
/* generator 1 */
/* generator 2, distinct from 1 */
a2ndx++;
c2ndx++;
/* generator 3, distinct from 1 and 2 */
a3ndx++;
a3ndx++;
c3ndx++;
c3ndx++;
if (tid->tid_usepool) {
0x10000 * sizeof(isc_uint16_t));
return (ISC_R_NOMEMORY);
for (i = 0; ; i++) {
if (i == 0xFFFF)
break;
}
} else {
(sizeof(isc_uint16_t)) );
return (ISC_R_NOMEMORY);
for (i = 0; i < TID_SHUFFLE_TABLE_SIZE; i++) {
}
}
return (ISC_R_SUCCESS);
}
static void
if (tid->tid_usepool)
0x10000 * sizeof(isc_uint16_t));
else
(sizeof(isc_uint16_t)) );
}
void
}