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
44extern 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//
66mDNSexport 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
102typedef 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*
111typedef 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*
120typedef 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)
132static mDNSBool foreground = 0;
133static mDNSBool verbose = 0;
134
135// globals set via signal handler (accessed exclusively by main select loop and signal handler)
136static mDNSBool terminate = 0;
137static mDNSBool dumptable = 0;
138static mDNSBool hangup    = 0;
139
140// global for config file location
141static 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
149mDNSlocal 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)
165mDNSlocal 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
178mDNSlocal 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
192mDNSlocal 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
205mDNSlocal 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
216mDNSlocal 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
238mDNSlocal 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
262exit:
263
264	return err;
265	}
266
267
268// Remove socket from event loop
269
270mDNSlocal 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
289exit:
290
291	return err;
292	}
293
294// create a socket connected to nameserver
295// caller terminates connection via close()
296mDNSlocal 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
323mDNSlocal 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
351mDNSlocal 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).
368static 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
412mDNSlocal PktMsg*
413RecvPacket
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
475exit:
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
491mDNSlocal DNSZone*
492FindZone
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
512mDNSlocal mDNSBool
513ZoneHandlesName
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
531mDNSlocal 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
537mDNSlocal mDNSBool IsUpdate( PktMsg * pkt )
538	{
539	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_OP_Update );
540	}
541
542
543mDNSlocal mDNSBool IsNotify(PktMsg *pkt)
544	{
545	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( mDNSu8) ( kDNSFlag0_OP_Notify );
546	}
547
548
549mDNSlocal 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
581mDNSlocal 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
589mDNSlocal mDNSBool
590IsPublicSRV
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
617exit:
618
619	return ret;
620	}
621
622
623mDNSlocal void
624SetZone
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
692mDNSlocal int
693UDPServerTransaction(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
741exit:
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
756mDNSlocal 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//
785mDNSlocal 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
806mDNSlocal 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
834mDNSlocal 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
867mDNSlocal 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
880mDNSlocal 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.
908mDNSlocal 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
998exit:
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
1012mDNSlocal 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
1025mDNSlocal void PrintUsage(void)
1026	{
1027	fprintf(stderr, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1028			"Use \"dnsextd -h\" for help\n");
1029	}
1030
1031mDNSlocal 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
1062mDNSlocal 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
1129arg_error:
1130
1131	PrintUsage();
1132	return -1;
1133	}
1134
1135
1136//
1137// Initialization Routines
1138//
1139
1140// Allocate memory, initialize locks and bookkeeping variables
1141mDNSlocal 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
1153mDNSlocal int
1154SetupSockets
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
1281exit:
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
1292mDNSlocal 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)
1338mDNSlocal 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
1374mDNSlocal 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
1476mDNSlocal 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
1503mDNSlocal PktMsg*
1504HandleRequest
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
1614exit:
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
1645mDNSlocal 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
1661mDNSlocal 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
1670mDNSlocal 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
1709mDNSlocal 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
1738mDNSlocal 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
1822mDNSlocal 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
1891mDNSlocal 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
1924mDNSlocal 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
1946mDNSlocal 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
1978mDNSlocal 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
2058mDNSlocal 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
2083mDNSlocal 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
2119mDNSlocal 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
2155mDNSlocal 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
2205mDNSlocal 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
2240mDNSlocal 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
2284mDNSlocal 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
2300mDNSlocal int
2301RecvNotify
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
2315exit:
2316
2317	return err;
2318	}
2319
2320
2321mDNSlocal 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
2385mDNSlocal 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
2507exit:
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
2525mDNSlocal void*
2526UDPMessageHandler
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
2545exit:
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
2560mDNSlocal int
2561RecvUDPMessage
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
2641exit:
2642
2643	if ( err && context )
2644		{
2645		free( context );
2646		}
2647
2648	return err;
2649	}
2650
2651
2652mDNSlocal void
2653FreeTCPContext
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
2670mDNSlocal void*
2671TCPMessageHandler
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
2692exit:
2693
2694	FreeTCPContext( context );
2695
2696	if ( reply )
2697		{
2698		free( reply );
2699		}
2700
2701	pthread_exit(NULL);
2702	}
2703
2704
2705mDNSlocal void
2706RecvTCPMessage
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
2788exit:
2789
2790	if ( err )
2791		{
2792		RemoveSourceFromEventLoop( context->d, context->sock );
2793		}
2794
2795	if ( freeContext )
2796		{
2797		FreeTCPContext( context );
2798		}
2799	}
2800
2801
2802mDNSlocal int
2803AcceptTCPConnection
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
2828exit:
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
2842mDNSlocal 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)
2996mDNSlocal 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
3003mDNSlocal mStatus
3004SetPublicSRV
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
3019exit:
3020
3021	return err;
3022	}
3023
3024
3025int 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.
3100void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
3101void mDNS_ConfigChanged(mDNS *const m)  { ( void ) m; }
3102void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
3103void 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; }
3107DNSServer *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); }
3109void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
3110void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
3111	{ ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
3112mDNSs32 mDNS_Execute   (mDNS *const m) { ( void ) m; return 0; }
3113mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
3114mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3115void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
3116	{ ( void ) m; ( void ) set; ( void ) flapping; }
3117const char * const  mDNS_DomainTypeNames[1] = {};
3118mStatus 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; }
3121mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3122mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
3123	{ ( void ) m; ( void ) set; ( void ) flapping; return 0; }
3124void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
3125void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
3126void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router)
3127	{ ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
3128mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
3129mStatus 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; }
3132mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
3133void TriggerEventCompletion(void);
3134void TriggerEventCompletion() {}
3135mDNS 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
3140const 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
3144const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
3145asm(".desc ___crashreporter_info__, 0x10");
3146#endif
3147