Home | History | Annotate | Download | only in mDNSShared
      1 /* -*- Mode: C; tab-width: 4 -*-
      2  *
      3  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 #if __APPLE__
     19 // In Mac OS X 10.5 and later trying to use the daemon function gives a daemon is deprecated
     20 // error, which prevents compilation because we build with "-Werror".
     21 // Since this is supposed to be portable cross-platform code, we don't care that daemon is
     22 // deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
     23 #define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
     24 #endif
     25 
     26 #include <signal.h>
     27 #include <pthread.h>
     28 #include <stdlib.h>
     29 #include <unistd.h>
     30 #include <sys/types.h>
     31 #include <sys/socket.h>
     32 #include <netinet/in.h>
     33 #include <arpa/inet.h>
     34 #include <stdio.h>
     35 #include <syslog.h>
     36 #include <string.h>
     37 #include <sys/time.h>
     38 #include <sys/resource.h>
     39 #include <time.h>
     40 #include <errno.h>
     41 
     42 #if __APPLE__
     43 #undef daemon
     44 extern int daemon(int, int);
     45 #endif
     46 
     47 // Solaris doesn't have daemon(), so we define it here
     48 #ifdef NOT_HAVE_DAEMON
     49 #include "../mDNSPosix/mDNSUNP.h"		// For daemon()
     50 #endif // NOT_HAVE_DAEMON
     51 
     52 #include "dnsextd.h"
     53 #include "../mDNSShared/uds_daemon.h"
     54 #include "../mDNSShared/dnssd_ipc.h"
     55 #include "../mDNSCore/uDNS.h"
     56 #include "../mDNSShared/DebugServices.h"
     57 
     58 // Compatibility workaround
     59 #ifndef AF_LOCAL
     60 #define AF_LOCAL AF_UNIX
     61 #endif
     62 
     63 //
     64 // Constants
     65 //
     66 mDNSexport const char ProgramName[] = "dnsextd";
     67 
     68 #define LOOPBACK					"127.0.0.1"
     69 #if !defined(LISTENQ)
     70 #	define LISTENQ					128					// tcp connection backlog
     71 #endif
     72 #define RECV_BUFLEN					9000
     73 #define LEASETABLE_INIT_NBUCKETS	256					// initial hashtable size (doubles as table fills)
     74 #define EXPIRATION_INTERVAL			300					// check for expired records every 5 minutes
     75 #define SRV_TTL						7200				// TTL For _dns-update SRV records
     76 #define CONFIG_FILE					"/etc/dnsextd.conf"
     77 #define TCP_SOCKET_FLAGS   			kTCPSocketFlags_UseTLS
     78 
     79 // LLQ Lease bounds (seconds)
     80 #define LLQ_MIN_LEASE (15 * 60)
     81 #define LLQ_MAX_LEASE (120 * 60)
     82 #define LLQ_LEASE_FUDGE 60
     83 
     84 // LLQ SOA poll interval (microseconds)
     85 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
     86 #define LLQ_MONITOR_INTERVAL 250000
     87 #ifdef SIGINFO
     88 #define INFO_SIGNAL SIGINFO
     89 #else
     90 #define INFO_SIGNAL SIGUSR1
     91 #endif
     92 
     93 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
     94 
     95 //
     96 // Data Structures
     97 // Structs/fields that must be locked for thread safety are explicitly commented
     98 //
     99 
    100 // args passed to UDP request handler thread as void*
    101 
    102 typedef struct
    103 	{
    104     PktMsg pkt;
    105     struct sockaddr_in cliaddr;
    106     DaemonInfo *d;
    107 	int sd;
    108 	} UDPContext;
    109 
    110 // args passed to TCP request handler thread as void*
    111 typedef struct
    112 	{
    113 	PktMsg	pkt;
    114     struct sockaddr_in cliaddr;
    115     TCPSocket *sock;           // socket connected to client
    116     DaemonInfo *d;
    117 	} TCPContext;
    118 
    119 // args passed to UpdateAnswerList thread as void*
    120 typedef struct
    121 	{
    122     DaemonInfo *d;
    123     AnswerListElem *a;
    124 	} UpdateAnswerListArgs;
    125 
    126 //
    127 // Global Variables
    128 //
    129 
    130 // booleans to determine runtime output
    131 // read-only after initialization (no mutex protection)
    132 static mDNSBool foreground = 0;
    133 static mDNSBool verbose = 0;
    134 
    135 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
    136 static mDNSBool terminate = 0;
    137 static mDNSBool dumptable = 0;
    138 static mDNSBool hangup    = 0;
    139 
    140 // global for config file location
    141 static char *   cfgfile   = NULL;
    142 
    143 //
    144 // Logging Routines
    145 // Log messages are delivered to syslog unless -f option specified
    146 //
    147 
    148 // common message logging subroutine
    149 mDNSlocal void PrintLog(const char *buffer)
    150 	{
    151 	if (foreground)
    152 		{
    153 		fprintf(stderr,"%s\n", buffer);
    154 		fflush(stderr);
    155 		}
    156 	else
    157 		{
    158 		openlog("dnsextd", LOG_CONS, LOG_DAEMON);
    159 		syslog(LOG_ERR, "%s", buffer);
    160 		closelog();
    161 		}
    162 	}
    163 
    164 // Verbose Logging (conditional on -v option)
    165 mDNSlocal void VLog(const char *format, ...)
    166 	{
    167    	char buffer[512];
    168 	va_list ptr;
    169 
    170 	if (!verbose) return;
    171 	va_start(ptr,format);
    172 	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
    173 	va_end(ptr);
    174  	PrintLog(buffer);
    175 	}
    176 
    177 // Unconditional Logging
    178 mDNSlocal void Log(const char *format, ...)
    179 	{
    180    	char buffer[512];
    181 	va_list ptr;
    182 
    183 	va_start(ptr,format);
    184 	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
    185 	va_end(ptr);
    186  	PrintLog(buffer);
    187 	}
    188 
    189 // Error Logging
    190 // prints message "dnsextd <function>: <operation> - <error message>"
    191 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
    192 mDNSlocal void LogErr(const char *fn, const char *operation)
    193 	{
    194 	char buf[512], errbuf[256];
    195 	strerror_r(errno, errbuf, sizeof(errbuf));
    196 	snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, errbuf);
    197 	PrintLog(buf);
    198 	}
    199 
    200 //
    201 // Networking Utility Routines
    202 //
    203 
    204 // Convert DNS Message Header from Network to Host byte order
    205 mDNSlocal void HdrNToH(PktMsg *pkt)
    206 	{
    207 	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
    208 	mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
    209 	pkt->msg.h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
    210 	pkt->msg.h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
    211 	pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
    212 	pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
    213 	}
    214 
    215 // Convert DNS Message Header from Host to Network byte order
    216 mDNSlocal void HdrHToN(PktMsg *pkt)
    217 	{
    218 	mDNSu16 numQuestions   = pkt->msg.h.numQuestions;
    219 	mDNSu16 numAnswers     = pkt->msg.h.numAnswers;
    220 	mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
    221 	mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
    222 	mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
    223 
    224 	// Put all the integer values in IETF byte-order (MSB first, LSB second)
    225 	*ptr++ = (mDNSu8)(numQuestions   >> 8);
    226 	*ptr++ = (mDNSu8)(numQuestions   &  0xFF);
    227 	*ptr++ = (mDNSu8)(numAnswers     >> 8);
    228 	*ptr++ = (mDNSu8)(numAnswers     &  0xFF);
    229 	*ptr++ = (mDNSu8)(numAuthorities >> 8);
    230 	*ptr++ = (mDNSu8)(numAuthorities &  0xFF);
    231 	*ptr++ = (mDNSu8)(numAdditionals >> 8);
    232 	*ptr++ = (mDNSu8)(numAdditionals &  0xFF);
    233 	}
    234 
    235 
    236 // Add socket to event loop
    237 
    238 mDNSlocal mStatus AddSourceToEventLoop( DaemonInfo * self, TCPSocket *sock, EventCallback callback, void *context )
    239 	{
    240 	EventSource	* newSource;
    241 	mStatus			err = mStatus_NoError;
    242 
    243 	if ( self->eventSources.LinkOffset == 0 )
    244 		{
    245 		InitLinkedList( &self->eventSources, offsetof( EventSource, next));
    246 		}
    247 
    248 	newSource = ( EventSource*) malloc( sizeof *newSource );
    249 	if ( newSource == NULL )
    250 		{
    251 		err = mStatus_NoMemoryErr;
    252 		goto exit;
    253 		}
    254 
    255 	newSource->callback = callback;
    256 	newSource->context = context;
    257 	newSource->sock = sock;
    258 	newSource->fd = mDNSPlatformTCPGetFD( sock );
    259 
    260 	AddToTail( &self->eventSources, newSource );
    261 
    262 exit:
    263 
    264 	return err;
    265 	}
    266 
    267 
    268 // Remove socket from event loop
    269 
    270 mDNSlocal mStatus RemoveSourceFromEventLoop( DaemonInfo * self, TCPSocket *sock )
    271 	{
    272 	EventSource	*	source;
    273 	mStatus			err;
    274 
    275 	for ( source = ( EventSource* ) self->eventSources.Head; source; source = source->next )
    276 		{
    277 		if ( source->sock == sock )
    278 			{
    279 			RemoveFromList( &self->eventSources, source );
    280 
    281 			free( source );
    282 			err = mStatus_NoError;
    283 			goto exit;
    284 			}
    285 		}
    286 
    287 	err = mStatus_NoSuchNameErr;
    288 
    289 exit:
    290 
    291 	return err;
    292 	}
    293 
    294 // create a socket connected to nameserver
    295 // caller terminates connection via close()
    296 mDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
    297 	{
    298 	int ntries = 0, retry = 0;
    299 
    300 	while (1)
    301 		{
    302 		mDNSIPPort port = zeroIPPort;
    303 		int fd;
    304 
    305 		TCPSocket *sock = mDNSPlatformTCPSocket( NULL, 0, &port );
    306 		if ( !sock ) { LogErr("ConnectToServer", "socket");  return NULL; }
    307 		fd = mDNSPlatformTCPGetFD( sock );
    308 		if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
    309 		mDNSPlatformTCPCloseConnection( sock );
    310 		if (++ntries < 10)
    311 			{
    312 			LogErr("ConnectToServer", "connect");
    313 			Log("ConnectToServer - retrying connection");
    314 			if (!retry) retry = 500000 + random() % 500000;
    315 			usleep(retry);
    316 			retry *= 2;
    317 			}
    318 		else { Log("ConnectToServer - %d failed attempts.  Aborting.", ntries); return NULL; }
    319 		}
    320 	}
    321 
    322 // send an entire block of data over a connected socket
    323 mDNSlocal int MySend(TCPSocket *sock, const void *msg, int len)
    324 	{
    325 	int selectval, n, nsent = 0;
    326 	fd_set wset;
    327 	struct timeval timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
    328 
    329 	while (nsent < len)
    330 		{
    331 		int fd;
    332 
    333 		FD_ZERO(&wset);
    334 
    335 		fd = mDNSPlatformTCPGetFD( sock );
    336 
    337 		FD_SET( fd, &wset );
    338 		selectval = select( fd+1, NULL, &wset, NULL, &timeout);
    339 		if (selectval < 0) { LogErr("MySend", "select");  return -1; }
    340 		if (!selectval || !FD_ISSET(fd, &wset)) { Log("MySend - timeout"); return -1; }
    341 
    342 		n = mDNSPlatformWriteTCP( sock, ( char* ) msg + nsent, len - nsent);
    343 
    344 		if (n < 0) { LogErr("MySend", "send");  return -1; }
    345 		nsent += n;
    346 		}
    347 	return 0;
    348 	}
    349 
    350 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
    351 mDNSlocal int SendPacket(TCPSocket *sock, PktMsg *pkt)
    352 	{
    353 	// send the lenth, in network byte order
    354 	mDNSu16 len = htons((mDNSu16)pkt->len);
    355 	if (MySend(sock, &len, sizeof(len)) < 0) return -1;
    356 
    357 	// send the message
    358 	VLog("SendPacket Q:%d A:%d A:%d A:%d ",
    359 		ntohs(pkt->msg.h.numQuestions),
    360 		ntohs(pkt->msg.h.numAnswers),
    361 		ntohs(pkt->msg.h.numAuthorities),
    362 		ntohs(pkt->msg.h.numAdditionals));
    363 	return MySend(sock, &pkt->msg, pkt->len);
    364 	}
    365 
    366 // Receive len bytes, waiting until we have all of them.
    367 // Returns number of bytes read (which should always be the number asked for).
    368 static int my_recv(TCPSocket *sock, void *const buf, const int len, mDNSBool * closed)
    369     {
    370     // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
    371     // use an explicit while() loop instead.
    372     // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
    373     // arithmetic on "void *" pointers is compiler-dependent.
    374 
    375 	fd_set rset;
    376 	struct timeval timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
    377     int selectval, remaining = len;
    378     char *ptr = (char *)buf;
    379 	ssize_t num_read;
    380 
    381 	while (remaining)
    382     	{
    383 		int fd;
    384 
    385 		fd = mDNSPlatformTCPGetFD( sock );
    386 
    387 		FD_ZERO(&rset);
    388 		FD_SET(fd, &rset);
    389 		selectval = select(fd+1, &rset, NULL, NULL, &timeout);
    390 		if (selectval < 0) { LogErr("my_recv", "select");  return -1; }
    391 		if (!selectval || !FD_ISSET(fd, &rset))
    392 			{
    393 			Log("my_recv - timeout");
    394 			return -1;
    395 			}
    396 
    397 		num_read = mDNSPlatformReadTCP( sock, ptr, remaining, closed );
    398 
    399     	if (((num_read == 0) && *closed) || (num_read < 0) || (num_read > remaining)) return -1;
    400 		if (num_read == 0) return 0;
    401     	ptr       += num_read;
    402     	remaining -= num_read;
    403     	}
    404     return(len);
    405     }
    406 
    407 // Return a DNS Message read off of a TCP socket, or NULL on failure
    408 // If storage is non-null, result is placed in that buffer.  Otherwise,
    409 // returned value is allocated with Malloc, and contains sufficient extra
    410 // storage for a Lease OPT RR
    411 
    412 mDNSlocal PktMsg*
    413 RecvPacket
    414 	(
    415 	TCPSocket *	sock,
    416 	PktMsg		*	storage,
    417 	mDNSBool	*	closed
    418 	)
    419 	{
    420 	int				nread;
    421 	int 			allocsize;
    422 	mDNSu16			msglen = 0;
    423 	PktMsg		*	pkt = NULL;
    424 	unsigned int	srclen;
    425 	int				fd;
    426 	mStatus			err = 0;
    427 
    428 	fd = mDNSPlatformTCPGetFD( sock );
    429 
    430 	nread = my_recv( sock, &msglen, sizeof( msglen ), closed );
    431 
    432 	require_action_quiet( nread != -1, exit, err = mStatus_UnknownErr );
    433 	require_action_quiet( nread > 0, exit, err = mStatus_NoError );
    434 
    435 	msglen = ntohs( msglen );
    436 	require_action_quiet( nread == sizeof( msglen ), exit, err = mStatus_UnknownErr; Log( "Could not read length field of message") );
    437 
    438 	if ( storage )
    439 		{
    440 		require_action_quiet( msglen <= sizeof( storage->msg ), exit, err = mStatus_UnknownErr; Log( "RecvPacket: provided buffer too small." ) );
    441 		pkt = storage;
    442 		}
    443 	else
    444 		{
    445 		// buffer extra space to add an OPT RR
    446 
    447 		if ( msglen > sizeof(DNSMessage))
    448 			{
    449 			allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
    450 			}
    451 		else
    452 			{
    453 			allocsize = sizeof(PktMsg);
    454 			}
    455 
    456 		pkt = malloc(allocsize);
    457 		require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) );
    458 		mDNSPlatformMemZero( pkt, sizeof( *pkt ) );
    459 		}
    460 
    461 	pkt->len = msglen;
    462 	srclen = sizeof(pkt->src);
    463 
    464 	if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) )
    465 		{
    466 		LogErr("RecvPacket", "getpeername");
    467 		mDNSPlatformMemZero(&pkt->src, sizeof(pkt->src));
    468 		}
    469 
    470 	nread = my_recv(sock, &pkt->msg, msglen, closed );
    471 	require_action_quiet( nread >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvPacket", "recv" ) );
    472 	require_action_quiet( nread == msglen, exit, err = mStatus_UnknownErr ; Log( "Could not read entire message" ) );
    473 	require_action_quiet( pkt->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr ; Log( "RecvPacket: Message too short (%d bytes)", pkt->len ) );
    474 
    475 exit:
    476 
    477 	if ( err && pkt )
    478 		{
    479 		if ( pkt != storage )
    480 			{
    481 			free(pkt);
    482 			}
    483 
    484 		pkt = NULL;
    485 		}
    486 
    487 	return pkt;
    488 	}
    489 
    490 
    491 mDNSlocal DNSZone*
    492 FindZone
    493 	(
    494 	DaemonInfo	*	self,
    495 	domainname	*	name
    496 	)
    497 	{
    498 	DNSZone * zone;
    499 
    500 	for ( zone = self->zones; zone; zone = zone->next )
    501 		{
    502 		if ( SameDomainName( &zone->name, name ) )
    503 			{
    504 				break;
    505 			}
    506 		}
    507 
    508 		return zone;
    509 	}
    510 
    511 
    512 mDNSlocal mDNSBool
    513 ZoneHandlesName
    514 	(
    515 	const domainname * zname,
    516 	const domainname * dname
    517 	)
    518 	{
    519 	mDNSu16	i = DomainNameLength( zname );
    520 	mDNSu16	j = DomainNameLength( dname );
    521 
    522 	if ( ( i == ( MAX_DOMAIN_NAME + 1 ) ) || ( j == ( MAX_DOMAIN_NAME + 1 ) ) || ( i > j )  || ( memcmp( zname->c, dname->c + ( j - i ), i ) != 0 ) )
    523 		{
    524 		return mDNSfalse;
    525 		}
    526 
    527 	return mDNStrue;
    528 	}
    529 
    530 
    531 mDNSlocal mDNSBool IsQuery( PktMsg * pkt )
    532 	{
    533 	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery );
    534 	}
    535 
    536 
    537 mDNSlocal mDNSBool IsUpdate( PktMsg * pkt )
    538 	{
    539 	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_OP_Update );
    540 	}
    541 
    542 
    543 mDNSlocal mDNSBool IsNotify(PktMsg *pkt)
    544 	{
    545 	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( mDNSu8) ( kDNSFlag0_OP_Notify );
    546 	}
    547 
    548 
    549 mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
    550 	{
    551 	const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
    552 	LargeCacheRecord lcr;
    553 	int i;
    554 	mDNSBool result = mDNSfalse;
    555 
    556 	HdrNToH(pkt);
    557 	if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
    558 
    559 	if (!pkt->msg.h.numAdditionals) goto end;
    560 	ptr = LocateAdditionals(&pkt->msg, end);
    561 	if (!ptr) goto end;
    562 
    563 	// find last Additional info.
    564 	for (i = 0; i < pkt->msg.h.numAdditionals; i++)
    565 		{
    566 		ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
    567 		if (!ptr) { Log("Unable to read additional record"); goto end; }
    568 		}
    569 
    570 	if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= DNSOpt_LLQData_Space && lcr.r.resrec.rdata->u.opt[0].opt == kDNSOpt_LLQ )
    571 		{
    572 		result = mDNStrue;
    573 		}
    574 
    575 	end:
    576 	HdrHToN(pkt);
    577 	return result;
    578 	}
    579 
    580 // !!!KRS implement properly
    581 mDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
    582 	{
    583 	if ((pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery ) &&
    584 		pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
    585 	return mDNSfalse;
    586 	}
    587 
    588 
    589 mDNSlocal mDNSBool
    590 IsPublicSRV
    591 	(
    592 	DaemonInfo	*	self,
    593 	DNSQuestion	*	q
    594 	)
    595 	{
    596 	DNameListElem	*	elem;
    597 	mDNSBool			ret		= mDNSfalse;
    598 	int					i		= ( int ) DomainNameLength( &q->qname ) - 1;
    599 
    600 	for ( elem = self->public_names; elem; elem = elem->next )
    601 		{
    602 		int	j = ( int ) DomainNameLength( &elem->name ) - 1;
    603 
    604 		if ( i > j )
    605 			{
    606 			for ( ; i >= 0; i--, j-- )
    607 				{
    608 				if ( q->qname.c[ i ] != elem->name.c[ j ] )
    609 					{
    610 					ret = mDNStrue;
    611 					goto exit;
    612 					}
    613 				}
    614 			}
    615 		}
    616 
    617 exit:
    618 
    619 	return ret;
    620 	}
    621 
    622 
    623 mDNSlocal void
    624 SetZone
    625 	(
    626 	DaemonInfo	* self,
    627 	PktMsg		* pkt
    628 	)
    629 	{
    630 	domainname			zname;
    631 	mDNSu8				QR_OP;
    632 	const mDNSu8	*	ptr = pkt->msg.data;
    633 	mDNSBool			exception = mDNSfalse;
    634 
    635 	// Initialize
    636 
    637 	pkt->zone			= NULL;
    638 	pkt->isZonePublic	= mDNStrue;
    639 	zname.c[0]			= '\0';
    640 
    641 	// Figure out what type of packet this is
    642 
    643 	QR_OP = ( mDNSu8 ) ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask );
    644 
    645 	if ( IsQuery( pkt ) )
    646 		{
    647 		DNSQuestion question;
    648 
    649 		// It's a query
    650 
    651 		ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
    652 
    653 		AppendDomainName( &zname, &question.qname );
    654 
    655 		exception = ( ( question.qtype == kDNSType_SOA ) || ( question.qtype == kDNSType_NS ) || ( ( question.qtype == kDNSType_SRV ) && IsPublicSRV( self, &question ) ) );
    656 		}
    657 	else if ( IsUpdate( pkt ) )
    658 		{
    659 		DNSQuestion question;
    660 
    661 		// It's an update.  The format of the zone section is the same as the format for the question section
    662 		// according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
    663 
    664 		ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
    665 
    666 		AppendDomainName( &zname, &question.qname );
    667 
    668 		exception = mDNSfalse;
    669 		}
    670 
    671 	if ( zname.c[0] != '\0' )
    672 		{
    673 		// Find the right zone
    674 
    675 		for ( pkt->zone = self->zones; pkt->zone; pkt->zone = pkt->zone->next )
    676 			{
    677 			if ( ZoneHandlesName( &pkt->zone->name, &zname ) )
    678 				{
    679 				VLog( "found correct zone %##s for query", pkt->zone->name.c );
    680 
    681 				pkt->isZonePublic = ( ( pkt->zone->type == kDNSZonePublic ) || exception );
    682 
    683 				VLog( "zone %##s is %s", pkt->zone->name.c, ( pkt->isZonePublic ) ? "public" : "private" );
    684 
    685 				break;
    686 				}
    687 			}
    688 		}
    689 	}
    690 
    691 
    692 mDNSlocal int
    693 UDPServerTransaction(const DaemonInfo *d, const PktMsg *request, PktMsg *reply, mDNSBool *trunc)
    694 	{
    695 	fd_set			rset;
    696 	struct timeval	timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
    697 	int				sd;
    698 	int				res;
    699 	mStatus			err = mStatus_NoError;
    700 
    701 	// Initialize
    702 
    703 	*trunc = mDNSfalse;
    704 
    705 	// Create a socket
    706 
    707  	sd = socket( AF_INET, SOCK_DGRAM, 0 );
    708 	require_action( sd >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "socket" ) );
    709 
    710 	// Send the packet to the nameserver
    711 
    712 	VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
    713 		ntohs(request->msg.h.numQuestions),
    714 		ntohs(request->msg.h.numAnswers),
    715 		ntohs(request->msg.h.numAuthorities),
    716 		ntohs(request->msg.h.numAdditionals));
    717 	res = sendto( sd, (char *)&request->msg, request->len, 0, ( struct sockaddr* ) &d->ns_addr, sizeof( d->ns_addr ) );
    718 	require_action( res == (int) request->len, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "sendto" ) );
    719 
    720 	// Wait for reply
    721 
    722 	FD_ZERO( &rset );
    723 	FD_SET( sd, &rset );
    724 	res = select( sd + 1, &rset, NULL, NULL, &timeout );
    725 	require_action( res >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "select" ) );
    726 	require_action( ( res > 0 ) && FD_ISSET( sd, &rset ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - timeout" ) );
    727 
    728 	// Receive reply
    729 
    730 	reply->len = recvfrom( sd, &reply->msg, sizeof(reply->msg), 0, NULL, NULL );
    731 	require_action( ( ( int ) reply->len ) >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "recvfrom" ) );
    732 	require_action( reply->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - Message too short (%d bytes)", reply->len ) );
    733 
    734 	// Check for truncation bit
    735 
    736 	if ( reply->msg.h.flags.b[0] & kDNSFlag0_TC )
    737 		{
    738 		*trunc = mDNStrue;
    739 		}
    740 
    741 exit:
    742 
    743 	if ( sd >= 0 )
    744 		{
    745 		close( sd );
    746 		}
    747 
    748 	return err;
    749 	}
    750 
    751 //
    752 // Dynamic Update Utility Routines
    753 //
    754 
    755 // check if a request and server response complete a successful dynamic update
    756 mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
    757 	{
    758 	char buf[32];
    759 	char *vlogmsg = NULL;
    760 
    761 	// check messages
    762 	if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
    763 	if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
    764 
    765 	// check request operation
    766 	if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
    767 		{ vlogmsg = "Request opcode not an update"; goto failure; }
    768 
    769 	// check result
    770 	if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask)) { vlogmsg = "Reply contains non-zero rcode";  goto failure; }
    771 	if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
    772 		{ vlogmsg = "Reply opcode not an update response"; goto failure; }
    773 
    774 	VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
    775 	return mDNStrue;
    776 
    777 	failure:
    778 	VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
    779 	return mDNSfalse;
    780 	}
    781 
    782 // Allocate an appropriately sized CacheRecord and copy data from original.
    783 // Name pointer in CacheRecord object is set to point to the name specified
    784 //
    785 mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
    786 	{
    787 	CacheRecord *cr;
    788 	size_t size = sizeof(*cr);
    789 	if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
    790 	cr = malloc(size);
    791 	if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
    792 	memcpy(cr, orig, size);
    793 	cr->resrec.rdata = (RData*)&cr->smallrdatastorage;
    794 	cr->resrec.name = name;
    795 
    796 	return cr;
    797 	}
    798 
    799 
    800 //
    801 // Lease Hashtable Utility Routines
    802 //
    803 
    804 // double hash table size
    805 // caller must lock table prior to invocation
    806 mDNSlocal void RehashTable(DaemonInfo *d)
    807 	{
    808 	RRTableElem *ptr, *tmp, **new;
    809 	int i, bucket, newnbuckets = d->nbuckets * 2;
    810 
    811 	VLog("Rehashing lease table (new size %d buckets)", newnbuckets);
    812 	new = malloc(sizeof(RRTableElem *) * newnbuckets);
    813 	if (!new) { LogErr("RehashTable", "malloc");  return; }
    814 	mDNSPlatformMemZero(new, newnbuckets * sizeof(RRTableElem *));
    815 
    816 	for (i = 0; i < d->nbuckets; i++)
    817 		{
    818 		ptr = d->table[i];
    819 		while (ptr)
    820 			{
    821 			bucket = ptr->rr.resrec.namehash % newnbuckets;
    822 			tmp = ptr;
    823 			ptr = ptr->next;
    824 			tmp->next = new[bucket];
    825 			new[bucket] = tmp;
    826 			}
    827 		}
    828 	d->nbuckets = newnbuckets;
    829 	free(d->table);
    830 	d->table = new;
    831 	}
    832 
    833 // print entire contents of hashtable, invoked via SIGINFO
    834 mDNSlocal void PrintLeaseTable(DaemonInfo *d)
    835 	{
    836 	int i;
    837 	RRTableElem *ptr;
    838 	char rrbuf[MaxMsg], addrbuf[16];
    839 	struct timeval now;
    840 	int hr, min, sec;
    841 
    842 	if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
    843 	if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
    844 
    845 	Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
    846 	for (i = 0; i < d->nbuckets; i++)
    847 		{
    848 		for (ptr = d->table[i]; ptr; ptr = ptr->next)
    849 			{
    850 			hr = ((ptr->expire - now.tv_sec) / 60) / 60;
    851 			min = ((ptr->expire - now.tv_sec) / 60) % 60;
    852 			sec = (ptr->expire - now.tv_sec) % 60;
    853 			Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET, &ptr->cli.sin_addr, addrbuf, 16), hr, min, sec,
    854 				GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
    855 			}
    856 		}
    857 	pthread_mutex_unlock(&d->tablelock);
    858 	}
    859 
    860 //
    861 // Startup SRV Registration Routines
    862 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
    863 // the daemon accepts requests
    864 //
    865 
    866 // delete all RRS of a given name/type
    867 mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit,  ResourceRecord *rr)
    868 	{
    869 	ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
    870 	if (!ptr || ptr + 10 >= limit) return NULL;  // out of space
    871 	ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
    872 	ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
    873 	ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8);
    874 	ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY &  0xFF);
    875 	mDNSPlatformMemZero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
    876 	msg->h.mDNS_numUpdates++;
    877 	return ptr + 10;
    878 	}
    879 
    880 mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, DNSZone * zone, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSIPPort port, mDNSBool registration)
    881 	{
    882 	AuthRecord rr;
    883 	char hostname[1024], buf[MaxMsg];
    884 	mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
    885 
    886 	( void ) d;
    887 
    888 	mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, AuthRecordAny, NULL, NULL);
    889 	rr.resrec.rrclass = kDNSClass_IN;
    890 	rr.resrec.rdata->u.srv.priority = 0;
    891 	rr.resrec.rdata->u.srv.weight   = 0;
    892 	rr.resrec.rdata->u.srv.port     = port;
    893 	if (gethostname(hostname, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
    894 		rr.resrec.rdata->u.srv.target.c[0] = '\0';
    895 
    896 	MakeDomainNameFromDNSNameString(&rr.namestorage, regtype);
    897 	AppendDomainName(&rr.namestorage, &zone->name);
    898 	VLog("%s  %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
    899 		 GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
    900 	if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
    901 	else              ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
    902 	return ptr;
    903 	}
    904 
    905 
    906 // perform dynamic update.
    907 // specify deletion by passing false for the register parameter, otherwise register the records.
    908 mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
    909 	{
    910 	TCPSocket *sock = NULL;
    911 	DNSZone * zone;
    912 	int err = mStatus_NoError;
    913 
    914 	sock = ConnectToServer( d );
    915 	require_action( sock, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: ConnectToServer failed" ) );
    916 
    917 	for ( zone = d->zones; zone; zone = zone->next )
    918 		{
    919 		PktMsg pkt;
    920 		mDNSu8 *ptr = pkt.msg.data;
    921 		mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
    922 		PktMsg *reply = NULL;
    923 		mDNSBool closed;
    924 		mDNSBool ok;
    925 
    926 		// Initialize message
    927 		InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
    928 		pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
    929 		pkt.src.sin_family = AF_INET;
    930 
    931 		// format message body
    932 		ptr = putZone(&pkt.msg, ptr, end, &zone->name, mDNSOpaque16fromIntVal(kDNSClass_IN));
    933 		require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    934 
    935 	   if ( zone->type == kDNSZonePrivate )
    936             {
    937             ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls._tcp.", d->private_port, registration);
    938             require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    939             ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls._tcp.", d->private_port, registration);
    940             require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    941             ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls._tcp.", d->private_port, registration);
    942             require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    943 
    944 			if ( !registration )
    945 				{
    946 				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
    947 				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    948 				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
    949 				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    950 				}
    951 			}
    952         else
    953             {
    954 			if ( !registration )
    955 				{
    956 				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls.", d->private_port, registration);
    957 				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    958 				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls.", d->private_port, registration);
    959 				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    960 				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls.", d->private_port, registration);
    961 				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    962 				}
    963 
    964 			ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
    965             require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    966             ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
    967             require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
    968 			}
    969 
    970 		HdrHToN(&pkt);
    971 
    972 		if ( zone->updateKeys )
    973 			{
    974 			DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 );
    975 			require_action( ptr, exit, Log("UpdateSRV: Error constructing lease expiration update" ) );
    976 			}
    977 
    978 		pkt.len = ptr - (mDNSu8 *)&pkt.msg;
    979 
    980 		// send message, receive reply
    981 
    982 		err = SendPacket( sock, &pkt );
    983 		require_action( !err, exit, Log( "UpdateSRV: SendPacket failed" ) );
    984 
    985 		reply = RecvPacket( sock, NULL, &closed );
    986 		require_action( reply, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: RecvPacket returned NULL" ) );
    987 
    988 		ok = SuccessfulUpdateTransaction( &pkt, reply );
    989 
    990 		if ( !ok )
    991 			{
    992 			Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
    993 			}
    994 
    995 		free( reply );
    996 		}
    997 
    998 exit:
    999 
   1000 	if ( sock )
   1001 		{
   1002 		mDNSPlatformTCPCloseConnection( sock );
   1003 		}
   1004 
   1005 	return err;
   1006 	}
   1007 
   1008 // wrapper routines/macros
   1009 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
   1010 
   1011 // clear any existing records prior to registration
   1012 mDNSlocal int SetUpdateSRV(DaemonInfo *d)
   1013 	{
   1014 	int err;
   1015 
   1016 	err = ClearUpdateSRV(d);         // clear any existing record
   1017 	if (!err) err = UpdateSRV(d, 1);
   1018 	return err;
   1019 	}
   1020 
   1021 //
   1022 // Argument Parsing and Configuration
   1023 //
   1024 
   1025 mDNSlocal void PrintUsage(void)
   1026 	{
   1027 	fprintf(stderr, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
   1028 			"Use \"dnsextd -h\" for help\n");
   1029 	}
   1030 
   1031 mDNSlocal void PrintHelp(void)
   1032 	{
   1033 	fprintf(stderr, "\n\n");
   1034 	PrintUsage();
   1035 
   1036 	fprintf(stderr,
   1037 			"dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
   1038             "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
   1039 			"that do not natively support these extensions.  (See dns-sd.org for more info on DNS Service\n"
   1040 			"Discovery, Update Leases, and Long Lived Queries.)\n\n"
   1041 
   1042             "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
   1043             "and Long Lived Queries are to be administered.  dnsextd communicates directly with the\n"
   1044 			"primary master server for this zone.\n\n"
   1045 
   1046 			"The options are as follows:\n\n"
   1047 
   1048 			"-f    Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
   1049 
   1050 			"-d    Run daemon in foreground.\n\n"
   1051 
   1052 			"-h    Print help.\n\n"
   1053 
   1054 			"-v    Verbose output.\n\n"
   1055 		);
   1056 	}
   1057 
   1058 
   1059 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
   1060 // returns 0 (success) if program is to continue execution
   1061 // output control arguments (-f, -v) do not affect this routine
   1062 mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
   1063 	{
   1064 	DNSZone	*	zone;
   1065 	int			opt;
   1066 	int			err = 0;
   1067 
   1068 	cfgfile = strdup( CONFIG_FILE );
   1069 	require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr );
   1070 
   1071     // defaults, may be overriden by command option
   1072 
   1073 	// setup our sockaddr
   1074 
   1075 	mDNSPlatformMemZero( &d->addr, sizeof( d->addr ) );
   1076 	d->addr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
   1077 	d->addr.sin_port		= UnicastDNSPort.NotAnInteger;
   1078 	d->addr.sin_family		= AF_INET;
   1079 #ifndef NOT_HAVE_SA_LEN
   1080 	d->addr.sin_len			= sizeof( d->addr );
   1081 #endif
   1082 
   1083 	// setup nameserver's sockaddr
   1084 
   1085 	mDNSPlatformMemZero(&d->ns_addr, sizeof(d->ns_addr));
   1086 	d->ns_addr.sin_family	= AF_INET;
   1087 	inet_pton( AF_INET, LOOPBACK, &d->ns_addr.sin_addr );
   1088 	d->ns_addr.sin_port		= NSIPCPort.NotAnInteger;
   1089 #ifndef NOT_HAVE_SA_LEN
   1090 	d->ns_addr.sin_len		= sizeof( d->ns_addr );
   1091 #endif
   1092 
   1093 	// setup our ports
   1094 
   1095 	d->private_port = PrivateDNSPort;
   1096 	d->llq_port     = DNSEXTPort;
   1097 
   1098 	while ((opt = getopt(argc, argv, "f:hdv")) != -1)
   1099 		{
   1100 		switch(opt)
   1101 			{
   1102 			case 'f': free( cfgfile ); cfgfile = strdup( optarg ); require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr ); break;
   1103 			case 'h': PrintHelp();    return -1;
   1104 			case 'd': foreground = 1; break;		// Also used when launched via OS X's launchd mechanism
   1105 			case 'v': verbose = 1;    break;
   1106 			default:  goto arg_error;
   1107 			}
   1108 		}
   1109 
   1110 	err = ParseConfig( d, cfgfile );
   1111 	require_noerr( err, arg_error );
   1112 
   1113 	// Make sure we've specified some zones
   1114 
   1115 	require_action( d->zones, arg_error, err = mStatus_UnknownErr );
   1116 
   1117 	// if we have a shared secret, use it for the entire zone
   1118 
   1119 	for ( zone = d->zones; zone; zone = zone->next )
   1120 		{
   1121 		if ( zone->updateKeys )
   1122 			{
   1123 			AssignDomainName( &zone->updateKeys->domain, &zone->name );
   1124 			}
   1125 		}
   1126 
   1127 	return 0;
   1128 
   1129 arg_error:
   1130 
   1131 	PrintUsage();
   1132 	return -1;
   1133 	}
   1134 
   1135 
   1136 //
   1137 // Initialization Routines
   1138 //
   1139 
   1140 // Allocate memory, initialize locks and bookkeeping variables
   1141 mDNSlocal int InitLeaseTable(DaemonInfo *d)
   1142 	{
   1143 	if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
   1144 	d->nbuckets = LEASETABLE_INIT_NBUCKETS;
   1145 	d->nelems = 0;
   1146 	d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
   1147 	if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; }
   1148 	mDNSPlatformMemZero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
   1149 	return 0;
   1150 	}
   1151 
   1152 
   1153 mDNSlocal int
   1154 SetupSockets
   1155 	(
   1156 	DaemonInfo * self
   1157 	)
   1158 	{
   1159 	static const int kOn = 1;
   1160 	int					sockpair[2];
   1161 	mDNSBool			private = mDNSfalse;
   1162 	struct sockaddr_in	daddr;
   1163 	DNSZone			*	zone;
   1164 	mStatus				err = 0;
   1165 
   1166 	// set up sockets on which we all ns requests
   1167 
   1168 	self->tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
   1169 	require_action( dnssd_SocketValid(self->tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
   1170 
   1171 #if defined(SO_REUSEADDR)
   1172 	err = setsockopt(self->tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
   1173 	require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
   1174 #endif
   1175 
   1176 	err = bind( self->tcpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
   1177 	require_action( !err, exit, LogErr( "SetupSockets", "bind self->tcpsd" ) );
   1178 
   1179 	err = listen( self->tcpsd, LISTENQ );
   1180 	require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
   1181 
   1182 	self->udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
   1183 	require_action( dnssd_SocketValid(self->udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
   1184 
   1185 #if defined(SO_REUSEADDR)
   1186 	err = setsockopt(self->udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
   1187 	require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
   1188 #endif
   1189 
   1190 	err = bind( self->udpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
   1191 	require_action( !err, exit, LogErr( "SetupSockets", "bind self->udpsd" ) );
   1192 
   1193 	// set up sockets on which we receive llq requests
   1194 
   1195 	mDNSPlatformMemZero(&self->llq_addr, sizeof(self->llq_addr));
   1196 	self->llq_addr.sin_family		= AF_INET;
   1197 	self->llq_addr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
   1198 	self->llq_addr.sin_port			= ( self->llq_port.NotAnInteger ) ? self->llq_port.NotAnInteger : DNSEXTPort.NotAnInteger;
   1199 
   1200 	if (self->llq_addr.sin_port == self->addr.sin_port)
   1201 		{
   1202 		self->llq_tcpsd = self->tcpsd;
   1203 		self->llq_udpsd = self->udpsd;
   1204 		}
   1205 	else
   1206 		{
   1207 		self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
   1208 		require_action( dnssd_SocketValid(self->llq_tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
   1209 
   1210 #if defined(SO_REUSEADDR)
   1211 		err = setsockopt(self->llq_tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
   1212 		require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
   1213 #endif
   1214 
   1215 		err = bind( self->llq_tcpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
   1216 		require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
   1217 
   1218 		err = listen( self->llq_tcpsd, LISTENQ );
   1219 		require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
   1220 
   1221 		self->llq_udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
   1222 		require_action( dnssd_SocketValid(self->llq_udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
   1223 
   1224 #if defined(SO_REUSEADDR)
   1225 		err = setsockopt(self->llq_udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
   1226 		require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
   1227 #endif
   1228 
   1229 		err = bind(self->llq_udpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
   1230 		require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
   1231 		}
   1232 
   1233 	// set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
   1234 
   1235 	err = socketpair( AF_LOCAL, SOCK_STREAM, 0, sockpair );
   1236 	require_action( !err, exit, LogErr( "SetupSockets", "socketpair" ) );
   1237 
   1238 	self->LLQEventListenSock = sockpair[0];
   1239 	self->LLQEventNotifySock = sockpair[1];
   1240 
   1241 	// set up socket on which we receive private requests
   1242 
   1243 	self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
   1244 	require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
   1245 	mDNSPlatformMemZero(&daddr, sizeof(daddr));
   1246 	daddr.sin_family		= AF_INET;
   1247 	daddr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
   1248 	daddr.sin_port			= ( self->private_port.NotAnInteger ) ? self->private_port.NotAnInteger : PrivateDNSPort.NotAnInteger;
   1249 
   1250 	self->tlssd = socket( AF_INET, SOCK_STREAM, 0 );
   1251 	require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
   1252 
   1253 #if defined(SO_REUSEADDR)
   1254 	err = setsockopt(self->tlssd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
   1255 	require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
   1256 #endif
   1257 
   1258 	err = bind( self->tlssd, ( struct sockaddr* ) &daddr, sizeof( daddr ) );
   1259 	require_action( !err, exit, LogErr( "SetupSockets", "bind self->tlssd" ) );
   1260 
   1261 	err = listen( self->tlssd, LISTENQ );
   1262 	require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
   1263 
   1264 	// Do we have any private zones?
   1265 
   1266 	for ( zone = self->zones; zone; zone = zone->next )
   1267 		{
   1268 		if ( zone->type == kDNSZonePrivate )
   1269 			{
   1270 			private = mDNStrue;
   1271 			break;
   1272 			}
   1273 		}
   1274 
   1275 	if ( private )
   1276 		{
   1277 		err = mDNSPlatformTLSSetupCerts();
   1278 		require_action( !err, exit, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
   1279 		}
   1280 
   1281 exit:
   1282 
   1283 	return err;
   1284 	}
   1285 
   1286 //
   1287 // periodic table updates
   1288 //
   1289 
   1290 // Delete a resource record from the nameserver via a dynamic update
   1291 // sd is a socket already connected to the server
   1292 mDNSlocal void DeleteOneRecord(DaemonInfo *d, CacheRecord *rr, domainname *zname, TCPSocket *sock)
   1293 	{
   1294 	DNSZone	*	zone;
   1295 	PktMsg pkt;
   1296 	mDNSu8 *ptr = pkt.msg.data;
   1297 	mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
   1298 	char buf[MaxMsg];
   1299 	mDNSBool closed;
   1300 	PktMsg *reply = NULL;
   1301 
   1302 	VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));
   1303 
   1304 	InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
   1305 
   1306 	ptr = putZone(&pkt.msg, ptr, end, zname, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
   1307 	if (!ptr) goto end;
   1308 	ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
   1309 	if (!ptr) goto end;
   1310 
   1311 	HdrHToN(&pkt);
   1312 
   1313 	zone = FindZone( d, zname );
   1314 
   1315 	if ( zone && zone->updateKeys)
   1316 		{
   1317 		DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 );
   1318 		if (!ptr) goto end;
   1319 		}
   1320 
   1321 	pkt.len = ptr - (mDNSu8 *)&pkt.msg;
   1322 	pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
   1323 	pkt.src.sin_family = AF_INET;
   1324 	if (SendPacket( sock, &pkt)) { Log("DeleteOneRecord: SendPacket failed"); }
   1325 	reply = RecvPacket( sock, NULL, &closed );
   1326 	if (reply) HdrNToH(reply);
   1327 	require_action( reply, end, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
   1328 
   1329 	if (!SuccessfulUpdateTransaction(&pkt, reply))
   1330 		Log("Expiration update failed with rcode %d", reply ? reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask : -1);
   1331 
   1332 	end:
   1333 	if (!ptr) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
   1334 	if (reply) free(reply);
   1335 	}
   1336 
   1337 // iterate over table, deleting expired records (or all records if DeleteAll is true)
   1338 mDNSlocal void DeleteRecords(DaemonInfo *d, mDNSBool DeleteAll)
   1339 	{
   1340 	struct timeval now;
   1341 	int i;
   1342 	TCPSocket *sock = ConnectToServer(d);
   1343 	if (!sock) { Log("DeleteRecords: ConnectToServer failed"); return; }
   1344 	if (gettimeofday(&now, NULL)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
   1345 	if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
   1346 
   1347 	for (i = 0; i < d->nbuckets; i++)
   1348 		{
   1349 		RRTableElem **ptr = &d->table[i];
   1350 		while (*ptr)
   1351 			{
   1352 			if (DeleteAll || (*ptr)->expire - now.tv_sec < 0)
   1353 				{
   1354 				RRTableElem *fptr;
   1355 				// delete record from server
   1356 				DeleteOneRecord(d, &(*ptr)->rr, &(*ptr)->zone, sock);
   1357 				fptr = *ptr;
   1358 				*ptr = (*ptr)->next;
   1359 				free(fptr);
   1360 				d->nelems--;
   1361 				}
   1362 			else ptr = &(*ptr)->next;
   1363 			}
   1364 		}
   1365 	pthread_mutex_unlock(&d->tablelock);
   1366 	mDNSPlatformTCPCloseConnection( sock );
   1367 	}
   1368 
   1369 //
   1370 // main update request handling
   1371 //
   1372 
   1373 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
   1374 mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
   1375 	{
   1376 	RRTableElem **rptr, *tmp;
   1377 	int i, allocsize, bucket;
   1378 	LargeCacheRecord lcr;
   1379 	ResourceRecord *rr = &lcr.r.resrec;
   1380 	const mDNSu8 *ptr, *end;
   1381 	struct timeval tv;
   1382 	DNSQuestion zone;
   1383 	char buf[MaxMsg];
   1384 
   1385 	if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
   1386 	HdrNToH(pkt);
   1387 	ptr = pkt->msg.data;
   1388 	end = (mDNSu8 *)&pkt->msg + pkt->len;
   1389 	ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
   1390 	if (!ptr) { Log("UpdateLeaseTable: cannot read zone");  goto cleanup; }
   1391 	ptr = LocateAuthorities(&pkt->msg, end);
   1392 	if (!ptr) { Log("UpdateLeaseTable: Format error");  goto cleanup; }
   1393 
   1394 	for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
   1395 		{
   1396 		mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
   1397 
   1398 		ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
   1399 		if (!ptr || lcr.r.resrec.RecordType == kDNSRecordTypePacketNegative) { Log("UpdateLeaseTable: GetLargeResourceRecord failed"); goto cleanup; }
   1400 		bucket = rr->namehash % d->nbuckets;
   1401 		rptr = &d->table[bucket];
   1402 
   1403 		// handle deletions
   1404 		if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
   1405 			DeleteAllRRSets = mDNStrue; // delete all rrsets for a name
   1406 		else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
   1407 			DeleteOneRRSet = mDNStrue;
   1408 		else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE)
   1409 			DeleteOneRR = mDNStrue;
   1410 
   1411 		if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR)
   1412 			{
   1413 			while (*rptr)
   1414 			  {
   1415 			  if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
   1416 				 (DeleteAllRRSets ||
   1417 				 (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
   1418 				  (DeleteOneRR && IdenticalResourceRecord(&(*rptr)->rr.resrec, rr))))
   1419 				  {
   1420 				  tmp = *rptr;
   1421 				  VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
   1422 				  *rptr = (*rptr)->next;
   1423 				  free(tmp);
   1424 				  d->nelems--;
   1425 				  }
   1426 			  else rptr = &(*rptr)->next;
   1427 			  }
   1428 			}
   1429 		else if (lease > 0)
   1430 			{
   1431 			// see if add or refresh
   1432 			while (*rptr && !IdenticalResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
   1433 			if (*rptr)
   1434 				{
   1435 				// refresh
   1436 				if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
   1437 				(*rptr)->expire = tv.tv_sec + (unsigned)lease;
   1438 				VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
   1439 				}
   1440 			else
   1441 				{
   1442 				// New record - add to table
   1443 				if (d->nelems > d->nbuckets)
   1444 					{
   1445 					RehashTable(d);
   1446 					bucket = rr->namehash % d->nbuckets;
   1447 					rptr = &d->table[bucket];
   1448 					}
   1449 				if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
   1450 				allocsize = sizeof(RRTableElem);
   1451 				if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
   1452 				tmp = malloc(allocsize);
   1453 				if (!tmp) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
   1454 				memcpy(&tmp->rr, &lcr.r, sizeof(CacheRecord) + rr->rdlength - InlineCacheRDSize);
   1455 				tmp->rr.resrec.rdata = (RData *)&tmp->rr.smallrdatastorage;
   1456 				AssignDomainName(&tmp->name, rr->name);
   1457 				tmp->rr.resrec.name = &tmp->name;
   1458 				tmp->expire = tv.tv_sec + (unsigned)lease;
   1459 				tmp->cli.sin_addr = pkt->src.sin_addr;
   1460 				AssignDomainName(&tmp->zone, &zone.qname);
   1461 				tmp->next = d->table[bucket];
   1462 				d->table[bucket] = tmp;
   1463 				d->nelems++;
   1464 				VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
   1465 				}
   1466 			}
   1467 		}
   1468 
   1469 	cleanup:
   1470 	pthread_mutex_unlock(&d->tablelock);
   1471 	HdrHToN(pkt);
   1472 	}
   1473 
   1474 // Given a successful reply from a server, create a new reply that contains lease information
   1475 // Replies are currently not signed !!!KRS change this
   1476 mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
   1477 	{
   1478 	PktMsg *reply;
   1479 	mDNSu8 *ptr, *end;
   1480 	mDNSOpaque16 flags;
   1481 
   1482 	(void)d;  //unused
   1483 	reply = malloc(sizeof(*reply));
   1484 	if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
   1485 	flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
   1486 	flags.b[1] = 0;
   1487 
   1488 	InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
   1489 	reply->src.sin_addr.s_addr = zerov4Addr.NotAnInteger;            // unused except for log messages
   1490 	reply->src.sin_family = AF_INET;
   1491 	ptr = reply->msg.data;
   1492 	end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage);
   1493 	ptr = putUpdateLease(&reply->msg, ptr, lease);
   1494 	if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }
   1495 	reply->len = ptr - (mDNSu8 *)&reply->msg;
   1496 	HdrHToN(reply);
   1497 	return reply;
   1498 	}
   1499 
   1500 
   1501 // pkt is thread-local, not requiring locking
   1502 
   1503 mDNSlocal PktMsg*
   1504 HandleRequest
   1505 	(
   1506 	DaemonInfo	*	self,
   1507 	PktMsg		*	request
   1508 	)
   1509 	{
   1510 	PktMsg		*	reply = NULL;
   1511 	PktMsg		*	leaseReply;
   1512 	PktMsg	 		buf;
   1513 	char			addrbuf[32];
   1514 	TCPSocket *	sock = NULL;
   1515 	mStatus			err;
   1516 	mDNSs32		lease = 0;
   1517 	if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) == kDNSFlag0_OP_Update)
   1518 		{
   1519 		int i, adds = 0, dels = 0;
   1520 		const mDNSu8 *ptr, *end = (mDNSu8 *)&request->msg + request->len;
   1521 		HdrNToH(request);
   1522 		lease = GetPktLease(&mDNSStorage, &request->msg, end);
   1523 		ptr = LocateAuthorities(&request->msg, end);
   1524 		for (i = 0; i < request->msg.h.mDNS_numUpdates; i++)
   1525 			{
   1526 			LargeCacheRecord lcr;
   1527 			ptr = GetLargeResourceRecord(NULL, &request->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
   1528 			if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rroriginalttl) adds++; else dels++;
   1529 			}
   1530 		HdrHToN(request);
   1531 		if (adds && !lease)
   1532 			{
   1533 			static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } };
   1534 			Log("Rejecting Update Request with %d additions but no lease", adds);
   1535 			reply = malloc(sizeof(*reply));
   1536 			mDNSPlatformMemZero(&reply->src, sizeof(reply->src));
   1537 			reply->len = sizeof(DNSMessageHeader);
   1538 			reply->zone = NULL;
   1539 			reply->isZonePublic = 0;
   1540 			InitializeDNSMessage(&reply->msg.h, request->msg.h.id, UpdateRefused);
   1541 			return(reply);
   1542 			}
   1543 		if (lease > 7200)	// Don't allow lease greater than two hours; typically 90-minute renewal period
   1544 			lease = 7200;
   1545 		}
   1546 	// Send msg to server, read reply
   1547 
   1548 	if ( request->len <= 512 )
   1549 		{
   1550 		mDNSBool trunc;
   1551 
   1552 		if ( UDPServerTransaction( self, request, &buf, &trunc) < 0 )
   1553 			{
   1554 			Log("HandleRequest - UDPServerTransaction failed.  Trying TCP");
   1555 			}
   1556 		else if ( trunc )
   1557 			{
   1558 			VLog("HandleRequest - answer truncated.  Using TCP");
   1559 			}
   1560 		else
   1561 			{
   1562 			reply = &buf; // success
   1563 			}
   1564 		}
   1565 
   1566 	if ( !reply )
   1567 		{
   1568 		mDNSBool closed;
   1569 		int res;
   1570 
   1571 		sock = ConnectToServer( self );
   1572 		require_action_quiet( sock, exit, err = mStatus_UnknownErr ; Log( "Discarding request from %s due to connection errors", inet_ntop( AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
   1573 
   1574 		res = SendPacket( sock, request );
   1575 		require_action_quiet( res >= 0, exit, err = mStatus_UnknownErr ; Log( "Couldn't relay message from %s to server.  Discarding.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
   1576 
   1577 		reply = RecvPacket( sock, &buf, &closed );
   1578 		}
   1579 
   1580 	// IMPORTANT: reply is in network byte order at this point in the code
   1581 	// We keep it this way because we send it back to the client in the same form
   1582 
   1583 	// Is it an update?
   1584 
   1585 	if ( reply && ( ( reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( kDNSFlag0_OP_Update | kDNSFlag0_QR_Response ) ) )
   1586 		{
   1587 		char 		pingmsg[4];
   1588 		mDNSBool	ok = SuccessfulUpdateTransaction( request, reply );
   1589 		require_action( ok, exit, err = mStatus_UnknownErr; VLog( "Message from %s not a successful update.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
   1590 
   1591 		UpdateLeaseTable( request, self, lease );
   1592 
   1593 		if ( lease > 0 )
   1594 			{
   1595 			leaseReply = FormatLeaseReply( self, reply, lease );
   1596 
   1597 			if ( !leaseReply )
   1598 				{
   1599 				Log("HandleRequest - unable to format lease reply");
   1600 				}
   1601 
   1602 			// %%% Looks like a potential memory leak -- who frees the original reply?
   1603 			reply = leaseReply;
   1604 			}
   1605 
   1606 		// tell the main thread there was an update so it can send LLQs
   1607 
   1608 		if ( send( self->LLQEventNotifySock, pingmsg, sizeof( pingmsg ), 0 ) != sizeof( pingmsg ) )
   1609 			{
   1610 			LogErr("HandleRequest", "send");
   1611 			}
   1612 		}
   1613 
   1614 exit:
   1615 
   1616 	if ( sock )
   1617 		{
   1618 		mDNSPlatformTCPCloseConnection( sock );
   1619 		}
   1620 
   1621 	if ( reply == &buf )
   1622 		{
   1623 		reply = malloc( sizeof( *reply ) );
   1624 
   1625 		if ( reply )
   1626 			{
   1627 			reply->len = buf.len;
   1628 			memcpy(&reply->msg, &buf.msg, buf.len);
   1629 			}
   1630 		else
   1631 			{
   1632 			LogErr("HandleRequest", "malloc");
   1633 			}
   1634 		}
   1635 
   1636 	return reply;
   1637 	}
   1638 
   1639 
   1640 //
   1641 // LLQ Support Routines
   1642 //
   1643 
   1644 // Set fields of an LLQ OPT Resource Record
   1645 mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, const mDNSOpaque64 *const id, mDNSs32 lease)
   1646 	{
   1647 	mDNSPlatformMemZero(opt, sizeof(*opt));
   1648 	mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
   1649 	opt->resrec.rrclass = NormalMaxDNSMessageData;
   1650 	opt->resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
   1651 	opt->resrec.rdestimate = sizeof(rdataOPT);
   1652 	opt->resrec.rdata->u.opt[0].opt = kDNSOpt_LLQ;
   1653 	opt->resrec.rdata->u.opt[0].u.llq.vers  = kLLQ_Vers;
   1654 	opt->resrec.rdata->u.opt[0].u.llq.llqOp = opcode;
   1655 	opt->resrec.rdata->u.opt[0].u.llq.err   = LLQErr_NoError;
   1656 	opt->resrec.rdata->u.opt[0].u.llq.id    = *id;
   1657 	opt->resrec.rdata->u.opt[0].u.llq.llqlease = lease;
   1658 	}
   1659 
   1660 // Calculate effective remaining lease of an LLQ
   1661 mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
   1662 	{
   1663 	struct timeval t;
   1664 
   1665 	gettimeofday(&t, NULL);
   1666 	if (e->expire < t.tv_sec) return 0;
   1667 	else return e->expire - t.tv_sec;
   1668 	}
   1669 
   1670 mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
   1671 	{
   1672 	int  bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
   1673 	LLQEntry **ptr = &d->LLQTable[bucket];
   1674 	AnswerListElem *a = e->AnswerList;
   1675 	char addr[32];
   1676 
   1677 	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
   1678 	VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
   1679 
   1680 	if (a && !(--a->refcount) && d->AnswerTableCount >= LLQ_TABLESIZE)
   1681 		{
   1682 		// currently, generating initial answers blocks the main thread, so we keep the answer list
   1683 		// even if the ref count drops to zero.  To prevent unbounded table growth, we free shared answers
   1684 		// if the ref count drops to zero AND there are more table elements than buckets
   1685 		// !!!KRS update this when we make the table dynamically growable
   1686 
   1687 		CacheRecord *cr = a->KnownAnswers, *tmp;
   1688 		AnswerListElem **tbl = &d->AnswerTable[bucket];
   1689 
   1690 		while (cr)
   1691 			{
   1692 			tmp = cr;
   1693 			cr = cr->next;
   1694 			free(tmp);
   1695 			}
   1696 
   1697 		while (*tbl && *tbl != a) tbl = &(*tbl)->next;
   1698 		if (*tbl) { *tbl = (*tbl)->next; free(a); d->AnswerTableCount--; }
   1699 		else Log("Error: DeleteLLQ - AnswerList not found in table");
   1700 		}
   1701 
   1702 	// remove LLQ from table, free memory
   1703 	while(*ptr && *ptr != e) ptr = &(*ptr)->next;
   1704 	if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
   1705 	*ptr = (*ptr)->next;
   1706 	free(e);
   1707 	}
   1708 
   1709 mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst, TCPSocket *sock)
   1710 	{
   1711 	char addr[32];
   1712 	int err = -1;
   1713 
   1714 	HdrHToN(pkt);
   1715 
   1716 	if ( sock )
   1717 		{
   1718 		if ( SendPacket( sock, pkt ) != 0 )
   1719 			{
   1720 			LogErr("DaemonInfo", "MySend");
   1721 			Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
   1722 			}
   1723 		}
   1724 	else
   1725 		{
   1726 		if (sendto(d->llq_udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
   1727 			{
   1728 			LogErr("DaemonInfo", "sendto");
   1729 			Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
   1730 			}
   1731 		}
   1732 
   1733 	err = 0;
   1734 	HdrNToH(pkt);
   1735 	return err;
   1736 	}
   1737 
   1738 mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e)
   1739 	{
   1740 	PktMsg q;
   1741 	int i;
   1742 	TCPSocket *sock = NULL;
   1743 	const mDNSu8 *ansptr;
   1744 	mDNSu8 *end = q.msg.data;
   1745 	PktMsg buf, *reply = NULL;
   1746 	LargeCacheRecord lcr;
   1747 	CacheRecord *AnswerList = NULL;
   1748 	mDNSu8 rcode;
   1749 
   1750 	VLog("Querying server for %##s type %d", e->name.c, e->type);
   1751 
   1752 	InitializeDNSMessage(&q.msg.h, zeroID, uQueryFlags);
   1753 
   1754 	end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
   1755 	if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
   1756 	q.len = (int)(end - (mDNSu8 *)&q.msg);
   1757 
   1758 	HdrHToN(&q);
   1759 
   1760 	if (!e->UseTCP)
   1761 		{
   1762 		mDNSBool trunc;
   1763 
   1764 		if (UDPServerTransaction(d, &q, &buf, &trunc) < 0)
   1765 			Log("AnswerQuestion %##s - UDPServerTransaction failed.  Trying TCP", e->name.c);
   1766 		else if (trunc)
   1767 			{ VLog("AnswerQuestion %##s - answer truncated.  Using TCP", e->name.c); e->UseTCP = mDNStrue; }
   1768 		else reply = &buf;  // success
   1769 		}
   1770 
   1771 	if (!reply)
   1772 		{
   1773 		mDNSBool closed;
   1774 
   1775 		sock = ConnectToServer(d);
   1776 		if (!sock) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
   1777 		if (SendPacket( sock, &q)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock ); goto end; }
   1778 		reply = RecvPacket( sock, NULL, &closed );
   1779 		mDNSPlatformTCPCloseConnection( sock );
   1780 		require_action( reply, end, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
   1781 		}
   1782 
   1783 	HdrNToH(&q);
   1784 	if (reply) HdrNToH(reply);
   1785 
   1786 	if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
   1787 		{ Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
   1788 	rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
   1789 	if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->name.c, e->type, rcode); goto end; }
   1790 
   1791 	end = (mDNSu8 *)&reply->msg + reply->len;
   1792 	ansptr = LocateAnswers(&reply->msg, end);
   1793 	if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
   1794 
   1795 	for (i = 0; i < reply->msg.h.numAnswers; i++)
   1796 		{
   1797 		ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
   1798 		if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
   1799 		if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative)
   1800 			{
   1801 			if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
   1802 				{
   1803 				Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
   1804 					  lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
   1805 				}
   1806 			else
   1807 				{
   1808 				CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
   1809 				if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
   1810 				cr->next = AnswerList;
   1811 				AnswerList = cr;
   1812 				}
   1813 			}
   1814 		}
   1815 
   1816 	end:
   1817 	if (reply && reply != &buf) free(reply);
   1818 	return AnswerList;
   1819 	}
   1820 
   1821 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
   1822 mDNSlocal void *UpdateAnswerList(void *args)
   1823 	{
   1824 	CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
   1825 	DaemonInfo *d = ((UpdateAnswerListArgs *)args)->d;
   1826 	AnswerListElem *a = ((UpdateAnswerListArgs *)args)->a;
   1827 
   1828 	free(args);
   1829 	args = NULL;
   1830 
   1831 	// get up to date answers
   1832 	NewAnswers = AnswerQuestion(d, a);
   1833 
   1834 	// first pass - mark all answers for deletion
   1835 	for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
   1836 		(*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
   1837 
   1838 	// second pass - mark answers pre-existent
   1839 	for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
   1840 		{
   1841 		for (na = &NewAnswers; *na; na = &(*na)->next)
   1842 			{
   1843 			if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec))
   1844 				{ (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
   1845 			}
   1846 		}
   1847 
   1848 	// third pass - add new records to Event list
   1849 	na = &NewAnswers;
   1850 	while (*na)
   1851 		{
   1852 		for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
   1853 			if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
   1854 		if (!*ka)
   1855 			{
   1856 			// answer is not in list - splice from NewAnswers list, add to Event list
   1857 			cr = *na;
   1858 			*na = (*na)->next;        // splice from list
   1859 			cr->next = a->EventList;  // add spliced record to event list
   1860 			a->EventList = cr;
   1861 			cr->resrec.rroriginalttl = 1; // 1 means add
   1862 			}
   1863 		else na = &(*na)->next;
   1864 		}
   1865 
   1866 	// move all the removes from the answer list to the event list
   1867 	ka = &a->KnownAnswers;
   1868 	while (*ka)
   1869 		{
   1870 		if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
   1871 			{
   1872 			cr = *ka;
   1873 			*ka = (*ka)->next;
   1874 			cr->next = a->EventList;
   1875 			a->EventList = cr;
   1876 			}
   1877 		else ka = &(*ka)->next;
   1878 		}
   1879 
   1880 	// lastly, free the remaining records (known answers) in NewAnswers list
   1881 	while (NewAnswers)
   1882 		{
   1883 		cr = NewAnswers;
   1884 		NewAnswers = NewAnswers->next;
   1885 		free(cr);
   1886 		}
   1887 
   1888 	return NULL;
   1889 	}
   1890 
   1891 mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
   1892 	{
   1893 	PktMsg  response;
   1894 	CacheRecord *cr;
   1895 	mDNSu8 *end = (mDNSu8 *)&response.msg.data;
   1896 	mDNSOpaque16 msgID;
   1897 	char rrbuf[MaxMsg], addrbuf[32];
   1898 	AuthRecord opt;
   1899 
   1900 	// Should this really be random?  Do we use the msgID on the receiving end?
   1901 	msgID.NotAnInteger = random();
   1902 	if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
   1903 	InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
   1904 	end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
   1905 	if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
   1906 
   1907 	// put adds/removes in packet
   1908 	for (cr = e->AnswerList->EventList; cr; cr = cr->next)
   1909 		{
   1910 		if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
   1911 		VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf);
   1912 		end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
   1913 		if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
   1914 		}
   1915 
   1916 	FormatLLQOpt(&opt, kLLQOp_Event, &e->id, LLQLease(e));
   1917 	end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
   1918 	if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
   1919 
   1920 	response.len = (int)(end - (mDNSu8 *)&response.msg);
   1921 	if (SendLLQ(d, &response, e->cli, NULL ) < 0) LogMsg("Error: SendEvents - SendLLQ");
   1922 	}
   1923 
   1924 mDNSlocal void PrintLLQAnswers(DaemonInfo *d)
   1925 	{
   1926 	int i;
   1927 	char rrbuf[MaxMsg];
   1928 
   1929 	Log("Printing LLQ Answer Table contents");
   1930 
   1931 	for (i = 0; i < LLQ_TABLESIZE; i++)
   1932 		{
   1933 		AnswerListElem *a = d->AnswerTable[i];
   1934 		while(a)
   1935 			{
   1936 			int ancount = 0;
   1937 			const CacheRecord *rr = a->KnownAnswers;
   1938 			while (rr) { ancount++; rr = rr->next; }
   1939 			Log("%p : Question %##s;  type %d;  referenced by %d LLQs; %d answers:", a, a->name.c, a->type, a->refcount, ancount);
   1940 			for (rr = a->KnownAnswers; rr; rr = rr->next) Log("\t%s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, rrbuf));
   1941 			a = a->next;
   1942 			}
   1943 		}
   1944 	}
   1945 
   1946 mDNSlocal void PrintLLQTable(DaemonInfo *d)
   1947 	{
   1948 	LLQEntry *e;
   1949 	char addr[32];
   1950 	int i;
   1951 
   1952 	Log("Printing LLQ table contents");
   1953 
   1954 	for (i = 0; i < LLQ_TABLESIZE; i++)
   1955 		{
   1956 		e = d->LLQTable[i];
   1957 		while(e)
   1958 			{
   1959 			char *state;
   1960 
   1961 			switch (e->state)
   1962 				{
   1963 				case RequestReceived: state = "RequestReceived"; break;
   1964 				case ChallengeSent:   state = "ChallengeSent";   break;
   1965 				case Established:     state = "Established";     break;
   1966 				default:              state = "unknown";
   1967 				}
   1968 			inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
   1969 
   1970 			Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
   1971 				addr, state, e->qname.c, e->qtype, e->lease, LLQLease(e), e->AnswerList);
   1972 			e = e->next;
   1973 			}
   1974 		}
   1975 	}
   1976 
   1977 // Send events to clients as a result of a change in the zone
   1978 mDNSlocal void GenLLQEvents(DaemonInfo *d)
   1979 	{
   1980 	LLQEntry **e;
   1981 	int i;
   1982 	struct timeval t;
   1983 	UpdateAnswerListArgs *args;
   1984 
   1985 	VLog("Generating LLQ Events");
   1986 
   1987 	gettimeofday(&t, NULL);
   1988 
   1989 	// get all answers up to date
   1990 	for (i = 0; i < LLQ_TABLESIZE; i++)
   1991 		{
   1992 		AnswerListElem *a = d->AnswerTable[i];
   1993 		while(a)
   1994 			{
   1995 			args = malloc(sizeof(*args));
   1996 			if (!args) { LogErr("GenLLQEvents", "malloc"); return; }
   1997 			args->d = d;
   1998 			args->a = a;
   1999 			if (pthread_create(&a->tid, NULL, UpdateAnswerList, args) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
   2000 			usleep(1);
   2001 			a = a->next;
   2002 			}
   2003 		}
   2004 
   2005 	for (i = 0; i < LLQ_TABLESIZE; i++)
   2006 		{
   2007 		AnswerListElem *a = d->AnswerTable[i];
   2008 		while(a)
   2009 			{
   2010 			if (pthread_join(a->tid, NULL)) LogErr("GenLLQEvents", "pthread_join");
   2011 			a = a->next;
   2012 			}
   2013 		}
   2014 
   2015     // for each established LLQ, send events
   2016 	for (i = 0; i < LLQ_TABLESIZE; i++)
   2017 		{
   2018 		e = &d->LLQTable[i];
   2019 		while(*e)
   2020 			{
   2021 			if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
   2022 			else
   2023 				{
   2024 				if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
   2025 				e = &(*e)->next;
   2026 				}
   2027 			}
   2028 		}
   2029 
   2030 	// now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
   2031 	for (i = 0; i < LLQ_TABLESIZE; i++)
   2032 		{
   2033 		AnswerListElem *a = d->AnswerTable[i];
   2034 		while(a)
   2035 			{
   2036 			if (a->EventList)
   2037 				{
   2038 				CacheRecord *cr = a->EventList, *tmp;
   2039 				while (cr)
   2040 					{
   2041 					tmp = cr;
   2042 					cr = cr->next;
   2043 					if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
   2044 					else
   2045 						{
   2046 						tmp->next = a->KnownAnswers;
   2047 						a->KnownAnswers = tmp;
   2048 						tmp->resrec.rroriginalttl = 0;
   2049 						}
   2050 					}
   2051 				a->EventList = NULL;
   2052 				}
   2053 			a = a->next;
   2054 			}
   2055 		}
   2056 	}
   2057 
   2058 mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
   2059 	{
   2060 	int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
   2061 	AnswerListElem *a = d->AnswerTable[bucket];
   2062 	while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
   2063 	if (!a)
   2064 		{
   2065 		a = malloc(sizeof(*a));
   2066 		if (!a) { LogErr("SetAnswerList", "malloc"); return; }
   2067 		AssignDomainName(&a->name, &e->qname);
   2068 		a->type = e->qtype;
   2069 		a->refcount = 0;
   2070 		a->EventList = NULL;
   2071 		a->UseTCP = mDNSfalse;
   2072 		a->next = d->AnswerTable[bucket];
   2073 		d->AnswerTable[bucket] = a;
   2074 		d->AnswerTableCount++;
   2075 		a->KnownAnswers = AnswerQuestion(d, a);
   2076 		}
   2077 
   2078 	e->AnswerList = a;
   2079 	a->refcount ++;
   2080 	}
   2081 
   2082  // Allocate LLQ entry, insert into table
   2083 mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease )
   2084 	{
   2085 	char addr[32];
   2086 	struct timeval t;
   2087 	int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
   2088    	LLQEntry *e;
   2089 
   2090 	e = malloc(sizeof(*e));
   2091 	if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
   2092 
   2093 	inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
   2094 	VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
   2095 
   2096 	// initialize structure
   2097 	e->cli = cli;
   2098 	AssignDomainName(&e->qname, qname);
   2099 	e->qtype = qtype;
   2100 	e->id    = zeroOpaque64;
   2101 	e->state = RequestReceived;
   2102 	e->AnswerList = NULL;
   2103 
   2104 	if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
   2105 	else if (lease > LLQ_MAX_LEASE) lease = LLQ_MAX_LEASE;
   2106 
   2107 	gettimeofday(&t, NULL);
   2108 	e->expire = t.tv_sec + (int)lease;
   2109 	e->lease = lease;
   2110 
   2111 	// add to table
   2112 	e->next = d->LLQTable[bucket];
   2113 	d->LLQTable[bucket] = e;
   2114 
   2115 	return e;
   2116 	}
   2117 
   2118 // Handle a refresh request from client
   2119 mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
   2120 	{
   2121 	AuthRecord opt;
   2122 	PktMsg ack;
   2123 	mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
   2124 	char addr[32];
   2125 
   2126 	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
   2127 	VLog("%s LLQ for %##s from %s", llq->llqlease ? "Refreshing" : "Deleting", e->qname.c, addr);
   2128 
   2129 	if (llq->llqlease)
   2130 		{
   2131 		struct timeval t;
   2132 		if (llq->llqlease < LLQ_MIN_LEASE) llq->llqlease = LLQ_MIN_LEASE;
   2133 		else if (llq->llqlease > LLQ_MAX_LEASE) llq->llqlease = LLQ_MIN_LEASE;
   2134 		gettimeofday(&t, NULL);
   2135 		e->expire = t.tv_sec + llq->llqlease;
   2136 		}
   2137 
   2138 	ack.src.sin_addr.s_addr = 0; // unused
   2139 	InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
   2140 	end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
   2141 	if (!end) { Log("Error: putQuestion"); return; }
   2142 
   2143 	FormatLLQOpt(&opt, kLLQOp_Refresh, &e->id, llq->llqlease ? LLQLease(e) : 0);
   2144 	end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
   2145 	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
   2146 
   2147 	ack.len = (int)(end - (mDNSu8 *)&ack.msg);
   2148 	if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQRefresh");
   2149 
   2150 	if (llq->llqlease) e->state = Established;
   2151 	else DeleteLLQ(d, e);
   2152 	}
   2153 
   2154 // Complete handshake with Ack an initial answers
   2155 mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock)
   2156 	{
   2157 	char addr[32];
   2158 	CacheRecord *ptr;
   2159 	AuthRecord opt;
   2160 	PktMsg ack;
   2161 	mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
   2162 	char rrbuf[MaxMsg], addrbuf[32];
   2163 
   2164 	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
   2165 
   2166 	if (!mDNSSameOpaque64(&llq->id, &e->id) ||
   2167 		llq->vers  != kLLQ_Vers             ||
   2168 		llq->llqOp != kLLQOp_Setup          ||
   2169 		llq->err   != LLQErr_NoError        ||
   2170 		llq->llqlease > e->lease + LLQ_LEASE_FUDGE ||
   2171 		llq->llqlease < e->lease - LLQ_LEASE_FUDGE)
   2172 		{
   2173 			Log("Incorrect challenge response from %s", addr);
   2174 			return;
   2175 		}
   2176 
   2177 	if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
   2178 	else                         VLog("Delivering LLQ ack + answers for %##s", e->qname.c);
   2179 
   2180 	// format ack + answers
   2181 	ack.src.sin_addr.s_addr = 0; // unused
   2182 	InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
   2183 	end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
   2184 	if (!end) { Log("Error: putQuestion"); return; }
   2185 
   2186 	if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
   2187 
   2188 	if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
   2189 	for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
   2190 		{
   2191 		if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
   2192 		VLog("%s Intitial Answer - %s", addr, rrbuf);
   2193 		end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
   2194 		if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
   2195 		}
   2196 
   2197 	FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
   2198 	end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
   2199 	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
   2200 
   2201 	ack.len = (int)(end - (mDNSu8 *)&ack.msg);
   2202 	if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQCompleteHandshake");
   2203 	}
   2204 
   2205 mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
   2206 	{
   2207 	struct timeval t;
   2208 	PktMsg challenge;
   2209 	mDNSu8 *end = challenge.msg.data;
   2210 	AuthRecord opt;
   2211 
   2212 	if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
   2213 	else                           VLog("Sending LLQ setup challenge for %##s", e->qname.c);
   2214 
   2215 	if (!mDNSOpaque64IsZero(&llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
   2216 	if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
   2217 
   2218 	if (mDNSOpaque64IsZero(&e->id)) // don't regenerate random ID for retransmissions
   2219 		{
   2220 		// construct ID <time><random>
   2221 		gettimeofday(&t, NULL);
   2222 		e->id.l[0] = t.tv_sec;
   2223 		e->id.l[1] = random();
   2224 		}
   2225 
   2226 	// format response (query + LLQ opt rr)
   2227 	challenge.src.sin_addr.s_addr = 0; // unused
   2228 	InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
   2229 	end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
   2230 	if (!end) { Log("Error: putQuestion"); return; }
   2231 	FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
   2232 	end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
   2233 	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
   2234 	challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
   2235 	if (SendLLQ(d, &challenge, e->cli, NULL)) { Log("Error: LLQSetupChallenge"); return; }
   2236 	e->state = ChallengeSent;
   2237 	}
   2238 
   2239 // Take action on an LLQ message from client.  Entry must be initialized and in table
   2240 mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
   2241 	{
   2242 	switch(e->state)
   2243 		{
   2244 		case RequestReceived:
   2245 			if ( sock )
   2246 				{
   2247 				struct timeval t;
   2248 				gettimeofday(&t, NULL);
   2249 				e->id.l[0] = t.tv_sec;	// construct ID <time><random>
   2250 				e->id.l[1] = random();
   2251 				llq->id = e->id;
   2252 				LLQCompleteHandshake( d, e, llq, msgID, sock );
   2253 
   2254 				// Set the state to established because we've just set the LLQ up using TCP
   2255 				e->state = Established;
   2256 				}
   2257 			else
   2258 				{
   2259 				LLQSetupChallenge(d, e, llq, msgID);
   2260 				}
   2261 			return;
   2262 		case ChallengeSent:
   2263 			if (mDNSOpaque64IsZero(&llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
   2264 			else LLQCompleteHandshake(d, e, llq, msgID, sock );
   2265 			return;
   2266 		case Established:
   2267 			if (mDNSOpaque64IsZero(&llq->id))
   2268 				{
   2269 				// client started over.  reset state.
   2270 				LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->llqlease );
   2271 				if (!newe) return;
   2272 				DeleteLLQ(d, e);
   2273 				LLQSetupChallenge(d, newe, llq, msgID);
   2274 				return;
   2275 				}
   2276 			else if (llq->llqOp == kLLQOp_Setup)
   2277 				{ LLQCompleteHandshake(d, e, llq, msgID, sock); return; } // Ack lost
   2278 			else if (llq->llqOp == kLLQOp_Refresh)
   2279 				{ LLQRefresh(d, e, llq, msgID, sock); return; }
   2280 			else { Log("Unhandled message for established LLQ"); return; }
   2281 		}
   2282 	}
   2283 
   2284 mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, const mDNSOpaque64 *const id)
   2285 	{
   2286 	int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
   2287 	LLQEntry *ptr = d->LLQTable[bucket];
   2288 
   2289 	while(ptr)
   2290 		{
   2291 		if (((ptr->state == ChallengeSent && mDNSOpaque64IsZero(id) && (cli.sin_port == ptr->cli.sin_port)) || // zero-id due to packet loss OK in state ChallengeSent
   2292 			 mDNSSameOpaque64(id, &ptr->id)) &&                        // id match
   2293 			(cli.sin_addr.s_addr == ptr->cli.sin_addr.s_addr) && (qtype == ptr->qtype) && SameDomainName(&ptr->qname, qname)) // same source, type, qname
   2294 			return ptr;
   2295 		ptr = ptr->next;
   2296 		}
   2297 	return NULL;
   2298 	}
   2299 
   2300 mDNSlocal int
   2301 RecvNotify
   2302 	(
   2303 	DaemonInfo	*	d,
   2304 	PktMsg		*	pkt
   2305 	)
   2306 	{
   2307 	int	res;
   2308 	int	err = 0;
   2309 
   2310 	pkt->msg.h.flags.b[0] |= kDNSFlag0_QR_Response;
   2311 
   2312 	res = sendto( d->udpsd, &pkt->msg, pkt->len, 0, ( struct sockaddr* ) &pkt->src, sizeof( pkt->src ) );
   2313 	require_action( res == ( int ) pkt->len, exit, err = mStatus_UnknownErr; LogErr( "RecvNotify", "sendto" ) );
   2314 
   2315 exit:
   2316 
   2317 	return err;
   2318 	}
   2319 
   2320 
   2321 mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
   2322 	{
   2323 	DNSQuestion q;
   2324 	LargeCacheRecord opt;
   2325 	int i, err = -1;
   2326 	char addr[32];
   2327 	const mDNSu8 *qptr = pkt->msg.data;
   2328     const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
   2329 	const mDNSu8 *aptr;
   2330 	LLQOptData *llq = NULL;
   2331 	LLQEntry *e = NULL;
   2332 
   2333 	HdrNToH(pkt);
   2334 	aptr = LocateAdditionals(&pkt->msg, end);	// Can't do this until after HdrNToH(pkt);
   2335 	inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
   2336 
   2337 	VLog("Received LLQ msg from %s", addr);
   2338 	// sanity-check packet
   2339 	if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
   2340 		{
   2341 		Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
   2342 		goto end;
   2343 		}
   2344 
   2345 	// Locate the OPT record.
   2346 	// According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
   2347 	// This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
   2348 	// but not necessarily the *last* entry in the Additional Section.
   2349 	for (i = 0; i < pkt->msg.h.numAdditionals; i++)
   2350 		{
   2351 		aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
   2352 		if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
   2353 		if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
   2354 		}
   2355 
   2356 	// validate OPT
   2357 	if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; }
   2358 	if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * DNSOpt_LLQData_Space) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
   2359 
   2360 	// dispatch each question
   2361 	for (i = 0; i < pkt->msg.h.numQuestions; i++)
   2362 		{
   2363 		qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
   2364 		if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
   2365 		llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt[0].u.llq + i; // point into OptData at index i
   2366 		if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
   2367 
   2368 		e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id);
   2369 		if (!e)
   2370 			{
   2371 			// no entry - if zero ID, create new
   2372 			e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->llqlease );
   2373 			if (!e) goto end;
   2374 			}
   2375 		UpdateLLQ(d, e, llq, pkt->msg.h.id, sock);
   2376 		}
   2377 	err = 0;
   2378 
   2379 	end:
   2380 	HdrHToN(pkt);
   2381 	return err;
   2382 	}
   2383 
   2384 
   2385 mDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo ** key, mDNSu16 * rcode, mDNSu16 * tcode )
   2386 	{
   2387 	const mDNSu8 	*	lastPtr = NULL;
   2388 	const mDNSu8 	*	ptr = NULL;
   2389 	DomainAuthInfo	*	keys;
   2390 	mDNSu8 			*	end	= ( mDNSu8* ) &pkt->msg + pkt->len;
   2391 	LargeCacheRecord	lcr;
   2392 	mDNSBool			hasTSIG = mDNSfalse;
   2393 	mDNSBool			strip = mDNSfalse;
   2394 	mDNSBool			ok = mDNSfalse;
   2395 	int					i;
   2396 
   2397 	// Unused parameters
   2398 
   2399 	( void ) d;
   2400 
   2401 	HdrNToH(pkt);
   2402 
   2403 	*key = NULL;
   2404 
   2405 	if ( pkt->msg.h.numAdditionals )
   2406 		{
   2407 		ptr = LocateAdditionals(&pkt->msg, end);
   2408 		if (ptr)
   2409 			{
   2410 			for (i = 0; i < pkt->msg.h.numAdditionals; i++)
   2411 				{
   2412 				lastPtr = ptr;
   2413 				ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
   2414 				if (!ptr)
   2415 					{
   2416 					Log("Unable to read additional record");
   2417 					lastPtr = NULL;
   2418 					break;
   2419 					}
   2420 				}
   2421 
   2422 				hasTSIG = ( ptr && lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rrtype == kDNSType_TSIG );
   2423 			}
   2424 		else
   2425 			{
   2426 			LogMsg( "IsAuthorized: unable to find Additional section" );
   2427 			}
   2428 		}
   2429 
   2430 	// If we don't know what zone this is, then it's authorized.
   2431 
   2432 	if ( !pkt->zone )
   2433 		{
   2434 		ok = mDNStrue;
   2435 		strip = mDNSfalse;
   2436 		goto exit;
   2437 		}
   2438 
   2439 	if ( IsQuery( pkt ) )
   2440 		{
   2441 		keys = pkt->zone->queryKeys;
   2442 		strip = mDNStrue;
   2443 		}
   2444 	else if ( IsUpdate( pkt ) )
   2445 		{
   2446 		keys = pkt->zone->updateKeys;
   2447 		strip = mDNSfalse;
   2448 		}
   2449 	else
   2450 		{
   2451 		ok = mDNStrue;
   2452 		strip = mDNSfalse;
   2453 		goto exit;
   2454 		}
   2455 
   2456 	if ( pkt->isZonePublic )
   2457 		{
   2458 		ok = mDNStrue;
   2459 		goto exit;
   2460 		}
   2461 
   2462 	// If there are no keys, then we're authorized
   2463 
   2464 	if ( ( hasTSIG && !keys ) || ( !hasTSIG && keys ) )
   2465 		{
   2466 		Log( "Invalid TSIG spec %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
   2467 		*rcode = kDNSFlag1_RC_NotAuth;
   2468 		*tcode = TSIG_ErrBadKey;
   2469 		strip = mDNStrue;
   2470 		ok = mDNSfalse;
   2471 		goto exit;
   2472 		}
   2473 
   2474 	// Find the right key
   2475 
   2476 	for ( *key = keys; *key; *key = (*key)->next )
   2477 		{
   2478 		if ( SameDomainName( lcr.r.resrec.name, &(*key)->keyname ) )
   2479 			{
   2480 			break;
   2481 			}
   2482 		}
   2483 
   2484 	if ( !(*key) )
   2485 		{
   2486 		Log( "Invalid TSIG name %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
   2487 		*rcode = kDNSFlag1_RC_NotAuth;
   2488 		*tcode = TSIG_ErrBadKey;
   2489 		strip = mDNStrue;
   2490 		ok = mDNSfalse;
   2491 		goto exit;
   2492 		}
   2493 
   2494 	// Okay, we have the correct key and a TSIG record.  DNSDigest_VerifyMessage does the heavy
   2495 	// lifting of message verification
   2496 
   2497 	pkt->msg.h.numAdditionals--;
   2498 
   2499 	HdrHToN( pkt );
   2500 
   2501 	ok = DNSDigest_VerifyMessage( &pkt->msg, ( mDNSu8* ) lastPtr, &lcr, (*key), rcode, tcode );
   2502 
   2503 	HdrNToH( pkt );
   2504 
   2505 	pkt->msg.h.numAdditionals++;
   2506 
   2507 exit:
   2508 
   2509 	if ( hasTSIG && strip )
   2510 		{
   2511 		// Strip the TSIG from the message
   2512 
   2513 		pkt->msg.h.numAdditionals--;
   2514 		pkt->len = lastPtr - ( mDNSu8* ) ( &pkt->msg );
   2515 		}
   2516 
   2517 	HdrHToN(pkt);
   2518 
   2519 	return ok;
   2520 	}
   2521 
   2522 // request handler wrappers for TCP and UDP requests
   2523 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
   2524 
   2525 mDNSlocal void*
   2526 UDPMessageHandler
   2527 	(
   2528 	void * vptr
   2529 	)
   2530 	{
   2531 	UDPContext	*	context	= ( UDPContext* ) vptr;
   2532 	PktMsg		*	reply	= NULL;
   2533 	int				res;
   2534 	mStatus			err;
   2535 
   2536 	// !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
   2537 	// may give us a long answer that would require truncation for UDP delivery to client
   2538 
   2539 	reply = HandleRequest( context->d, &context->pkt );
   2540 	require_action( reply, exit, err = mStatus_UnknownErr );
   2541 
   2542 	res = sendto( context->sd, &reply->msg, reply->len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
   2543 	require_action_quiet( res == ( int ) reply->len, exit, LogErr( "UDPMessageHandler", "sendto" ) );
   2544 
   2545 exit:
   2546 
   2547 	if ( reply )
   2548 		{
   2549 		free( reply );
   2550 		}
   2551 
   2552 	free( context );
   2553 
   2554 	pthread_exit( NULL );
   2555 
   2556 	return NULL;
   2557 	}
   2558 
   2559 
   2560 mDNSlocal int
   2561 RecvUDPMessage
   2562 	(
   2563 	DaemonInfo	*	self,
   2564 	int				sd
   2565 	)
   2566 	{
   2567 	UDPContext		*	context = NULL;
   2568 	pthread_t			tid;
   2569 	mDNSu16				rcode;
   2570 	mDNSu16				tcode;
   2571 	DomainAuthInfo	*	key;
   2572 	unsigned int		clisize = sizeof( context->cliaddr );
   2573 	int					res;
   2574 	mStatus				err = mStatus_NoError;
   2575 
   2576 	context = malloc( sizeof( UDPContext ) );
   2577 	require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
   2578 
   2579 	mDNSPlatformMemZero( context, sizeof( *context ) );
   2580 	context->d = self;
   2581 	context->sd = sd;
   2582 
   2583 	res = recvfrom(sd, &context->pkt.msg, sizeof(context->pkt.msg), 0, (struct sockaddr *)&context->cliaddr, &clisize);
   2584 
   2585 	require_action( res >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvUDPMessage", "recvfrom" ) );
   2586 	context->pkt.len = res;
   2587 	require_action( clisize == sizeof( context->cliaddr ), exit, err = mStatus_UnknownErr ; Log( "Client address of unknown size %d", clisize ) );
   2588 	context->pkt.src = context->cliaddr;
   2589 
   2590 	// Set the zone in the packet
   2591 
   2592 	SetZone( context->d, &context->pkt );
   2593 
   2594 	// Notify messages handled by main thread
   2595 
   2596 	if ( IsNotify( &context->pkt ) )
   2597 		{
   2598 		int e = RecvNotify( self, &context->pkt );
   2599 		free(context);
   2600 		return e;
   2601 		}
   2602 	else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
   2603 		{
   2604 		if ( IsLLQRequest( &context->pkt ) )
   2605 			{
   2606 			// LLQ messages handled by main thread
   2607 			int e = RecvLLQ( self, &context->pkt, NULL );
   2608 			free(context);
   2609 			return e;
   2610 			}
   2611 
   2612 		if ( IsLLQAck(&context->pkt ) )
   2613 			{
   2614 			// !!!KRS need to do acks + retrans
   2615 
   2616 			free(context);
   2617 			return 0;
   2618 			}
   2619 
   2620 		err = pthread_create( &tid, NULL, UDPMessageHandler, context );
   2621 		require_action( !err, exit, LogErr( "RecvUDPMessage", "pthread_create" ) );
   2622 
   2623 		pthread_detach(tid);
   2624 		}
   2625 	else
   2626 		{
   2627 		PktMsg reply;
   2628 		int    e;
   2629 
   2630 		memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
   2631 
   2632 		reply.msg.h.flags.b[0]  =  kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
   2633 		reply.msg.h.flags.b[1]  =  kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
   2634 
   2635 		e = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
   2636 		require_action_quiet( e == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
   2637 
   2638 		err = mStatus_NoAuth;
   2639 		}
   2640 
   2641 exit:
   2642 
   2643 	if ( err && context )
   2644 		{
   2645 		free( context );
   2646 		}
   2647 
   2648 	return err;
   2649 	}
   2650 
   2651 
   2652 mDNSlocal void
   2653 FreeTCPContext
   2654 	(
   2655 	TCPContext * context
   2656 	)
   2657 	{
   2658 	if ( context )
   2659 		{
   2660 		if ( context->sock )
   2661 			{
   2662 			mDNSPlatformTCPCloseConnection( context->sock );
   2663 			}
   2664 
   2665 		free( context );
   2666 		}
   2667 	}
   2668 
   2669 
   2670 mDNSlocal void*
   2671 TCPMessageHandler
   2672 	(
   2673 	void * vptr
   2674 	)
   2675 	{
   2676 	TCPContext	*	context	= ( TCPContext* ) vptr;
   2677 	PktMsg		*	reply = NULL;
   2678 	int				res;
   2679 	char 			buf[32];
   2680 
   2681     //!!!KRS if this read blocks indefinitely, we can run out of threads
   2682 	// read the request
   2683 
   2684 	reply = HandleRequest( context->d, &context->pkt );
   2685 	require_action_quiet( reply, exit, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
   2686 
   2687 	// deliver reply to client
   2688 
   2689 	res = SendPacket( context->sock, reply );
   2690 	require_action( res >= 0, exit, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
   2691 
   2692 exit:
   2693 
   2694 	FreeTCPContext( context );
   2695 
   2696 	if ( reply )
   2697 		{
   2698 		free( reply );
   2699 		}
   2700 
   2701 	pthread_exit(NULL);
   2702 	}
   2703 
   2704 
   2705 mDNSlocal void
   2706 RecvTCPMessage
   2707 	(
   2708 	void * param
   2709 	)
   2710 	{
   2711 	TCPContext		*	context = ( TCPContext* ) param;
   2712 	mDNSu16				rcode;
   2713 	mDNSu16				tcode;
   2714 	pthread_t			tid;
   2715 	DomainAuthInfo	*	key;
   2716 	PktMsg			*	pkt;
   2717 	mDNSBool			closed;
   2718 	mDNSBool			freeContext = mDNStrue;
   2719 	mStatus				err = mStatus_NoError;
   2720 
   2721 	// Receive a packet.  It's okay if we don't actually read a packet, as long as the closed flag is
   2722 	// set to false.  This is because SSL/TLS layer might gobble up the first packet that we read off the
   2723 	// wire.  We'll let it do that, and wait for the next packet which will be ours.
   2724 
   2725 	pkt = RecvPacket( context->sock, &context->pkt, &closed );
   2726 	if (pkt) HdrNToH(pkt);
   2727 	require_action( pkt || !closed, exit, err = mStatus_UnknownErr; LogMsg( "client disconnected" ) );
   2728 
   2729 	if ( pkt )
   2730 		{
   2731 		// Always do this, regardless of what kind of packet it is.  If we wanted LLQ events to be sent over TCP,
   2732 		// we would change this line of code.  As it is now, we will reply to an LLQ via TCP, but then events
   2733 		// are sent over UDP
   2734 
   2735 		RemoveSourceFromEventLoop( context->d, context->sock );
   2736 
   2737 		// Set's the DNS Zone that is associated with this message
   2738 
   2739 		SetZone( context->d, &context->pkt );
   2740 
   2741 		// IsAuthorized will make sure the message is authorized for the designated zone.
   2742 		// After verifying the signature, it will strip the TSIG from the message
   2743 
   2744 		if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
   2745 			{
   2746 			if ( IsLLQRequest( &context->pkt ) )
   2747 				{
   2748 				// LLQ messages handled by main thread
   2749 				RecvLLQ( context->d, &context->pkt, context->sock);
   2750 				}
   2751 			else
   2752 				{
   2753 				err = pthread_create( &tid, NULL, TCPMessageHandler, context );
   2754 
   2755 				if ( err )
   2756 					{
   2757 					LogErr( "RecvTCPMessage", "pthread_create" );
   2758 					err = mStatus_NoError;
   2759 					goto exit;
   2760 					}
   2761 
   2762 				// Let the thread free the context
   2763 
   2764 				freeContext = mDNSfalse;
   2765 
   2766 				pthread_detach(tid);
   2767 				}
   2768 			}
   2769 		else
   2770 			{
   2771 			PktMsg reply;
   2772 
   2773 			LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context->pkt.src.sin_addr ), pkt->zone->name.c );
   2774 
   2775 			memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
   2776 
   2777 			reply.msg.h.flags.b[0]  =  kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
   2778 			reply.msg.h.flags.b[1]  =  kDNSFlag1_RA | kDNSFlag1_RC_Refused;
   2779 
   2780 			SendPacket( context->sock, &reply );
   2781 			}
   2782 		}
   2783 	else
   2784 		{
   2785 		freeContext = mDNSfalse;
   2786 		}
   2787 
   2788 exit:
   2789 
   2790 	if ( err )
   2791 		{
   2792 		RemoveSourceFromEventLoop( context->d, context->sock );
   2793 		}
   2794 
   2795 	if ( freeContext )
   2796 		{
   2797 		FreeTCPContext( context );
   2798 		}
   2799 	}
   2800 
   2801 
   2802 mDNSlocal int
   2803 AcceptTCPConnection
   2804 	(
   2805 	DaemonInfo		*	self,
   2806 	int					sd,
   2807 	TCPSocketFlags	flags
   2808 	)
   2809 	{
   2810 	TCPContext *	context = NULL;
   2811 	unsigned int	clilen = sizeof( context->cliaddr);
   2812 	int				newSock;
   2813 	mStatus			err = mStatus_NoError;
   2814 
   2815 	context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
   2816 	require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
   2817 	mDNSPlatformMemZero( context, sizeof( sizeof( TCPContext ) ) );
   2818 	context->d		 = self;
   2819 	newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen );
   2820 	require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) );
   2821 
   2822 	context->sock = mDNSPlatformTCPAccept( flags, newSock );
   2823 	require_action( context->sock, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
   2824 
   2825 	err = AddSourceToEventLoop( self, context->sock, RecvTCPMessage, context );
   2826 	require_action( !err, exit, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
   2827 
   2828 exit:
   2829 
   2830 	if ( err && context )
   2831 		{
   2832 		free( context );
   2833 		context = NULL;
   2834 		}
   2835 
   2836 	return err;
   2837 	}
   2838 
   2839 
   2840 // main event loop
   2841 // listen for incoming requests, periodically check table for expired records, respond to signals
   2842 mDNSlocal int Run(DaemonInfo *d)
   2843 	{
   2844 	int staticMaxFD, nfds;
   2845 	fd_set rset;
   2846 	struct timeval timenow, timeout, EventTS, tablecheck = { 0, 0 };
   2847 	mDNSBool EventsPending = mDNSfalse;
   2848 
   2849    	VLog("Listening for requests...");
   2850 
   2851 	staticMaxFD = 0;
   2852 
   2853 	if ( d->tcpsd + 1  > staticMaxFD )				staticMaxFD = d->tcpsd + 1;
   2854 	if ( d->udpsd + 1  > staticMaxFD )				staticMaxFD = d->udpsd + 1;
   2855 	if ( d->tlssd + 1  > staticMaxFD )				staticMaxFD = d->tlssd + 1;
   2856 	if ( d->llq_tcpsd + 1 > staticMaxFD )			staticMaxFD = d->llq_tcpsd + 1;
   2857 	if ( d->llq_udpsd + 1 > staticMaxFD )			staticMaxFD = d->llq_udpsd + 1;
   2858 	if ( d->LLQEventListenSock + 1 > staticMaxFD )	staticMaxFD = d->LLQEventListenSock + 1;
   2859 
   2860 	while(1)
   2861 		{
   2862 		EventSource	* source;
   2863 		int           maxFD;
   2864 
   2865 		// set timeout
   2866 		timeout.tv_sec = timeout.tv_usec = 0;
   2867 		if (gettimeofday(&timenow, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
   2868 
   2869 		if (EventsPending)
   2870 			{
   2871 			if (timenow.tv_sec - EventTS.tv_sec >= 5)           // if we've been waiting 5 seconds for a "quiet" period to send
   2872 				{ GenLLQEvents(d); EventsPending = mDNSfalse; } // events, we go ahead and do it now
   2873 			else timeout.tv_usec = 500000;                      // else do events after 1/2 second with no new events or LLQs
   2874 			}
   2875 		if (!EventsPending)
   2876 			{
   2877 			// if no pending events, timeout when we need to check for expired records
   2878 			if (tablecheck.tv_sec && timenow.tv_sec - tablecheck.tv_sec >= 0)
   2879 				{ DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; } // table check overdue
   2880 			if (!tablecheck.tv_sec) tablecheck.tv_sec = timenow.tv_sec + EXPIRATION_INTERVAL;
   2881 			timeout.tv_sec = tablecheck.tv_sec - timenow.tv_sec;
   2882 			}
   2883 
   2884 		FD_ZERO(&rset);
   2885 		FD_SET( d->tcpsd, &rset );
   2886 		FD_SET( d->udpsd, &rset );
   2887 		FD_SET( d->tlssd, &rset );
   2888 		FD_SET( d->llq_tcpsd, &rset );
   2889 		FD_SET( d->llq_udpsd, &rset );
   2890 		FD_SET( d->LLQEventListenSock, &rset );
   2891 
   2892 		maxFD = staticMaxFD;
   2893 
   2894 		for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
   2895 			{
   2896 			FD_SET( source->fd, &rset );
   2897 
   2898 			if ( source->fd > maxFD )
   2899 				{
   2900 				maxFD = source->fd;
   2901 				}
   2902 			}
   2903 
   2904 		nfds = select( maxFD + 1, &rset, NULL, NULL, &timeout);
   2905 		if (nfds < 0)
   2906 			{
   2907 			if (errno == EINTR)
   2908 				{
   2909 				if (terminate)
   2910 					{
   2911 					// close sockets to prevent clients from making new requests during shutdown
   2912 					close( d->tcpsd );
   2913 					close( d->udpsd );
   2914 					close( d->tlssd );
   2915 					close( d->llq_tcpsd );
   2916 					close( d->llq_udpsd );
   2917 					d->tcpsd = d->udpsd = d->tlssd = d->llq_tcpsd = d->llq_udpsd = -1;
   2918 					DeleteRecords(d, mDNStrue);
   2919 					return 0;
   2920 					}
   2921 				else if (dumptable)
   2922 					{
   2923 					Log( "Received SIGINFO" );
   2924 
   2925 					PrintLeaseTable(d);
   2926 					PrintLLQTable(d);
   2927 					PrintLLQAnswers(d);
   2928 					dumptable = 0;
   2929 					}
   2930 				else if (hangup)
   2931 					{
   2932 					int err;
   2933 
   2934 					Log( "Received SIGHUP" );
   2935 
   2936 					err = ParseConfig( d, cfgfile );
   2937 
   2938 					if ( err )
   2939 						{
   2940 						LogErr( "Run", "ParseConfig" );
   2941 						return -1;
   2942 						}
   2943 
   2944 					hangup = 0;
   2945 					}
   2946 				else
   2947 					{
   2948 					Log("Received unhandled signal - continuing");
   2949 					}
   2950 				}
   2951 			else
   2952 				{
   2953 				LogErr("Run", "select"); return -1;
   2954 				}
   2955 			}
   2956 		else if (nfds)
   2957 			{
   2958 			if (FD_ISSET(d->udpsd, &rset))		RecvUDPMessage( d, d->udpsd );
   2959 			if (FD_ISSET(d->llq_udpsd, &rset))	RecvUDPMessage( d, d->llq_udpsd );
   2960 			if (FD_ISSET(d->tcpsd, &rset))		AcceptTCPConnection( d, d->tcpsd, 0 );
   2961 			if (FD_ISSET(d->llq_tcpsd, &rset))	AcceptTCPConnection( d, d->llq_tcpsd, 0 );
   2962 			if (FD_ISSET(d->tlssd, &rset))  	AcceptTCPConnection( d, d->tlssd, TCP_SOCKET_FLAGS );
   2963 			if (FD_ISSET(d->LLQEventListenSock, &rset))
   2964 				{
   2965 				// clear signalling data off socket
   2966 				char buf[256];
   2967 				recv(d->LLQEventListenSock, buf, 256, 0);
   2968 				if (!EventsPending)
   2969 					{
   2970 					EventsPending = mDNStrue;
   2971 					if (gettimeofday(&EventTS, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
   2972 					}
   2973 				}
   2974 
   2975 			for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
   2976 				{
   2977 				if ( FD_ISSET( source->fd, &rset ) )
   2978 					{
   2979 					source->callback( source->context );
   2980 					break;  // in case we removed this guy from the event loop
   2981 					}
   2982 				}
   2983 			}
   2984 		else
   2985 			{
   2986 			// timeout
   2987 			if (EventsPending) { GenLLQEvents(d); EventsPending = mDNSfalse; }
   2988 			else { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; }
   2989 			}
   2990 		}
   2991 	return 0;
   2992 	}
   2993 
   2994 // signal handler sets global variables, which are inspected by main event loop
   2995 // (select automatically returns due to the handled signal)
   2996 mDNSlocal void HndlSignal(int sig)
   2997 	{
   2998 	if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
   2999 	if (sig == INFO_SIGNAL)               { dumptable = 1; return; }
   3000 	if (sig == SIGHUP)                    { hangup    = 1; return; }
   3001 	}
   3002 
   3003 mDNSlocal mStatus
   3004 SetPublicSRV
   3005 	(
   3006 	DaemonInfo	*	d,
   3007 	const char	*	name
   3008 	)
   3009 	{
   3010 	DNameListElem * elem;
   3011 	mStatus			err = mStatus_NoError;
   3012 
   3013 	elem = ( DNameListElem* ) malloc( sizeof( DNameListElem ) );
   3014 	require_action( elem, exit, err = mStatus_NoMemoryErr );
   3015 	MakeDomainNameFromDNSNameString( &elem->name, name );
   3016 	elem->next = d->public_names;
   3017 	d->public_names = elem;
   3018 
   3019 exit:
   3020 
   3021 	return err;
   3022 	}
   3023 
   3024 
   3025 int main(int argc, char *argv[])
   3026 	{
   3027 	int started_via_launchd = 0;
   3028 	DaemonInfo *d;
   3029 	struct rlimit rlim;
   3030 
   3031 	Log("dnsextd starting");
   3032 
   3033 	d = malloc(sizeof(*d));
   3034 	if (!d) { LogErr("main", "malloc"); exit(1); }
   3035 	mDNSPlatformMemZero(d, sizeof(DaemonInfo));
   3036 
   3037 	// Setup the public SRV record names
   3038 
   3039 	SetPublicSRV(d, "_dns-update._udp.");
   3040 	SetPublicSRV(d, "_dns-llq._udp.");
   3041 	SetPublicSRV(d, "_dns-update-tls._tcp.");
   3042 	SetPublicSRV(d, "_dns-query-tls._tcp.");
   3043 	SetPublicSRV(d, "_dns-llq-tls._tcp.");
   3044 
   3045 	// Setup signal handling
   3046 
   3047 	if (signal(SIGHUP,      HndlSignal) == SIG_ERR) perror("Can't catch SIGHUP");
   3048 	if (signal(SIGTERM,     HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
   3049 	if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
   3050 	if (signal(SIGINT,      HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
   3051 	if (signal(SIGPIPE,     SIG_IGN  )  == SIG_ERR) perror("Can't ignore SIGPIPE");
   3052 
   3053 	// remove open file limit
   3054 	rlim.rlim_max = RLIM_INFINITY;
   3055 	rlim.rlim_cur = RLIM_INFINITY;
   3056 	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
   3057 		{
   3058 		LogErr("main", "setrlimit");
   3059 		Log("Using default file descriptor resource limit");
   3060 		}
   3061 
   3062 	if (argc > 1 && !strcasecmp(argv[1], "-launchd"))
   3063 		{
   3064 		Log("started_via_launchd");
   3065 		started_via_launchd = 1;
   3066 		argv++;
   3067 		argc--;
   3068 		}
   3069 	if (ProcessArgs(argc, argv, d) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
   3070 
   3071 	if (!foreground && !started_via_launchd)
   3072 		{
   3073 		if (daemon(0,0))
   3074 			{
   3075 			LogErr("main", "daemon");
   3076 			foreground = 1;
   3077 			}
   3078 		}
   3079 
   3080 	if (InitLeaseTable(d) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
   3081 	if (SetupSockets(d) < 0) { LogErr("main", "SetupSockets"); exit(1); }
   3082 	if (SetUpdateSRV(d) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
   3083 
   3084 	Run(d);
   3085 
   3086 	Log("dnsextd stopping");
   3087 
   3088 	if (ClearUpdateSRV(d) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); }  // clear update srv's even if Run or pthread_create returns an error
   3089 	free(d);
   3090 	exit(0);
   3091 	}
   3092 
   3093 
   3094 // These are stubbed out implementations of up-call routines that the various platform support layers
   3095 // call.  These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
   3096 // link this code in.
   3097 //
   3098 // It's an error for these routines to actually be called, so perhaps we should log any call
   3099 // to them.
   3100 void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
   3101 void mDNS_ConfigChanged(mDNS *const m)  { ( void ) m; }
   3102 void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
   3103 void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
   3104                                 const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
   3105                                 const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
   3106 	{ ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
   3107 DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout)
   3108 	{ ( void ) m; ( void ) d; ( void ) interface; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; return(NULL); }
   3109 void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
   3110 void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
   3111 	{ ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
   3112 mDNSs32 mDNS_Execute   (mDNS *const m) { ( void ) m; return 0; }
   3113 mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
   3114 mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
   3115 void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
   3116 	{ ( void ) m; ( void ) set; ( void ) flapping; }
   3117 const char * const  mDNS_DomainTypeNames[1] = {};
   3118 mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
   3119                                 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
   3120 	{ ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
   3121 mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
   3122 mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
   3123 	{ ( void ) m; ( void ) set; ( void ) flapping; return 0; }
   3124 void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
   3125 void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
   3126 void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router)
   3127 	{ ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
   3128 mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
   3129 mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
   3130 	const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, const char *autoTunnelPrefix)
   3131 	{ ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; ( void ) autoTunnelPrefix; return 0; }
   3132 mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
   3133 void TriggerEventCompletion(void);
   3134 void TriggerEventCompletion() {}
   3135 mDNS mDNSStorage;
   3136 
   3137 
   3138 // For convenience when using the "strings" command, this is the last thing in the file
   3139 // The "@(#) " pattern is a special prefix the "what" command looks for
   3140 const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
   3141 
   3142 #if _BUILDING_XCODE_PROJECT_
   3143 // If the process crashes, then this string will be magically included in the automatically-generated crash log
   3144 const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
   3145 asm(".desc ___crashreporter_info__, 0x10");
   3146 #endif
   3147