source: rtems-libbsd/mDNSResponder/mDNSShared/dnsextd.c @ a814950

55-freebsd-126-freebsd-12
Last change on this file since a814950 was a814950, checked in by Sebastian Huber <sebastian.huber@…>, on 09/19/18 at 06:55:35

mDNSResponder: Update to v765.50.9

The sources can be obtained via:

https://opensource.apple.com/tarballs/mDNSResponder/mDNSResponder-765.50.9.tar.gz

Update #3522.

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