]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnsextd.c
mDNSResponder-878.230.2.tar.gz
[apple/mdnsresponder.git] / mDNSShared / dnsextd.c
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
44 extern int daemon(int, int);
45 #endif
46
47 // Solaris doesn't have daemon(), so we define it here
48 #ifdef NOT_HAVE_DAEMON
49 #include "../mDNSPosix/mDNSUNP.h" // For daemon()
50 #endif // NOT_HAVE_DAEMON
51
52 #include "dnsextd.h"
53 #include "../mDNSShared/uds_daemon.h"
54 #include "../mDNSShared/dnssd_ipc.h"
55 #include "../mDNSCore/uDNS.h"
56 #include "../mDNSShared/DebugServices.h"
57
58 // Compatibility workaround
59 #ifndef AF_LOCAL
60 #define AF_LOCAL AF_UNIX
61 #endif
62
63 //
64 // Constants
65 //
66 mDNSexport const char ProgramName[] = "dnsextd";
67
68 #define LOOPBACK "127.0.0.1"
69 #if !defined(LISTENQ)
70 # define LISTENQ 128 // tcp connection backlog
71 #endif
72 #define RECV_BUFLEN 9000
73 #define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
74 #define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
75 #define SRV_TTL 7200 // TTL For _dns-update SRV records
76 #define CONFIG_FILE "/etc/dnsextd.conf"
77 #define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
78
79 // LLQ Lease bounds (seconds)
80 #define LLQ_MIN_LEASE (15 * 60)
81 #define LLQ_MAX_LEASE (120 * 60)
82 #define LLQ_LEASE_FUDGE 60
83
84 // LLQ SOA poll interval (microseconds)
85 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
86 #define LLQ_MONITOR_INTERVAL 250000
87 #ifdef SIGINFO
88 #define INFO_SIGNAL SIGINFO
89 #else
90 #define INFO_SIGNAL SIGUSR1
91 #endif
92
93 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
94
95 //
96 // Data Structures
97 // Structs/fields that must be locked for thread safety are explicitly commented
98 //
99
100 // args passed to UDP request handler thread as void*
101
102 typedef struct
103 {
104 PktMsg pkt;
105 struct sockaddr_in cliaddr;
106 DaemonInfo *d;
107 int sd;
108 } UDPContext;
109
110 // args passed to TCP request handler thread as void*
111 typedef struct
112 {
113 PktMsg pkt;
114 struct sockaddr_in cliaddr;
115 TCPSocket *sock; // socket connected to client
116 DaemonInfo *d;
117 } TCPContext;
118
119 // args passed to UpdateAnswerList thread as void*
120 typedef struct
121 {
122 DaemonInfo *d;
123 AnswerListElem *a;
124 } UpdateAnswerListArgs;
125
126 //
127 // Global Variables
128 //
129
130 // booleans to determine runtime output
131 // read-only after initialization (no mutex protection)
132 static mDNSBool foreground = 0;
133 static mDNSBool verbose = 0;
134
135 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
136 static mDNSBool terminate = 0;
137 static mDNSBool dumptable = 0;
138 static mDNSBool hangup = 0;
139
140 // global for config file location
141 static char * cfgfile = NULL;
142
143 //
144 // Logging Routines
145 // Log messages are delivered to syslog unless -f option specified
146 //
147
148 // common message logging subroutine
149 mDNSlocal void PrintLog(const char *buffer)
150 {
151 if (foreground)
152 {
153 fprintf(stderr,"%s\n", buffer);
154 fflush(stderr);
155 }
156 else
157 {
158 openlog("dnsextd", LOG_CONS, LOG_DAEMON);
159 syslog(LOG_ERR, "%s", buffer);
160 closelog();
161 }
162 }
163
164 // Verbose Logging (conditional on -v option)
165 mDNSlocal void VLog(const char *format, ...)
166 {
167 char buffer[512];
168 va_list ptr;
169
170 if (!verbose) return;
171 va_start(ptr,format);
172 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
173 va_end(ptr);
174 PrintLog(buffer);
175 }
176
177 // Unconditional Logging
178 mDNSlocal void Log(const char *format, ...)
179 {
180 char buffer[512];
181 va_list ptr;
182
183 va_start(ptr,format);
184 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
185 va_end(ptr);
186 PrintLog(buffer);
187 }
188
189 // Error Logging
190 // prints message "dnsextd <function>: <operation> - <error message>"
191 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
192 mDNSlocal void LogErr(const char *fn, const char *operation)
193 {
194 char buf[512], errbuf[256];
195 strerror_r(errno, errbuf, sizeof(errbuf));
196 snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, errbuf);
197 PrintLog(buf);
198 }
199
200 //
201 // Networking Utility Routines
202 //
203
204 // Convert DNS Message Header from Network to Host byte order
205 mDNSlocal void HdrNToH(PktMsg *pkt)
206 {
207 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
208 mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
209 pkt->msg.h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
210 pkt->msg.h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
211 pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
212 pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
213 }
214
215 // Convert DNS Message Header from Host to Network byte order
216 mDNSlocal void HdrHToN(PktMsg *pkt)
217 {
218 mDNSu16 numQuestions = pkt->msg.h.numQuestions;
219 mDNSu16 numAnswers = pkt->msg.h.numAnswers;
220 mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
221 mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
222 mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
223
224 // Put all the integer values in IETF byte-order (MSB first, LSB second)
225 *ptr++ = (mDNSu8)(numQuestions >> 8);
226 *ptr++ = (mDNSu8)(numQuestions & 0xFF);
227 *ptr++ = (mDNSu8)(numAnswers >> 8);
228 *ptr++ = (mDNSu8)(numAnswers & 0xFF);
229 *ptr++ = (mDNSu8)(numAuthorities >> 8);
230 *ptr++ = (mDNSu8)(numAuthorities & 0xFF);
231 *ptr++ = (mDNSu8)(numAdditionals >> 8);
232 *ptr++ = (mDNSu8)(numAdditionals & 0xFF);
233 }
234
235
236 // Add socket to event loop
237
238 mDNSlocal mStatus AddSourceToEventLoop( DaemonInfo * self, TCPSocket *sock, EventCallback callback, void *context )
239 {
240 EventSource * newSource;
241 mStatus err = mStatus_NoError;
242
243 if ( self->eventSources.LinkOffset == 0 )
244 {
245 InitLinkedList( &self->eventSources, offsetof( EventSource, next));
246 }
247
248 newSource = ( EventSource*) malloc( sizeof *newSource );
249 if ( newSource == NULL )
250 {
251 err = mStatus_NoMemoryErr;
252 goto exit;
253 }
254
255 newSource->callback = callback;
256 newSource->context = context;
257 newSource->sock = sock;
258 newSource->fd = mDNSPlatformTCPGetFD( sock );
259
260 AddToTail( &self->eventSources, newSource );
261
262 exit:
263
264 return err;
265 }
266
267
268 // Remove socket from event loop
269
270 mDNSlocal mStatus RemoveSourceFromEventLoop( DaemonInfo * self, TCPSocket *sock )
271 {
272 EventSource * source;
273 mStatus err;
274
275 for ( source = ( EventSource* ) self->eventSources.Head; source; source = source->next )
276 {
277 if ( source->sock == sock )
278 {
279 RemoveFromList( &self->eventSources, source );
280
281 free( source );
282 err = mStatus_NoError;
283 goto exit;
284 }
285 }
286
287 err = mStatus_NoSuchNameErr;
288
289 exit:
290
291 return err;
292 }
293
294 // create a socket connected to nameserver
295 // caller terminates connection via close()
296 mDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
297 {
298 int ntries = 0, retry = 0;
299
300 while (1)
301 {
302 mDNSIPPort port = zeroIPPort;
303 int fd;
304
305 TCPSocket *sock = mDNSPlatformTCPSocket(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
323 mDNSlocal int MySend(TCPSocket *sock, const void *msg, int len)
324 {
325 int selectval, n, nsent = 0;
326 fd_set wset;
327 struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
328
329 while (nsent < len)
330 {
331 int fd;
332
333 FD_ZERO(&wset);
334
335 fd = mDNSPlatformTCPGetFD( sock );
336
337 FD_SET( fd, &wset );
338 selectval = select( fd+1, NULL, &wset, NULL, &timeout);
339 if (selectval < 0) { LogErr("MySend", "select"); return -1; }
340 if (!selectval || !FD_ISSET(fd, &wset)) { Log("MySend - timeout"); return -1; }
341
342 n = mDNSPlatformWriteTCP( sock, ( char* ) msg + nsent, len - nsent);
343
344 if (n < 0) { LogErr("MySend", "send"); return -1; }
345 nsent += n;
346 }
347 return 0;
348 }
349
350 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
351 mDNSlocal int SendPacket(TCPSocket *sock, PktMsg *pkt)
352 {
353 // send the lenth, in network byte order
354 mDNSu16 len = htons((mDNSu16)pkt->len);
355 if (MySend(sock, &len, sizeof(len)) < 0) return -1;
356
357 // send the message
358 VLog("SendPacket Q:%d A:%d A:%d A:%d ",
359 ntohs(pkt->msg.h.numQuestions),
360 ntohs(pkt->msg.h.numAnswers),
361 ntohs(pkt->msg.h.numAuthorities),
362 ntohs(pkt->msg.h.numAdditionals));
363 return MySend(sock, &pkt->msg, pkt->len);
364 }
365
366 // Receive len bytes, waiting until we have all of them.
367 // Returns number of bytes read (which should always be the number asked for).
368 static int my_recv(TCPSocket *sock, void *const buf, const int len, mDNSBool * closed)
369 {
370 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
371 // use an explicit while() loop instead.
372 // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
373 // arithmetic on "void *" pointers is compiler-dependent.
374
375 fd_set rset;
376 struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
377 int selectval, remaining = len;
378 char *ptr = (char *)buf;
379 ssize_t num_read;
380
381 while (remaining)
382 {
383 int fd;
384
385 fd = mDNSPlatformTCPGetFD( sock );
386
387 FD_ZERO(&rset);
388 FD_SET(fd, &rset);
389 selectval = select(fd+1, &rset, NULL, NULL, &timeout);
390 if (selectval < 0) { LogErr("my_recv", "select"); return -1; }
391 if (!selectval || !FD_ISSET(fd, &rset))
392 {
393 Log("my_recv - timeout");
394 return -1;
395 }
396
397 num_read = mDNSPlatformReadTCP( sock, ptr, remaining, closed );
398
399 if (((num_read == 0) && *closed) || (num_read < 0) || (num_read > remaining)) return -1;
400 if (num_read == 0) return 0;
401 ptr += num_read;
402 remaining -= num_read;
403 }
404 return(len);
405 }
406
407 // Return a DNS Message read off of a TCP socket, or NULL on failure
408 // If storage is non-null, result is placed in that buffer. Otherwise,
409 // returned value is allocated with Malloc, and contains sufficient extra
410 // storage for a Lease OPT RR
411
412 mDNSlocal PktMsg*
413 RecvPacket
414 (
415 TCPSocket * sock,
416 PktMsg * storage,
417 mDNSBool * closed
418 )
419 {
420 int nread;
421 int allocsize;
422 mDNSu16 msglen = 0;
423 PktMsg * pkt = NULL;
424 unsigned int srclen;
425 int fd;
426 mStatus err = 0;
427
428 fd = mDNSPlatformTCPGetFD( sock );
429
430 nread = my_recv( sock, &msglen, sizeof( msglen ), closed );
431
432 require_action_quiet( nread != -1, exit, err = mStatus_UnknownErr );
433 require_action_quiet( nread > 0, exit, err = mStatus_NoError );
434
435 msglen = ntohs( msglen );
436 require_action_quiet( nread == sizeof( msglen ), exit, err = mStatus_UnknownErr; Log( "Could not read length field of message") );
437
438 if ( storage )
439 {
440 require_action_quiet( msglen <= sizeof( storage->msg ), exit, err = mStatus_UnknownErr; Log( "RecvPacket: provided buffer too small." ) );
441 pkt = storage;
442 }
443 else
444 {
445 // buffer extra space to add an OPT RR
446
447 if ( msglen > sizeof(DNSMessage))
448 {
449 allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
450 }
451 else
452 {
453 allocsize = sizeof(PktMsg);
454 }
455
456 pkt = malloc(allocsize);
457 require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) );
458 mDNSPlatformMemZero( pkt, sizeof( *pkt ) );
459 }
460
461 pkt->len = msglen;
462 srclen = sizeof(pkt->src);
463
464 if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) )
465 {
466 LogErr("RecvPacket", "getpeername");
467 mDNSPlatformMemZero(&pkt->src, sizeof(pkt->src));
468 }
469
470 nread = my_recv(sock, &pkt->msg, msglen, closed );
471 require_action_quiet( nread >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvPacket", "recv" ) );
472 require_action_quiet( nread == msglen, exit, err = mStatus_UnknownErr ; Log( "Could not read entire message" ) );
473 require_action_quiet( pkt->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr ; Log( "RecvPacket: Message too short (%d bytes)", pkt->len ) );
474
475 exit:
476
477 if ( err && pkt )
478 {
479 if ( pkt != storage )
480 {
481 free(pkt);
482 }
483
484 pkt = NULL;
485 }
486
487 return pkt;
488 }
489
490
491 mDNSlocal DNSZone*
492 FindZone
493 (
494 DaemonInfo * self,
495 domainname * name
496 )
497 {
498 DNSZone * zone;
499
500 for ( zone = self->zones; zone; zone = zone->next )
501 {
502 if ( SameDomainName( &zone->name, name ) )
503 {
504 break;
505 }
506 }
507
508 return zone;
509 }
510
511
512 mDNSlocal mDNSBool
513 ZoneHandlesName
514 (
515 const domainname * zname,
516 const domainname * dname
517 )
518 {
519 mDNSu16 i = DomainNameLength( zname );
520 mDNSu16 j = DomainNameLength( dname );
521
522 if ( ( i == ( MAX_DOMAIN_NAME + 1 ) ) || ( j == ( MAX_DOMAIN_NAME + 1 ) ) || ( i > j ) || ( memcmp( zname->c, dname->c + ( j - i ), i ) != 0 ) )
523 {
524 return mDNSfalse;
525 }
526
527 return mDNStrue;
528 }
529
530
531 mDNSlocal mDNSBool IsQuery( PktMsg * pkt )
532 {
533 return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery );
534 }
535
536
537 mDNSlocal mDNSBool IsUpdate( PktMsg * pkt )
538 {
539 return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_OP_Update );
540 }
541
542
543 mDNSlocal mDNSBool IsNotify(PktMsg *pkt)
544 {
545 return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( mDNSu8) ( kDNSFlag0_OP_Notify );
546 }
547
548
549 mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
550 {
551 const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
552 LargeCacheRecord lcr;
553 int i;
554 mDNSBool result = mDNSfalse;
555
556 HdrNToH(pkt);
557 if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
558
559 if (!pkt->msg.h.numAdditionals) goto end;
560 ptr = LocateAdditionals(&pkt->msg, end);
561 if (!ptr) goto end;
562
563 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
576 end:
577 HdrHToN(pkt);
578 return result;
579 }
580
581 // !!!KRS implement properly
582 mDNSlocal 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
590 mDNSlocal mDNSBool
591 IsPublicSRV
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
618 exit:
619
620 return ret;
621 }
622
623
624 mDNSlocal void
625 SetZone
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
690 mDNSlocal int
691 UDPServerTransaction(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
739 exit:
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
754 mDNSlocal 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
775 failure:
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 //
783 mDNSlocal 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
804 mDNSlocal 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
832 mDNSlocal 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
865 mDNSlocal 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
878 mDNSlocal 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.
906 mDNSlocal 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
996 exit:
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
1010 mDNSlocal 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
1023 mDNSlocal void PrintUsage(void)
1024 {
1025 fprintf(stderr, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1026 "Use \"dnsextd -h\" for help\n");
1027 }
1028
1029 mDNSlocal 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
1060 mDNSlocal 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
1127 arg_error:
1128
1129 PrintUsage();
1130 return -1;
1131 }
1132
1133
1134 //
1135 // Initialization Routines
1136 //
1137
1138 // Allocate memory, initialize locks and bookkeeping variables
1139 mDNSlocal 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
1151 mDNSlocal int
1152 SetupSockets
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
1279 exit:
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
1290 mDNSlocal 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
1330 end:
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)
1336 mDNSlocal 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
1372 mDNSlocal 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
1465 cleanup:
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
1472 mDNSlocal 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
1496 mDNSlocal PktMsg*
1497 HandleRequest
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 mDNSu32 lease = 0;
1510 mDNSBool gotlease;
1511 if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) == kDNSFlag0_OP_Update)
1512 {
1513 int i, adds = 0, dels = 0;
1514 const mDNSu8 *ptr, *end = (mDNSu8 *)&request->msg + request->len;
1515 HdrNToH(request);
1516 gotlease = GetPktLease(&mDNSStorage, &request->msg, end, &lease);
1517 ptr = LocateAuthorities(&request->msg, end);
1518 for (i = 0; i < request->msg.h.mDNS_numUpdates; i++)
1519 {
1520 LargeCacheRecord lcr;
1521 ptr = GetLargeResourceRecord(NULL, &request->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1522 if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rroriginalttl) adds++;else dels++;
1523 }
1524 HdrHToN(request);
1525 if (adds && !gotlease)
1526 {
1527 static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } };
1528 Log("Rejecting Update Request with %d additions but no lease", adds);
1529 reply = malloc(sizeof(*reply));
1530 mDNSPlatformMemZero(&reply->src, sizeof(reply->src));
1531 reply->len = sizeof(DNSMessageHeader);
1532 reply->zone = NULL;
1533 reply->isZonePublic = 0;
1534 InitializeDNSMessage(&reply->msg.h, request->msg.h.id, UpdateRefused);
1535 return(reply);
1536 }
1537 if (lease > 7200) // Don't allow lease greater than two hours; typically 90-minute renewal period
1538 lease = 7200;
1539 }
1540 // Send msg to server, read reply
1541
1542 if ( request->len <= 512 )
1543 {
1544 mDNSBool trunc;
1545
1546 if ( UDPServerTransaction( self, request, &buf, &trunc) < 0 )
1547 {
1548 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1549 }
1550 else if ( trunc )
1551 {
1552 VLog("HandleRequest - answer truncated. Using TCP");
1553 }
1554 else
1555 {
1556 reply = &buf; // success
1557 }
1558 }
1559
1560 if ( !reply )
1561 {
1562 mDNSBool closed;
1563 int res;
1564
1565 sock = ConnectToServer( self );
1566 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 ) ) );
1567
1568 res = SendPacket( sock, request );
1569 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 ) ) );
1570
1571 reply = RecvPacket( sock, &buf, &closed );
1572 }
1573
1574 // IMPORTANT: reply is in network byte order at this point in the code
1575 // We keep it this way because we send it back to the client in the same form
1576
1577 // Is it an update?
1578
1579 if ( reply && ( ( reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( kDNSFlag0_OP_Update | kDNSFlag0_QR_Response ) ) )
1580 {
1581 char pingmsg[4];
1582 mDNSBool ok = SuccessfulUpdateTransaction( request, reply );
1583 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 ) ) );
1584
1585 UpdateLeaseTable( request, self, lease );
1586
1587 if ( lease > 0 )
1588 {
1589 leaseReply = FormatLeaseReply( self, reply, lease );
1590
1591 if ( !leaseReply )
1592 {
1593 Log("HandleRequest - unable to format lease reply");
1594 }
1595
1596 // %%% Looks like a potential memory leak -- who frees the original reply?
1597 reply = leaseReply;
1598 }
1599
1600 // tell the main thread there was an update so it can send LLQs
1601
1602 if ( send( self->LLQEventNotifySock, pingmsg, sizeof( pingmsg ), 0 ) != sizeof( pingmsg ) )
1603 {
1604 LogErr("HandleRequest", "send");
1605 }
1606 }
1607
1608 exit:
1609
1610 if ( sock )
1611 {
1612 mDNSPlatformTCPCloseConnection( sock );
1613 }
1614
1615 if ( reply == &buf )
1616 {
1617 reply = malloc( sizeof( *reply ) );
1618
1619 if ( reply )
1620 {
1621 reply->len = buf.len;
1622 memcpy(&reply->msg, &buf.msg, buf.len);
1623 }
1624 else
1625 {
1626 LogErr("HandleRequest", "malloc");
1627 }
1628 }
1629
1630 return reply;
1631 }
1632
1633
1634 //
1635 // LLQ Support Routines
1636 //
1637
1638 // Set fields of an LLQ OPT Resource Record
1639 mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, const mDNSOpaque64 *const id, mDNSs32 lease)
1640 {
1641 mDNSPlatformMemZero(opt, sizeof(*opt));
1642 mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
1643 opt->resrec.rrclass = NormalMaxDNSMessageData;
1644 opt->resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
1645 opt->resrec.rdestimate = sizeof(rdataOPT);
1646 opt->resrec.rdata->u.opt[0].opt = kDNSOpt_LLQ;
1647 opt->resrec.rdata->u.opt[0].u.llq.vers = kLLQ_Vers;
1648 opt->resrec.rdata->u.opt[0].u.llq.llqOp = opcode;
1649 opt->resrec.rdata->u.opt[0].u.llq.err = LLQErr_NoError;
1650 opt->resrec.rdata->u.opt[0].u.llq.id = *id;
1651 opt->resrec.rdata->u.opt[0].u.llq.llqlease = lease;
1652 }
1653
1654 // Calculate effective remaining lease of an LLQ
1655 mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
1656 {
1657 struct timeval t;
1658
1659 gettimeofday(&t, NULL);
1660 if (e->expire < t.tv_sec) return 0;
1661 else return e->expire - t.tv_sec;
1662 }
1663
1664 mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
1665 {
1666 int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
1667 LLQEntry **ptr = &d->LLQTable[bucket];
1668 AnswerListElem *a = e->AnswerList;
1669 char addr[32];
1670
1671 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
1672 VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
1673
1674 if (a && !(--a->refcount) && d->AnswerTableCount >= LLQ_TABLESIZE)
1675 {
1676 // currently, generating initial answers blocks the main thread, so we keep the answer list
1677 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1678 // if the ref count drops to zero AND there are more table elements than buckets
1679 // !!!KRS update this when we make the table dynamically growable
1680
1681 CacheRecord *cr = a->KnownAnswers, *tmp;
1682 AnswerListElem **tbl = &d->AnswerTable[bucket];
1683
1684 while (cr)
1685 {
1686 tmp = cr;
1687 cr = cr->next;
1688 free(tmp);
1689 }
1690
1691 while (*tbl && *tbl != a) tbl = &(*tbl)->next;
1692 if (*tbl) { *tbl = (*tbl)->next; free(a); d->AnswerTableCount--; }
1693 else Log("Error: DeleteLLQ - AnswerList not found in table");
1694 }
1695
1696 // remove LLQ from table, free memory
1697 while(*ptr && *ptr != e) ptr = &(*ptr)->next;
1698 if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1699 *ptr = (*ptr)->next;
1700 free(e);
1701 }
1702
1703 mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst, TCPSocket *sock)
1704 {
1705 char addr[32];
1706 int err = -1;
1707
1708 HdrHToN(pkt);
1709
1710 if ( sock )
1711 {
1712 if ( SendPacket( sock, pkt ) != 0 )
1713 {
1714 LogErr("DaemonInfo", "MySend");
1715 Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
1716 }
1717 }
1718 else
1719 {
1720 if (sendto(d->llq_udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
1721 {
1722 LogErr("DaemonInfo", "sendto");
1723 Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
1724 }
1725 }
1726
1727 err = 0;
1728 HdrNToH(pkt);
1729 return err;
1730 }
1731
1732 mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e)
1733 {
1734 PktMsg q;
1735 int i;
1736 TCPSocket *sock = NULL;
1737 const mDNSu8 *ansptr;
1738 mDNSu8 *end = q.msg.data;
1739 PktMsg buf, *reply = NULL;
1740 LargeCacheRecord lcr;
1741 CacheRecord *AnswerList = NULL;
1742 mDNSu8 rcode;
1743
1744 VLog("Querying server for %##s type %d", e->name.c, e->type);
1745
1746 InitializeDNSMessage(&q.msg.h, zeroID, uQueryFlags);
1747
1748 end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
1749 if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
1750 q.len = (int)(end - (mDNSu8 *)&q.msg);
1751
1752 HdrHToN(&q);
1753
1754 if (!e->UseTCP)
1755 {
1756 mDNSBool trunc;
1757
1758 if (UDPServerTransaction(d, &q, &buf, &trunc) < 0)
1759 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e->name.c);
1760 else if (trunc)
1761 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e->name.c); e->UseTCP = mDNStrue; }
1762 else reply = &buf; // success
1763 }
1764
1765 if (!reply)
1766 {
1767 mDNSBool closed;
1768
1769 sock = ConnectToServer(d);
1770 if (!sock) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
1771 if (SendPacket( sock, &q)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock ); goto end; }
1772 reply = RecvPacket( sock, NULL, &closed );
1773 mDNSPlatformTCPCloseConnection( sock );
1774 require_action( reply, end, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1775 }
1776
1777 HdrNToH(&q);
1778 if (reply) HdrNToH(reply);
1779
1780 if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
1781 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
1782 rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
1783 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; }
1784
1785 end = (mDNSu8 *)&reply->msg + reply->len;
1786 ansptr = LocateAnswers(&reply->msg, end);
1787 if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
1788
1789 for (i = 0; i < reply->msg.h.numAnswers; i++)
1790 {
1791 ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1792 if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
1793 if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative)
1794 {
1795 if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
1796 {
1797 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1798 lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
1799 }
1800 else
1801 {
1802 CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
1803 if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
1804 cr->next = AnswerList;
1805 AnswerList = cr;
1806 }
1807 }
1808 }
1809
1810 end:
1811 if (reply && reply != &buf) free(reply);
1812 return AnswerList;
1813 }
1814
1815 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1816 mDNSlocal void *UpdateAnswerList(void *args)
1817 {
1818 CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
1819 DaemonInfo *d = ((UpdateAnswerListArgs *)args)->d;
1820 AnswerListElem *a = ((UpdateAnswerListArgs *)args)->a;
1821
1822 free(args);
1823 args = NULL;
1824
1825 // get up to date answers
1826 NewAnswers = AnswerQuestion(d, a);
1827
1828 // first pass - mark all answers for deletion
1829 for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
1830 (*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
1831
1832 // second pass - mark answers pre-existent
1833 for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
1834 {
1835 for (na = &NewAnswers; *na; na = &(*na)->next)
1836 {
1837 if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec))
1838 { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
1839 }
1840 }
1841
1842 // third pass - add new records to Event list
1843 na = &NewAnswers;
1844 while (*na)
1845 {
1846 for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
1847 if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
1848 if (!*ka)
1849 {
1850 // answer is not in list - splice from NewAnswers list, add to Event list
1851 cr = *na;
1852 *na = (*na)->next; // splice from list
1853 cr->next = a->EventList; // add spliced record to event list
1854 a->EventList = cr;
1855 cr->resrec.rroriginalttl = 1; // 1 means add
1856 }
1857 else na = &(*na)->next;
1858 }
1859
1860 // move all the removes from the answer list to the event list
1861 ka = &a->KnownAnswers;
1862 while (*ka)
1863 {
1864 if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
1865 {
1866 cr = *ka;
1867 *ka = (*ka)->next;
1868 cr->next = a->EventList;
1869 a->EventList = cr;
1870 }
1871 else ka = &(*ka)->next;
1872 }
1873
1874 // lastly, free the remaining records (known answers) in NewAnswers list
1875 while (NewAnswers)
1876 {
1877 cr = NewAnswers;
1878 NewAnswers = NewAnswers->next;
1879 free(cr);
1880 }
1881
1882 return NULL;
1883 }
1884
1885 mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
1886 {
1887 PktMsg response;
1888 CacheRecord *cr;
1889 mDNSu8 *end = (mDNSu8 *)&response.msg.data;
1890 mDNSOpaque16 msgID;
1891 char rrbuf[MaxMsg], addrbuf[32];
1892 AuthRecord opt;
1893
1894 // Should this really be random? Do we use the msgID on the receiving end?
1895 msgID.NotAnInteger = random();
1896 if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
1897 InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
1898 end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
1899 if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
1900
1901 // put adds/removes in packet
1902 for (cr = e->AnswerList->EventList; cr; cr = cr->next)
1903 {
1904 if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
1905 VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove" : "Add", rrbuf);
1906 end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
1907 if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
1908 }
1909
1910 FormatLLQOpt(&opt, kLLQOp_Event, &e->id, LLQLease(e));
1911 end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
1912 if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
1913
1914 response.len = (int)(end - (mDNSu8 *)&response.msg);
1915 if (SendLLQ(d, &response, e->cli, NULL ) < 0) LogMsg("Error: SendEvents - SendLLQ");
1916 }
1917
1918 mDNSlocal void PrintLLQAnswers(DaemonInfo *d)
1919 {
1920 int i;
1921 char rrbuf[MaxMsg];
1922
1923 Log("Printing LLQ Answer Table contents");
1924
1925 for (i = 0; i < LLQ_TABLESIZE; i++)
1926 {
1927 AnswerListElem *a = d->AnswerTable[i];
1928 while(a)
1929 {
1930 int ancount = 0;
1931 const CacheRecord *rr = a->KnownAnswers;
1932 while (rr) { ancount++; rr = rr->next; }
1933 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a, a->name.c, a->type, a->refcount, ancount);
1934 for (rr = a->KnownAnswers; rr; rr = rr->next) Log("\t%s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, rrbuf));
1935 a = a->next;
1936 }
1937 }
1938 }
1939
1940 mDNSlocal void PrintLLQTable(DaemonInfo *d)
1941 {
1942 LLQEntry *e;
1943 char addr[32];
1944 int i;
1945
1946 Log("Printing LLQ table contents");
1947
1948 for (i = 0; i < LLQ_TABLESIZE; i++)
1949 {
1950 e = d->LLQTable[i];
1951 while(e)
1952 {
1953 char *state;
1954
1955 switch (e->state)
1956 {
1957 case RequestReceived: state = "RequestReceived"; break;
1958 case ChallengeSent: state = "ChallengeSent"; break;
1959 case Established: state = "Established"; break;
1960 default: state = "unknown";
1961 }
1962 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
1963
1964 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
1965 addr, state, e->qname.c, e->qtype, e->lease, LLQLease(e), e->AnswerList);
1966 e = e->next;
1967 }
1968 }
1969 }
1970
1971 // Send events to clients as a result of a change in the zone
1972 mDNSlocal void GenLLQEvents(DaemonInfo *d)
1973 {
1974 LLQEntry **e;
1975 int i;
1976 struct timeval t;
1977 UpdateAnswerListArgs *args;
1978
1979 VLog("Generating LLQ Events");
1980
1981 gettimeofday(&t, NULL);
1982
1983 // get all answers up to date
1984 for (i = 0; i < LLQ_TABLESIZE; i++)
1985 {
1986 AnswerListElem *a = d->AnswerTable[i];
1987 while(a)
1988 {
1989 args = malloc(sizeof(*args));
1990 if (!args) { LogErr("GenLLQEvents", "malloc"); return; }
1991 args->d = d;
1992 args->a = a;
1993 if (pthread_create(&a->tid, NULL, UpdateAnswerList, args) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
1994 usleep(1);
1995 a = a->next;
1996 }
1997 }
1998
1999 for (i = 0; i < LLQ_TABLESIZE; i++)
2000 {
2001 AnswerListElem *a = d->AnswerTable[i];
2002 while(a)
2003 {
2004 if (pthread_join(a->tid, NULL)) LogErr("GenLLQEvents", "pthread_join");
2005 a = a->next;
2006 }
2007 }
2008
2009 // for each established LLQ, send events
2010 for (i = 0; i < LLQ_TABLESIZE; i++)
2011 {
2012 e = &d->LLQTable[i];
2013 while(*e)
2014 {
2015 if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
2016 else
2017 {
2018 if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
2019 e = &(*e)->next;
2020 }
2021 }
2022 }
2023
2024 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2025 for (i = 0; i < LLQ_TABLESIZE; i++)
2026 {
2027 AnswerListElem *a = d->AnswerTable[i];
2028 while(a)
2029 {
2030 if (a->EventList)
2031 {
2032 CacheRecord *cr = a->EventList, *tmp;
2033 while (cr)
2034 {
2035 tmp = cr;
2036 cr = cr->next;
2037 if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
2038 else
2039 {
2040 tmp->next = a->KnownAnswers;
2041 a->KnownAnswers = tmp;
2042 tmp->resrec.rroriginalttl = 0;
2043 }
2044 }
2045 a->EventList = NULL;
2046 }
2047 a = a->next;
2048 }
2049 }
2050 }
2051
2052 mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
2053 {
2054 int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
2055 AnswerListElem *a = d->AnswerTable[bucket];
2056 while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
2057 if (!a)
2058 {
2059 a = malloc(sizeof(*a));
2060 if (!a) { LogErr("SetAnswerList", "malloc"); return; }
2061 AssignDomainName(&a->name, &e->qname);
2062 a->type = e->qtype;
2063 a->refcount = 0;
2064 a->EventList = NULL;
2065 a->UseTCP = mDNSfalse;
2066 a->next = d->AnswerTable[bucket];
2067 d->AnswerTable[bucket] = a;
2068 d->AnswerTableCount++;
2069 a->KnownAnswers = AnswerQuestion(d, a);
2070 }
2071
2072 e->AnswerList = a;
2073 a->refcount++;
2074 }
2075
2076 // Allocate LLQ entry, insert into table
2077 mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease )
2078 {
2079 char addr[32];
2080 struct timeval t;
2081 int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
2082 LLQEntry *e;
2083
2084 e = malloc(sizeof(*e));
2085 if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
2086
2087 inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
2088 VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
2089
2090 // initialize structure
2091 e->cli = cli;
2092 AssignDomainName(&e->qname, qname);
2093 e->qtype = qtype;
2094 e->id = zeroOpaque64;
2095 e->state = RequestReceived;
2096 e->AnswerList = NULL;
2097
2098 if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
2099 else if (lease > LLQ_MAX_LEASE) lease = LLQ_MAX_LEASE;
2100
2101 gettimeofday(&t, NULL);
2102 e->expire = t.tv_sec + (int)lease;
2103 e->lease = lease;
2104
2105 // add to table
2106 e->next = d->LLQTable[bucket];
2107 d->LLQTable[bucket] = e;
2108
2109 return e;
2110 }
2111
2112 // Handle a refresh request from client
2113 mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
2114 {
2115 AuthRecord opt;
2116 PktMsg ack;
2117 mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
2118 char addr[32];
2119
2120 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
2121 VLog("%s LLQ for %##s from %s", llq->llqlease ? "Refreshing" : "Deleting", e->qname.c, addr);
2122
2123 if (llq->llqlease)
2124 {
2125 struct timeval t;
2126 if (llq->llqlease < LLQ_MIN_LEASE) llq->llqlease = LLQ_MIN_LEASE;
2127 else if (llq->llqlease > LLQ_MAX_LEASE) llq->llqlease = LLQ_MIN_LEASE;
2128 gettimeofday(&t, NULL);
2129 e->expire = t.tv_sec + llq->llqlease;
2130 }
2131
2132 ack.src.sin_addr.s_addr = 0; // unused
2133 InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
2134 end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
2135 if (!end) { Log("Error: putQuestion"); return; }
2136
2137 FormatLLQOpt(&opt, kLLQOp_Refresh, &e->id, llq->llqlease ? LLQLease(e) : 0);
2138 end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
2139 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2140
2141 ack.len = (int)(end - (mDNSu8 *)&ack.msg);
2142 if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQRefresh");
2143
2144 if (llq->llqlease) e->state = Established;
2145 else DeleteLLQ(d, e);
2146 }
2147
2148 // Complete handshake with Ack an initial answers
2149 mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock)
2150 {
2151 char addr[32];
2152 CacheRecord *ptr;
2153 AuthRecord opt;
2154 PktMsg ack;
2155 mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
2156 char rrbuf[MaxMsg], addrbuf[32];
2157
2158 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
2159
2160 if (!mDNSSameOpaque64(&llq->id, &e->id) ||
2161 llq->vers != kLLQ_Vers ||
2162 llq->llqOp != kLLQOp_Setup ||
2163 llq->err != LLQErr_NoError ||
2164 llq->llqlease > e->lease + LLQ_LEASE_FUDGE ||
2165 llq->llqlease < e->lease - LLQ_LEASE_FUDGE)
2166 {
2167 Log("Incorrect challenge response from %s", addr);
2168 return;
2169 }
2170
2171 if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
2172 else VLog("Delivering LLQ ack + answers for %##s", e->qname.c);
2173
2174 // format ack + answers
2175 ack.src.sin_addr.s_addr = 0; // unused
2176 InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
2177 end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
2178 if (!end) { Log("Error: putQuestion"); return; }
2179
2180 if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
2181
2182 if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
2183 for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
2184 {
2185 if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
2186 VLog("%s Intitial Answer - %s", addr, rrbuf);
2187 end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
2188 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2189 }
2190
2191 FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
2192 end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
2193 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2194
2195 ack.len = (int)(end - (mDNSu8 *)&ack.msg);
2196 if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQCompleteHandshake");
2197 }
2198
2199 mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
2200 {
2201 struct timeval t;
2202 PktMsg challenge;
2203 mDNSu8 *end = challenge.msg.data;
2204 AuthRecord opt;
2205
2206 if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
2207 else VLog("Sending LLQ setup challenge for %##s", e->qname.c);
2208
2209 if (!mDNSOpaque64IsZero(&llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2210 if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2211
2212 if (mDNSOpaque64IsZero(&e->id)) // don't regenerate random ID for retransmissions
2213 {
2214 // construct ID <time><random>
2215 gettimeofday(&t, NULL);
2216 e->id.l[0] = t.tv_sec;
2217 e->id.l[1] = random();
2218 }
2219
2220 // format response (query + LLQ opt rr)
2221 challenge.src.sin_addr.s_addr = 0; // unused
2222 InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
2223 end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
2224 if (!end) { Log("Error: putQuestion"); return; }
2225 FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
2226 end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
2227 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2228 challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
2229 if (SendLLQ(d, &challenge, e->cli, NULL)) { Log("Error: LLQSetupChallenge"); return; }
2230 e->state = ChallengeSent;
2231 }
2232
2233 // Take action on an LLQ message from client. Entry must be initialized and in table
2234 mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
2235 {
2236 switch(e->state)
2237 {
2238 case RequestReceived:
2239 if ( sock )
2240 {
2241 struct timeval t;
2242 gettimeofday(&t, NULL);
2243 e->id.l[0] = t.tv_sec; // construct ID <time><random>
2244 e->id.l[1] = random();
2245 llq->id = e->id;
2246 LLQCompleteHandshake( d, e, llq, msgID, sock );
2247
2248 // Set the state to established because we've just set the LLQ up using TCP
2249 e->state = Established;
2250 }
2251 else
2252 {
2253 LLQSetupChallenge(d, e, llq, msgID);
2254 }
2255 return;
2256 case ChallengeSent:
2257 if (mDNSOpaque64IsZero(&llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
2258 else LLQCompleteHandshake(d, e, llq, msgID, sock );
2259 return;
2260 case Established:
2261 if (mDNSOpaque64IsZero(&llq->id))
2262 {
2263 // client started over. reset state.
2264 LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->llqlease );
2265 if (!newe) return;
2266 DeleteLLQ(d, e);
2267 LLQSetupChallenge(d, newe, llq, msgID);
2268 return;
2269 }
2270 else if (llq->llqOp == kLLQOp_Setup)
2271 { LLQCompleteHandshake(d, e, llq, msgID, sock); return; } // Ack lost
2272 else if (llq->llqOp == kLLQOp_Refresh)
2273 { LLQRefresh(d, e, llq, msgID, sock); return; }
2274 else { Log("Unhandled message for established LLQ"); return; }
2275 }
2276 }
2277
2278 mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, const mDNSOpaque64 *const id)
2279 {
2280 int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
2281 LLQEntry *ptr = d->LLQTable[bucket];
2282
2283 while(ptr)
2284 {
2285 if (((ptr->state == ChallengeSent && mDNSOpaque64IsZero(id) && (cli.sin_port == ptr->cli.sin_port)) || // zero-id due to packet loss OK in state ChallengeSent
2286 mDNSSameOpaque64(id, &ptr->id)) && // id match
2287 (cli.sin_addr.s_addr == ptr->cli.sin_addr.s_addr) && (qtype == ptr->qtype) && SameDomainName(&ptr->qname, qname)) // same source, type, qname
2288 return ptr;
2289 ptr = ptr->next;
2290 }
2291 return NULL;
2292 }
2293
2294 mDNSlocal int
2295 RecvNotify
2296 (
2297 DaemonInfo * d,
2298 PktMsg * pkt
2299 )
2300 {
2301 int res;
2302 int err = 0;
2303
2304 pkt->msg.h.flags.b[0] |= kDNSFlag0_QR_Response;
2305
2306 res = sendto( d->udpsd, &pkt->msg, pkt->len, 0, ( struct sockaddr* ) &pkt->src, sizeof( pkt->src ) );
2307 require_action( res == ( int ) pkt->len, exit, err = mStatus_UnknownErr; LogErr( "RecvNotify", "sendto" ) );
2308
2309 exit:
2310
2311 return err;
2312 }
2313
2314
2315 mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
2316 {
2317 DNSQuestion q;
2318 LargeCacheRecord opt;
2319 int i, err = -1;
2320 char addr[32];
2321 const mDNSu8 *qptr = pkt->msg.data;
2322 const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
2323 const mDNSu8 *aptr;
2324 LLQOptData *llq = NULL;
2325 LLQEntry *e = NULL;
2326
2327 HdrNToH(pkt);
2328 aptr = LocateAdditionals(&pkt->msg, end); // Can't do this until after HdrNToH(pkt);
2329 inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
2330
2331 VLog("Received LLQ msg from %s", addr);
2332 // sanity-check packet
2333 if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
2334 {
2335 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
2336 goto end;
2337 }
2338
2339 // Locate the OPT record.
2340 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2341 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2342 // but not necessarily the *last* entry in the Additional Section.
2343 for (i = 0; i < pkt->msg.h.numAdditionals; i++)
2344 {
2345 aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
2346 if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
2347 if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
2348 }
2349
2350 // validate OPT
2351 if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; }
2352 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); }
2353
2354 // dispatch each question
2355 for (i = 0; i < pkt->msg.h.numQuestions; i++)
2356 {
2357 qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
2358 if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
2359 llq = &opt.r.resrec.rdata->u.opt[i].u.llq; // point into OptData at index i
2360 if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
2361
2362 e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id);
2363 if (!e)
2364 {
2365 // no entry - if zero ID, create new
2366 e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->llqlease );
2367 if (!e) goto end;
2368 }
2369 UpdateLLQ(d, e, llq, pkt->msg.h.id, sock);
2370 }
2371 err = 0;
2372
2373 end:
2374 HdrHToN(pkt);
2375 return err;
2376 }
2377
2378
2379 mDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo ** key, mDNSu16 * rcode, mDNSu16 * tcode )
2380 {
2381 const mDNSu8 * lastPtr = NULL;
2382 const mDNSu8 * ptr = NULL;
2383 DomainAuthInfo * keys;
2384 mDNSu8 * end = ( mDNSu8* ) &pkt->msg + pkt->len;
2385 LargeCacheRecord lcr;
2386 mDNSBool hasTSIG = mDNSfalse;
2387 mDNSBool strip = mDNSfalse;
2388 mDNSBool ok = mDNSfalse;
2389 int i;
2390
2391 // Unused parameters
2392
2393 ( void ) d;
2394
2395 HdrNToH(pkt);
2396
2397 *key = NULL;
2398 bzero(&lcr, sizeof(lcr));
2399
2400 if ( pkt->msg.h.numAdditionals )
2401 {
2402 ptr = LocateAdditionals(&pkt->msg, end);
2403 if (ptr)
2404 {
2405 for (i = 0; i < pkt->msg.h.numAdditionals; i++)
2406 {
2407 lastPtr = ptr;
2408 ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2409 if (!ptr)
2410 {
2411 Log("Unable to read additional record");
2412 lastPtr = NULL;
2413 break;
2414 }
2415 }
2416
2417 hasTSIG = ( ptr && lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rrtype == kDNSType_TSIG );
2418 }
2419 else
2420 {
2421 LogMsg( "IsAuthorized: unable to find Additional section" );
2422 }
2423 }
2424
2425 // If we don't know what zone this is, then it's authorized.
2426
2427 if ( !pkt->zone )
2428 {
2429 ok = mDNStrue;
2430 strip = mDNSfalse;
2431 goto exit;
2432 }
2433
2434 if ( IsQuery( pkt ) )
2435 {
2436 keys = pkt->zone->queryKeys;
2437 strip = mDNStrue;
2438 }
2439 else if ( IsUpdate( pkt ) )
2440 {
2441 keys = pkt->zone->updateKeys;
2442 strip = mDNSfalse;
2443 }
2444 else
2445 {
2446 ok = mDNStrue;
2447 strip = mDNSfalse;
2448 goto exit;
2449 }
2450
2451 if ( pkt->isZonePublic )
2452 {
2453 ok = mDNStrue;
2454 goto exit;
2455 }
2456
2457 // If there are no keys, then we're authorized
2458
2459 if ( ( hasTSIG && !keys ) || ( !hasTSIG && keys ) )
2460 {
2461 Log( "Invalid TSIG spec %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
2462 *rcode = kDNSFlag1_RC_NotAuth;
2463 *tcode = TSIG_ErrBadKey;
2464 strip = mDNStrue;
2465 ok = mDNSfalse;
2466 goto exit;
2467 }
2468
2469 // Find the right key
2470
2471 for ( *key = keys; *key; *key = (*key)->next )
2472 {
2473 if ( SameDomainName( lcr.r.resrec.name, &(*key)->keyname ) )
2474 {
2475 break;
2476 }
2477 }
2478
2479 if ( !(*key) )
2480 {
2481 Log( "Invalid TSIG name %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
2482 *rcode = kDNSFlag1_RC_NotAuth;
2483 *tcode = TSIG_ErrBadKey;
2484 strip = mDNStrue;
2485 ok = mDNSfalse;
2486 goto exit;
2487 }
2488
2489 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2490 // lifting of message verification
2491
2492 pkt->msg.h.numAdditionals--;
2493
2494 HdrHToN( pkt );
2495
2496 ok = DNSDigest_VerifyMessage( &pkt->msg, ( mDNSu8* ) lastPtr, &lcr, (*key), rcode, tcode );
2497
2498 HdrNToH( pkt );
2499
2500 pkt->msg.h.numAdditionals++;
2501
2502 exit:
2503
2504 if ( hasTSIG && strip )
2505 {
2506 // Strip the TSIG from the message
2507
2508 pkt->msg.h.numAdditionals--;
2509 pkt->len = lastPtr - ( mDNSu8* ) ( &pkt->msg );
2510 }
2511
2512 HdrHToN(pkt);
2513
2514 return ok;
2515 }
2516
2517 // request handler wrappers for TCP and UDP requests
2518 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2519
2520 mDNSlocal void*
2521 UDPMessageHandler
2522 (
2523 void * vptr
2524 )
2525 {
2526 UDPContext * context = ( UDPContext* ) vptr;
2527 PktMsg * reply = NULL;
2528 int res;
2529 mStatus err;
2530
2531 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2532 // may give us a long answer that would require truncation for UDP delivery to client
2533
2534 reply = HandleRequest( context->d, &context->pkt );
2535 require_action( reply, exit, err = mStatus_UnknownErr );
2536
2537 res = sendto( context->sd, &reply->msg, reply->len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
2538 require_action_quiet( res == ( int ) reply->len, exit, LogErr( "UDPMessageHandler", "sendto" ) );
2539
2540 exit:
2541
2542 if ( reply )
2543 {
2544 free( reply );
2545 }
2546
2547 free( context );
2548
2549 pthread_exit( NULL );
2550
2551 return NULL;
2552 }
2553
2554
2555 mDNSlocal int
2556 RecvUDPMessage
2557 (
2558 DaemonInfo * self,
2559 int sd
2560 )
2561 {
2562 UDPContext * context = NULL;
2563 pthread_t tid;
2564 mDNSu16 rcode;
2565 mDNSu16 tcode;
2566 DomainAuthInfo * key;
2567 unsigned int clisize = sizeof( context->cliaddr );
2568 int res;
2569 mStatus err = mStatus_NoError;
2570
2571 context = malloc( sizeof( UDPContext ) );
2572 require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
2573
2574 mDNSPlatformMemZero( context, sizeof( *context ) );
2575 context->d = self;
2576 context->sd = sd;
2577
2578 res = recvfrom(sd, &context->pkt.msg, sizeof(context->pkt.msg), 0, (struct sockaddr *)&context->cliaddr, &clisize);
2579
2580 require_action( res >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvUDPMessage", "recvfrom" ) );
2581 context->pkt.len = res;
2582 require_action( clisize == sizeof( context->cliaddr ), exit, err = mStatus_UnknownErr ; Log( "Client address of unknown size %d", clisize ) );
2583 context->pkt.src = context->cliaddr;
2584
2585 // Set the zone in the packet
2586
2587 SetZone( context->d, &context->pkt );
2588
2589 // Notify messages handled by main thread
2590
2591 if ( IsNotify( &context->pkt ) )
2592 {
2593 int e = RecvNotify( self, &context->pkt );
2594 free(context);
2595 return e;
2596 }
2597 else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
2598 {
2599 if ( IsLLQRequest( &context->pkt ) )
2600 {
2601 // LLQ messages handled by main thread
2602 int e = RecvLLQ( self, &context->pkt, NULL );
2603 free(context);
2604 return e;
2605 }
2606
2607 if ( IsLLQAck(&context->pkt ) )
2608 {
2609 // !!!KRS need to do acks + retrans
2610
2611 free(context);
2612 return 0;
2613 }
2614
2615 err = pthread_create( &tid, NULL, UDPMessageHandler, context );
2616 require_action( !err, exit, LogErr( "RecvUDPMessage", "pthread_create" ) );
2617
2618 pthread_detach(tid);
2619 }
2620 else
2621 {
2622 PktMsg reply;
2623 int e;
2624
2625 memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
2626
2627 reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
2628 reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
2629
2630 e = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
2631 require_action_quiet( e == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
2632
2633 err = mStatus_NoAuth;
2634 }
2635
2636 exit:
2637
2638 if ( err && context )
2639 {
2640 free( context );
2641 }
2642
2643 return err;
2644 }
2645
2646
2647 mDNSlocal void
2648 FreeTCPContext
2649 (
2650 TCPContext * context
2651 )
2652 {
2653 if ( context )
2654 {
2655 if ( context->sock )
2656 {
2657 mDNSPlatformTCPCloseConnection( context->sock );
2658 }
2659
2660 free( context );
2661 }
2662 }
2663
2664
2665 mDNSlocal void*
2666 TCPMessageHandler
2667 (
2668 void * vptr
2669 )
2670 {
2671 TCPContext * context = ( TCPContext* ) vptr;
2672 PktMsg * reply = NULL;
2673 int res;
2674 char buf[32];
2675
2676 //!!!KRS if this read blocks indefinitely, we can run out of threads
2677 // read the request
2678
2679 reply = HandleRequest( context->d, &context->pkt );
2680 require_action_quiet( reply, exit, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
2681
2682 // deliver reply to client
2683
2684 res = SendPacket( context->sock, reply );
2685 require_action( res >= 0, exit, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
2686
2687 exit:
2688
2689 FreeTCPContext( context );
2690
2691 if ( reply )
2692 {
2693 free( reply );
2694 }
2695
2696 pthread_exit(NULL);
2697 }
2698
2699
2700 mDNSlocal void
2701 RecvTCPMessage
2702 (
2703 void * param
2704 )
2705 {
2706 TCPContext * context = ( TCPContext* ) param;
2707 mDNSu16 rcode;
2708 mDNSu16 tcode;
2709 pthread_t tid;
2710 DomainAuthInfo * key;
2711 PktMsg * pkt;
2712 mDNSBool closed;
2713 mDNSBool freeContext = mDNStrue;
2714 mStatus err = mStatus_NoError;
2715
2716 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2717 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2718 // wire. We'll let it do that, and wait for the next packet which will be ours.
2719
2720 pkt = RecvPacket( context->sock, &context->pkt, &closed );
2721 if (pkt) HdrNToH(pkt);
2722 require_action( pkt || !closed, exit, err = mStatus_UnknownErr; LogMsg( "client disconnected" ) );
2723
2724 if ( pkt )
2725 {
2726 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2727 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2728 // are sent over UDP
2729
2730 RemoveSourceFromEventLoop( context->d, context->sock );
2731
2732 // Set's the DNS Zone that is associated with this message
2733
2734 SetZone( context->d, &context->pkt );
2735
2736 // IsAuthorized will make sure the message is authorized for the designated zone.
2737 // After verifying the signature, it will strip the TSIG from the message
2738
2739 if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
2740 {
2741 if ( IsLLQRequest( &context->pkt ) )
2742 {
2743 // LLQ messages handled by main thread
2744 RecvLLQ( context->d, &context->pkt, context->sock);
2745 }
2746 else
2747 {
2748 err = pthread_create( &tid, NULL, TCPMessageHandler, context );
2749
2750 if ( err )
2751 {
2752 LogErr( "RecvTCPMessage", "pthread_create" );
2753 err = mStatus_NoError;
2754 goto exit;
2755 }
2756
2757 // Let the thread free the context
2758
2759 freeContext = mDNSfalse;
2760
2761 pthread_detach(tid);
2762 }
2763 }
2764 else
2765 {
2766 PktMsg reply;
2767
2768 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context->pkt.src.sin_addr ), pkt->zone->name.c );
2769
2770 memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
2771
2772 reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
2773 reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_Refused;
2774
2775 SendPacket( context->sock, &reply );
2776 }
2777 }
2778 else
2779 {
2780 freeContext = mDNSfalse;
2781 }
2782
2783 exit:
2784
2785 if ( err )
2786 {
2787 RemoveSourceFromEventLoop( context->d, context->sock );
2788 }
2789
2790 if ( freeContext )
2791 {
2792 FreeTCPContext( context );
2793 }
2794 }
2795
2796
2797 mDNSlocal int
2798 AcceptTCPConnection
2799 (
2800 DaemonInfo * self,
2801 int sd,
2802 TCPSocketFlags flags
2803 )
2804 {
2805 TCPContext * context = NULL;
2806 unsigned int clilen = sizeof( context->cliaddr);
2807 int newSock;
2808 mStatus err = mStatus_NoError;
2809
2810 context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
2811 require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
2812 mDNSPlatformMemZero( context, sizeof( sizeof( TCPContext ) ) );
2813 context->d = self;
2814 newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen );
2815 require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) );
2816
2817 context->sock = mDNSPlatformTCPAccept( flags, newSock );
2818 require_action( context->sock, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2819
2820 err = AddSourceToEventLoop( self, context->sock, RecvTCPMessage, context );
2821 require_action( !err, exit, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2822
2823 exit:
2824
2825 if ( err && context )
2826 {
2827 free( context );
2828 context = NULL;
2829 }
2830
2831 return err;
2832 }
2833
2834
2835 // main event loop
2836 // listen for incoming requests, periodically check table for expired records, respond to signals
2837 mDNSlocal int Run(DaemonInfo *d)
2838 {
2839 int staticMaxFD, nfds;
2840 fd_set rset;
2841 struct timeval timenow, timeout, EventTS, tablecheck = { 0, 0 };
2842 mDNSBool EventsPending = mDNSfalse;
2843
2844 VLog("Listening for requests...");
2845
2846 staticMaxFD = 0;
2847
2848 if ( d->tcpsd + 1 > staticMaxFD ) staticMaxFD = d->tcpsd + 1;
2849 if ( d->udpsd + 1 > staticMaxFD ) staticMaxFD = d->udpsd + 1;
2850 if ( d->tlssd + 1 > staticMaxFD ) staticMaxFD = d->tlssd + 1;
2851 if ( d->llq_tcpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_tcpsd + 1;
2852 if ( d->llq_udpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_udpsd + 1;
2853 if ( d->LLQEventListenSock + 1 > staticMaxFD ) staticMaxFD = d->LLQEventListenSock + 1;
2854
2855 while(1)
2856 {
2857 EventSource * source;
2858 int maxFD;
2859
2860 // set timeout
2861 timeout.tv_sec = timeout.tv_usec = 0;
2862 if (gettimeofday(&timenow, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
2863
2864 if (EventsPending)
2865 {
2866 if (timenow.tv_sec - EventTS.tv_sec >= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2867 { GenLLQEvents(d); EventsPending = mDNSfalse; } // events, we go ahead and do it now
2868 else timeout.tv_usec = 500000; // else do events after 1/2 second with no new events or LLQs
2869 }
2870 if (!EventsPending)
2871 {
2872 // if no pending events, timeout when we need to check for expired records
2873 if (tablecheck.tv_sec && timenow.tv_sec - tablecheck.tv_sec >= 0)
2874 { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; } // table check overdue
2875 if (!tablecheck.tv_sec) tablecheck.tv_sec = timenow.tv_sec + EXPIRATION_INTERVAL;
2876 timeout.tv_sec = tablecheck.tv_sec - timenow.tv_sec;
2877 }
2878
2879 FD_ZERO(&rset);
2880 FD_SET( d->tcpsd, &rset );
2881 FD_SET( d->udpsd, &rset );
2882 FD_SET( d->tlssd, &rset );
2883 FD_SET( d->llq_tcpsd, &rset );
2884 FD_SET( d->llq_udpsd, &rset );
2885 FD_SET( d->LLQEventListenSock, &rset );
2886
2887 maxFD = staticMaxFD;
2888
2889 for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
2890 {
2891 FD_SET( source->fd, &rset );
2892
2893 if ( source->fd > maxFD )
2894 {
2895 maxFD = source->fd;
2896 }
2897 }
2898
2899 nfds = select( maxFD + 1, &rset, NULL, NULL, &timeout);
2900 if (nfds < 0)
2901 {
2902 if (errno == EINTR)
2903 {
2904 if (terminate)
2905 {
2906 // close sockets to prevent clients from making new requests during shutdown
2907 close( d->tcpsd );
2908 close( d->udpsd );
2909 close( d->tlssd );
2910 close( d->llq_tcpsd );
2911 close( d->llq_udpsd );
2912 d->tcpsd = d->udpsd = d->tlssd = d->llq_tcpsd = d->llq_udpsd = -1;
2913 DeleteRecords(d, mDNStrue);
2914 return 0;
2915 }
2916 else if (dumptable)
2917 {
2918 Log( "Received SIGINFO" );
2919
2920 PrintLeaseTable(d);
2921 PrintLLQTable(d);
2922 PrintLLQAnswers(d);
2923 dumptable = 0;
2924 }
2925 else if (hangup)
2926 {
2927 int err;
2928
2929 Log( "Received SIGHUP" );
2930
2931 err = ParseConfig( d, cfgfile );
2932
2933 if ( err )
2934 {
2935 LogErr( "Run", "ParseConfig" );
2936 return -1;
2937 }
2938
2939 hangup = 0;
2940 }
2941 else
2942 {
2943 Log("Received unhandled signal - continuing");
2944 }
2945 }
2946 else
2947 {
2948 LogErr("Run", "select"); return -1;
2949 }
2950 }
2951 else if (nfds)
2952 {
2953 if (FD_ISSET(d->udpsd, &rset)) RecvUDPMessage( d, d->udpsd );
2954 if (FD_ISSET(d->llq_udpsd, &rset)) RecvUDPMessage( d, d->llq_udpsd );
2955 if (FD_ISSET(d->tcpsd, &rset)) AcceptTCPConnection( d, d->tcpsd, 0 );
2956 if (FD_ISSET(d->llq_tcpsd, &rset)) AcceptTCPConnection( d, d->llq_tcpsd, 0 );
2957 if (FD_ISSET(d->tlssd, &rset)) AcceptTCPConnection( d, d->tlssd, TCP_SOCKET_FLAGS );
2958 if (FD_ISSET(d->LLQEventListenSock, &rset))
2959 {
2960 // clear signalling data off socket
2961 char buf[256];
2962 recv(d->LLQEventListenSock, buf, 256, 0);
2963 if (!EventsPending)
2964 {
2965 EventsPending = mDNStrue;
2966 if (gettimeofday(&EventTS, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
2967 }
2968 }
2969
2970 for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
2971 {
2972 if ( FD_ISSET( source->fd, &rset ) )
2973 {
2974 source->callback( source->context );
2975 break; // in case we removed this guy from the event loop
2976 }
2977 }
2978 }
2979 else
2980 {
2981 // timeout
2982 if (EventsPending) { GenLLQEvents(d); EventsPending = mDNSfalse; }
2983 else { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; }
2984 }
2985 }
2986 return 0;
2987 }
2988
2989 // signal handler sets global variables, which are inspected by main event loop
2990 // (select automatically returns due to the handled signal)
2991 mDNSlocal void HndlSignal(int sig)
2992 {
2993 if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
2994 if (sig == INFO_SIGNAL) { dumptable = 1; return; }
2995 if (sig == SIGHUP) { hangup = 1; return; }
2996 }
2997
2998 mDNSlocal mStatus
2999 SetPublicSRV
3000 (
3001 DaemonInfo * d,
3002 const char * name
3003 )
3004 {
3005 DNameListElem * elem;
3006 mStatus err = mStatus_NoError;
3007
3008 elem = ( DNameListElem* ) malloc( sizeof( DNameListElem ) );
3009 require_action( elem, exit, err = mStatus_NoMemoryErr );
3010 MakeDomainNameFromDNSNameString( &elem->name, name );
3011 elem->next = d->public_names;
3012 d->public_names = elem;
3013
3014 exit:
3015
3016 return err;
3017 }
3018
3019
3020 int main(int argc, char *argv[])
3021 {
3022 int started_via_launchd = 0;
3023 DaemonInfo *d;
3024 struct rlimit rlim;
3025
3026 Log("dnsextd starting");
3027
3028 d = malloc(sizeof(*d));
3029 if (!d) { LogErr("main", "malloc"); exit(1); }
3030 mDNSPlatformMemZero(d, sizeof(DaemonInfo));
3031
3032 // Setup the public SRV record names
3033
3034 SetPublicSRV(d, "_dns-update._udp.");
3035 SetPublicSRV(d, "_dns-llq._udp.");
3036 SetPublicSRV(d, "_dns-update-tls._tcp.");
3037 SetPublicSRV(d, "_dns-query-tls._tcp.");
3038 SetPublicSRV(d, "_dns-llq-tls._tcp.");
3039
3040 // Setup signal handling
3041
3042 if (signal(SIGHUP, HndlSignal) == SIG_ERR) perror("Can't catch SIGHUP");
3043 if (signal(SIGTERM, HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
3044 if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
3045 if (signal(SIGINT, HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
3046 if (signal(SIGPIPE, SIG_IGN ) == SIG_ERR) perror("Can't ignore SIGPIPE");
3047
3048 // remove open file limit
3049 rlim.rlim_max = RLIM_INFINITY;
3050 rlim.rlim_cur = RLIM_INFINITY;
3051 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
3052 {
3053 LogErr("main", "setrlimit");
3054 Log("Using default file descriptor resource limit");
3055 }
3056
3057 if (argc > 1 && !strcasecmp(argv[1], "-launchd"))
3058 {
3059 Log("started_via_launchd");
3060 started_via_launchd = 1;
3061 argv++;
3062 argc--;
3063 }
3064 if (ProcessArgs(argc, argv, d) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3065
3066 if (!foreground && !started_via_launchd)
3067 {
3068 if (daemon(0,0))
3069 {
3070 LogErr("main", "daemon");
3071 foreground = 1;
3072 }
3073 }
3074
3075 if (InitLeaseTable(d) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3076 if (SetupSockets(d) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3077 if (SetUpdateSRV(d) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3078
3079 Run(d);
3080
3081 Log("dnsextd stopping");
3082
3083 if (ClearUpdateSRV(d) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3084 free(d);
3085 exit(0);
3086 }
3087
3088
3089 // These are stubbed out implementations of up-call routines that the various platform support layers
3090 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3091 // link this code in.
3092 //
3093 // It's an error for these routines to actually be called, so perhaps we should log any call
3094 // to them.
3095 void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
3096 void mDNS_ConfigChanged(mDNS *const m) { ( void ) m; }
3097 void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
3098 void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
3099 const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
3100 const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
3101 { ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
3102 DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const int serviceID, const mDNSAddr *addr, const mDNSIPPort port,
3103 mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46, mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
3104 { ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; (void) cellIntf; (void) isExpensive; (void) isCLAT46;
3105 (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
3106 void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
3107 void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
3108 { ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
3109 mDNSs32 mDNS_Execute (mDNS *const m) { ( void ) m; return 0; }
3110 mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
3111 mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3112 void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
3113 { ( void ) m; ( void ) set; ( void ) activationSpeed; }
3114 const char * const mDNS_DomainTypeNames[1] = {};
3115 mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
3116 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
3117 { ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
3118 mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3119 mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
3120 { ( void ) m; ( void ) set; ( void ) activationSpeed; return 0; }
3121 void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
3122 void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
3123 void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
3124 { ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
3125 mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
3126 mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
3127 const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
3128 { ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; ( void ) autoTunnel; return 0; }
3129 mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
3130 void TriggerEventCompletion(void);
3131 void TriggerEventCompletion() {}
3132 int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
3133 int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) { ( void ) rr; ( void ) q; return 1;}
3134 mDNS mDNSStorage;
3135
3136
3137 // For convenience when using the "strings" command, this is the last thing in the file
3138 // The "@(#) " pattern is a special prefix the "what" command looks for
3139 const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
3140
3141 #if _BUILDING_XCODE_PROJECT_
3142 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3143 const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
3144 asm (".desc ___crashreporter_info__, 0x10");
3145 #endif