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