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