]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnsextd.c
mDNSResponder-765.20.4.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( NULL, 0, &port, mDNSfalse );
306 if ( !sock ) { LogErr("ConnectToServer", "socket"); return NULL; }
307 fd = mDNSPlatformTCPGetFD( sock );
308 if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
309 mDNSPlatformTCPCloseConnection( sock );
310 if (++ntries < 10)
311 {
312 LogErr("ConnectToServer", "connect");
313 Log("ConnectToServer - retrying connection");
314 if (!retry) retry = 500000 + random() % 500000;
315 usleep(retry);
316 retry *= 2;
317 }
318 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries); return NULL; }
319 }
320 }
321
322 // send an entire block of data over a connected socket
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 mDNSs32 lease = 0;
1510 if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) == kDNSFlag0_OP_Update)
1511 {
1512 int i, adds = 0, dels = 0;
1513 const mDNSu8 *ptr, *end = (mDNSu8 *)&request->msg + request->len;
1514 HdrNToH(request);
1515 lease = GetPktLease(&mDNSStorage, &request->msg, end);
1516 ptr = LocateAuthorities(&request->msg, end);
1517 for (i = 0; i < request->msg.h.mDNS_numUpdates; i++)
1518 {
1519 LargeCacheRecord lcr;
1520 ptr = GetLargeResourceRecord(NULL, &request->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1521 if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rroriginalttl) adds++;else dels++;
1522 }
1523 HdrHToN(request);
1524 if (adds && !lease)
1525 {
1526 static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } };
1527 Log("Rejecting Update Request with %d additions but no lease", adds);
1528 reply = malloc(sizeof(*reply));
1529 mDNSPlatformMemZero(&reply->src, sizeof(reply->src));
1530 reply->len = sizeof(DNSMessageHeader);
1531 reply->zone = NULL;
1532 reply->isZonePublic = 0;
1533 InitializeDNSMessage(&reply->msg.h, request->msg.h.id, UpdateRefused);
1534 return(reply);
1535 }
1536 if (lease > 7200) // Don't allow lease greater than two hours; typically 90-minute renewal period
1537 lease = 7200;
1538 }
1539 // Send msg to server, read reply
1540
1541 if ( request->len <= 512 )
1542 {
1543 mDNSBool trunc;
1544
1545 if ( UDPServerTransaction( self, request, &buf, &trunc) < 0 )
1546 {
1547 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1548 }
1549 else if ( trunc )
1550 {
1551 VLog("HandleRequest - answer truncated. Using TCP");
1552 }
1553 else
1554 {
1555 reply = &buf; // success
1556 }
1557 }
1558
1559 if ( !reply )
1560 {
1561 mDNSBool closed;
1562 int res;
1563
1564 sock = ConnectToServer( self );
1565 require_action_quiet( sock, exit, err = mStatus_UnknownErr ; Log( "Discarding request from %s due to connection errors", inet_ntop( AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
1566
1567 res = SendPacket( sock, request );
1568 require_action_quiet( res >= 0, exit, err = mStatus_UnknownErr ; Log( "Couldn't relay message from %s to server. Discarding.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
1569
1570 reply = RecvPacket( sock, &buf, &closed );
1571 }
1572
1573 // IMPORTANT: reply is in network byte order at this point in the code
1574 // We keep it this way because we send it back to the client in the same form
1575
1576 // Is it an update?
1577
1578 if ( reply && ( ( reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( kDNSFlag0_OP_Update | kDNSFlag0_QR_Response ) ) )
1579 {
1580 char pingmsg[4];
1581 mDNSBool ok = SuccessfulUpdateTransaction( request, reply );
1582 require_action( ok, exit, err = mStatus_UnknownErr; VLog( "Message from %s not a successful update.", inet_ntop(AF_INET, &request->src.sin_addr, addrbuf, 32 ) ) );
1583
1584 UpdateLeaseTable( request, self, lease );
1585
1586 if ( lease > 0 )
1587 {
1588 leaseReply = FormatLeaseReply( self, reply, lease );
1589
1590 if ( !leaseReply )
1591 {
1592 Log("HandleRequest - unable to format lease reply");
1593 }
1594
1595 // %%% Looks like a potential memory leak -- who frees the original reply?
1596 reply = leaseReply;
1597 }
1598
1599 // tell the main thread there was an update so it can send LLQs
1600
1601 if ( send( self->LLQEventNotifySock, pingmsg, sizeof( pingmsg ), 0 ) != sizeof( pingmsg ) )
1602 {
1603 LogErr("HandleRequest", "send");
1604 }
1605 }
1606
1607 exit:
1608
1609 if ( sock )
1610 {
1611 mDNSPlatformTCPCloseConnection( sock );
1612 }
1613
1614 if ( reply == &buf )
1615 {
1616 reply = malloc( sizeof( *reply ) );
1617
1618 if ( reply )
1619 {
1620 reply->len = buf.len;
1621 memcpy(&reply->msg, &buf.msg, buf.len);
1622 }
1623 else
1624 {
1625 LogErr("HandleRequest", "malloc");
1626 }
1627 }
1628
1629 return reply;
1630 }
1631
1632
1633 //
1634 // LLQ Support Routines
1635 //
1636
1637 // Set fields of an LLQ OPT Resource Record
1638 mDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, const mDNSOpaque64 *const id, mDNSs32 lease)
1639 {
1640 mDNSPlatformMemZero(opt, sizeof(*opt));
1641 mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
1642 opt->resrec.rrclass = NormalMaxDNSMessageData;
1643 opt->resrec.rdlength = sizeof(rdataOPT); // One option in this OPT record
1644 opt->resrec.rdestimate = sizeof(rdataOPT);
1645 opt->resrec.rdata->u.opt[0].opt = kDNSOpt_LLQ;
1646 opt->resrec.rdata->u.opt[0].u.llq.vers = kLLQ_Vers;
1647 opt->resrec.rdata->u.opt[0].u.llq.llqOp = opcode;
1648 opt->resrec.rdata->u.opt[0].u.llq.err = LLQErr_NoError;
1649 opt->resrec.rdata->u.opt[0].u.llq.id = *id;
1650 opt->resrec.rdata->u.opt[0].u.llq.llqlease = lease;
1651 }
1652
1653 // Calculate effective remaining lease of an LLQ
1654 mDNSlocal mDNSu32 LLQLease(LLQEntry *e)
1655 {
1656 struct timeval t;
1657
1658 gettimeofday(&t, NULL);
1659 if (e->expire < t.tv_sec) return 0;
1660 else return e->expire - t.tv_sec;
1661 }
1662
1663 mDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
1664 {
1665 int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
1666 LLQEntry **ptr = &d->LLQTable[bucket];
1667 AnswerListElem *a = e->AnswerList;
1668 char addr[32];
1669
1670 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
1671 VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
1672
1673 if (a && !(--a->refcount) && d->AnswerTableCount >= LLQ_TABLESIZE)
1674 {
1675 // currently, generating initial answers blocks the main thread, so we keep the answer list
1676 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1677 // if the ref count drops to zero AND there are more table elements than buckets
1678 // !!!KRS update this when we make the table dynamically growable
1679
1680 CacheRecord *cr = a->KnownAnswers, *tmp;
1681 AnswerListElem **tbl = &d->AnswerTable[bucket];
1682
1683 while (cr)
1684 {
1685 tmp = cr;
1686 cr = cr->next;
1687 free(tmp);
1688 }
1689
1690 while (*tbl && *tbl != a) tbl = &(*tbl)->next;
1691 if (*tbl) { *tbl = (*tbl)->next; free(a); d->AnswerTableCount--; }
1692 else Log("Error: DeleteLLQ - AnswerList not found in table");
1693 }
1694
1695 // remove LLQ from table, free memory
1696 while(*ptr && *ptr != e) ptr = &(*ptr)->next;
1697 if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1698 *ptr = (*ptr)->next;
1699 free(e);
1700 }
1701
1702 mDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst, TCPSocket *sock)
1703 {
1704 char addr[32];
1705 int err = -1;
1706
1707 HdrHToN(pkt);
1708
1709 if ( sock )
1710 {
1711 if ( SendPacket( sock, pkt ) != 0 )
1712 {
1713 LogErr("DaemonInfo", "MySend");
1714 Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
1715 }
1716 }
1717 else
1718 {
1719 if (sendto(d->llq_udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
1720 {
1721 LogErr("DaemonInfo", "sendto");
1722 Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
1723 }
1724 }
1725
1726 err = 0;
1727 HdrNToH(pkt);
1728 return err;
1729 }
1730
1731 mDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e)
1732 {
1733 PktMsg q;
1734 int i;
1735 TCPSocket *sock = NULL;
1736 const mDNSu8 *ansptr;
1737 mDNSu8 *end = q.msg.data;
1738 PktMsg buf, *reply = NULL;
1739 LargeCacheRecord lcr;
1740 CacheRecord *AnswerList = NULL;
1741 mDNSu8 rcode;
1742
1743 VLog("Querying server for %##s type %d", e->name.c, e->type);
1744
1745 InitializeDNSMessage(&q.msg.h, zeroID, uQueryFlags);
1746
1747 end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
1748 if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
1749 q.len = (int)(end - (mDNSu8 *)&q.msg);
1750
1751 HdrHToN(&q);
1752
1753 if (!e->UseTCP)
1754 {
1755 mDNSBool trunc;
1756
1757 if (UDPServerTransaction(d, &q, &buf, &trunc) < 0)
1758 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e->name.c);
1759 else if (trunc)
1760 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e->name.c); e->UseTCP = mDNStrue; }
1761 else reply = &buf; // success
1762 }
1763
1764 if (!reply)
1765 {
1766 mDNSBool closed;
1767
1768 sock = ConnectToServer(d);
1769 if (!sock) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
1770 if (SendPacket( sock, &q)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock ); goto end; }
1771 reply = RecvPacket( sock, NULL, &closed );
1772 mDNSPlatformTCPCloseConnection( sock );
1773 require_action( reply, end, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1774 }
1775
1776 HdrNToH(&q);
1777 if (reply) HdrNToH(reply);
1778
1779 if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
1780 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
1781 rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
1782 if (rcode && rcode != kDNSFlag1_RC_NXDomain) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e->name.c, e->type, rcode); goto end; }
1783
1784 end = (mDNSu8 *)&reply->msg + reply->len;
1785 ansptr = LocateAnswers(&reply->msg, end);
1786 if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
1787
1788 for (i = 0; i < reply->msg.h.numAnswers; i++)
1789 {
1790 ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1791 if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
1792 if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative)
1793 {
1794 if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
1795 {
1796 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1797 lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
1798 }
1799 else
1800 {
1801 CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
1802 if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
1803 cr->next = AnswerList;
1804 AnswerList = cr;
1805 }
1806 }
1807 }
1808
1809 end:
1810 if (reply && reply != &buf) free(reply);
1811 return AnswerList;
1812 }
1813
1814 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1815 mDNSlocal void *UpdateAnswerList(void *args)
1816 {
1817 CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
1818 DaemonInfo *d = ((UpdateAnswerListArgs *)args)->d;
1819 AnswerListElem *a = ((UpdateAnswerListArgs *)args)->a;
1820
1821 free(args);
1822 args = NULL;
1823
1824 // get up to date answers
1825 NewAnswers = AnswerQuestion(d, a);
1826
1827 // first pass - mark all answers for deletion
1828 for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
1829 (*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
1830
1831 // second pass - mark answers pre-existent
1832 for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
1833 {
1834 for (na = &NewAnswers; *na; na = &(*na)->next)
1835 {
1836 if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec))
1837 { (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
1838 }
1839 }
1840
1841 // third pass - add new records to Event list
1842 na = &NewAnswers;
1843 while (*na)
1844 {
1845 for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
1846 if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
1847 if (!*ka)
1848 {
1849 // answer is not in list - splice from NewAnswers list, add to Event list
1850 cr = *na;
1851 *na = (*na)->next; // splice from list
1852 cr->next = a->EventList; // add spliced record to event list
1853 a->EventList = cr;
1854 cr->resrec.rroriginalttl = 1; // 1 means add
1855 }
1856 else na = &(*na)->next;
1857 }
1858
1859 // move all the removes from the answer list to the event list
1860 ka = &a->KnownAnswers;
1861 while (*ka)
1862 {
1863 if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
1864 {
1865 cr = *ka;
1866 *ka = (*ka)->next;
1867 cr->next = a->EventList;
1868 a->EventList = cr;
1869 }
1870 else ka = &(*ka)->next;
1871 }
1872
1873 // lastly, free the remaining records (known answers) in NewAnswers list
1874 while (NewAnswers)
1875 {
1876 cr = NewAnswers;
1877 NewAnswers = NewAnswers->next;
1878 free(cr);
1879 }
1880
1881 return NULL;
1882 }
1883
1884 mDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
1885 {
1886 PktMsg response;
1887 CacheRecord *cr;
1888 mDNSu8 *end = (mDNSu8 *)&response.msg.data;
1889 mDNSOpaque16 msgID;
1890 char rrbuf[MaxMsg], addrbuf[32];
1891 AuthRecord opt;
1892
1893 // Should this really be random? Do we use the msgID on the receiving end?
1894 msgID.NotAnInteger = random();
1895 if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
1896 InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
1897 end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
1898 if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
1899
1900 // put adds/removes in packet
1901 for (cr = e->AnswerList->EventList; cr; cr = cr->next)
1902 {
1903 if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
1904 VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove" : "Add", rrbuf);
1905 end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
1906 if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
1907 }
1908
1909 FormatLLQOpt(&opt, kLLQOp_Event, &e->id, LLQLease(e));
1910 end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
1911 if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
1912
1913 response.len = (int)(end - (mDNSu8 *)&response.msg);
1914 if (SendLLQ(d, &response, e->cli, NULL ) < 0) LogMsg("Error: SendEvents - SendLLQ");
1915 }
1916
1917 mDNSlocal void PrintLLQAnswers(DaemonInfo *d)
1918 {
1919 int i;
1920 char rrbuf[MaxMsg];
1921
1922 Log("Printing LLQ Answer Table contents");
1923
1924 for (i = 0; i < LLQ_TABLESIZE; i++)
1925 {
1926 AnswerListElem *a = d->AnswerTable[i];
1927 while(a)
1928 {
1929 int ancount = 0;
1930 const CacheRecord *rr = a->KnownAnswers;
1931 while (rr) { ancount++; rr = rr->next; }
1932 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a, a->name.c, a->type, a->refcount, ancount);
1933 for (rr = a->KnownAnswers; rr; rr = rr->next) Log("\t%s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, rrbuf));
1934 a = a->next;
1935 }
1936 }
1937 }
1938
1939 mDNSlocal void PrintLLQTable(DaemonInfo *d)
1940 {
1941 LLQEntry *e;
1942 char addr[32];
1943 int i;
1944
1945 Log("Printing LLQ table contents");
1946
1947 for (i = 0; i < LLQ_TABLESIZE; i++)
1948 {
1949 e = d->LLQTable[i];
1950 while(e)
1951 {
1952 char *state;
1953
1954 switch (e->state)
1955 {
1956 case RequestReceived: state = "RequestReceived"; break;
1957 case ChallengeSent: state = "ChallengeSent"; break;
1958 case Established: state = "Established"; break;
1959 default: state = "unknown";
1960 }
1961 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
1962
1963 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
1964 addr, state, e->qname.c, e->qtype, e->lease, LLQLease(e), e->AnswerList);
1965 e = e->next;
1966 }
1967 }
1968 }
1969
1970 // Send events to clients as a result of a change in the zone
1971 mDNSlocal void GenLLQEvents(DaemonInfo *d)
1972 {
1973 LLQEntry **e;
1974 int i;
1975 struct timeval t;
1976 UpdateAnswerListArgs *args;
1977
1978 VLog("Generating LLQ Events");
1979
1980 gettimeofday(&t, NULL);
1981
1982 // get all answers up to date
1983 for (i = 0; i < LLQ_TABLESIZE; i++)
1984 {
1985 AnswerListElem *a = d->AnswerTable[i];
1986 while(a)
1987 {
1988 args = malloc(sizeof(*args));
1989 if (!args) { LogErr("GenLLQEvents", "malloc"); return; }
1990 args->d = d;
1991 args->a = a;
1992 if (pthread_create(&a->tid, NULL, UpdateAnswerList, args) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
1993 usleep(1);
1994 a = a->next;
1995 }
1996 }
1997
1998 for (i = 0; i < LLQ_TABLESIZE; i++)
1999 {
2000 AnswerListElem *a = d->AnswerTable[i];
2001 while(a)
2002 {
2003 if (pthread_join(a->tid, NULL)) LogErr("GenLLQEvents", "pthread_join");
2004 a = a->next;
2005 }
2006 }
2007
2008 // for each established LLQ, send events
2009 for (i = 0; i < LLQ_TABLESIZE; i++)
2010 {
2011 e = &d->LLQTable[i];
2012 while(*e)
2013 {
2014 if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
2015 else
2016 {
2017 if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
2018 e = &(*e)->next;
2019 }
2020 }
2021 }
2022
2023 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2024 for (i = 0; i < LLQ_TABLESIZE; i++)
2025 {
2026 AnswerListElem *a = d->AnswerTable[i];
2027 while(a)
2028 {
2029 if (a->EventList)
2030 {
2031 CacheRecord *cr = a->EventList, *tmp;
2032 while (cr)
2033 {
2034 tmp = cr;
2035 cr = cr->next;
2036 if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
2037 else
2038 {
2039 tmp->next = a->KnownAnswers;
2040 a->KnownAnswers = tmp;
2041 tmp->resrec.rroriginalttl = 0;
2042 }
2043 }
2044 a->EventList = NULL;
2045 }
2046 a = a->next;
2047 }
2048 }
2049 }
2050
2051 mDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
2052 {
2053 int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
2054 AnswerListElem *a = d->AnswerTable[bucket];
2055 while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
2056 if (!a)
2057 {
2058 a = malloc(sizeof(*a));
2059 if (!a) { LogErr("SetAnswerList", "malloc"); return; }
2060 AssignDomainName(&a->name, &e->qname);
2061 a->type = e->qtype;
2062 a->refcount = 0;
2063 a->EventList = NULL;
2064 a->UseTCP = mDNSfalse;
2065 a->next = d->AnswerTable[bucket];
2066 d->AnswerTable[bucket] = a;
2067 d->AnswerTableCount++;
2068 a->KnownAnswers = AnswerQuestion(d, a);
2069 }
2070
2071 e->AnswerList = a;
2072 a->refcount++;
2073 }
2074
2075 // Allocate LLQ entry, insert into table
2076 mDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease )
2077 {
2078 char addr[32];
2079 struct timeval t;
2080 int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
2081 LLQEntry *e;
2082
2083 e = malloc(sizeof(*e));
2084 if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
2085
2086 inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
2087 VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
2088
2089 // initialize structure
2090 e->cli = cli;
2091 AssignDomainName(&e->qname, qname);
2092 e->qtype = qtype;
2093 e->id = zeroOpaque64;
2094 e->state = RequestReceived;
2095 e->AnswerList = NULL;
2096
2097 if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
2098 else if (lease > LLQ_MAX_LEASE) lease = LLQ_MAX_LEASE;
2099
2100 gettimeofday(&t, NULL);
2101 e->expire = t.tv_sec + (int)lease;
2102 e->lease = lease;
2103
2104 // add to table
2105 e->next = d->LLQTable[bucket];
2106 d->LLQTable[bucket] = e;
2107
2108 return e;
2109 }
2110
2111 // Handle a refresh request from client
2112 mDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
2113 {
2114 AuthRecord opt;
2115 PktMsg ack;
2116 mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
2117 char addr[32];
2118
2119 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
2120 VLog("%s LLQ for %##s from %s", llq->llqlease ? "Refreshing" : "Deleting", e->qname.c, addr);
2121
2122 if (llq->llqlease)
2123 {
2124 struct timeval t;
2125 if (llq->llqlease < LLQ_MIN_LEASE) llq->llqlease = LLQ_MIN_LEASE;
2126 else if (llq->llqlease > LLQ_MAX_LEASE) llq->llqlease = LLQ_MIN_LEASE;
2127 gettimeofday(&t, NULL);
2128 e->expire = t.tv_sec + llq->llqlease;
2129 }
2130
2131 ack.src.sin_addr.s_addr = 0; // unused
2132 InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
2133 end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
2134 if (!end) { Log("Error: putQuestion"); return; }
2135
2136 FormatLLQOpt(&opt, kLLQOp_Refresh, &e->id, llq->llqlease ? LLQLease(e) : 0);
2137 end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
2138 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2139
2140 ack.len = (int)(end - (mDNSu8 *)&ack.msg);
2141 if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQRefresh");
2142
2143 if (llq->llqlease) e->state = Established;
2144 else DeleteLLQ(d, e);
2145 }
2146
2147 // Complete handshake with Ack an initial answers
2148 mDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock)
2149 {
2150 char addr[32];
2151 CacheRecord *ptr;
2152 AuthRecord opt;
2153 PktMsg ack;
2154 mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
2155 char rrbuf[MaxMsg], addrbuf[32];
2156
2157 inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
2158
2159 if (!mDNSSameOpaque64(&llq->id, &e->id) ||
2160 llq->vers != kLLQ_Vers ||
2161 llq->llqOp != kLLQOp_Setup ||
2162 llq->err != LLQErr_NoError ||
2163 llq->llqlease > e->lease + LLQ_LEASE_FUDGE ||
2164 llq->llqlease < e->lease - LLQ_LEASE_FUDGE)
2165 {
2166 Log("Incorrect challenge response from %s", addr);
2167 return;
2168 }
2169
2170 if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
2171 else VLog("Delivering LLQ ack + answers for %##s", e->qname.c);
2172
2173 // format ack + answers
2174 ack.src.sin_addr.s_addr = 0; // unused
2175 InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
2176 end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
2177 if (!end) { Log("Error: putQuestion"); return; }
2178
2179 if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
2180
2181 if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
2182 for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
2183 {
2184 if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
2185 VLog("%s Intitial Answer - %s", addr, rrbuf);
2186 end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
2187 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2188 }
2189
2190 FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
2191 end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
2192 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2193
2194 ack.len = (int)(end - (mDNSu8 *)&ack.msg);
2195 if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQCompleteHandshake");
2196 }
2197
2198 mDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
2199 {
2200 struct timeval t;
2201 PktMsg challenge;
2202 mDNSu8 *end = challenge.msg.data;
2203 AuthRecord opt;
2204
2205 if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
2206 else VLog("Sending LLQ setup challenge for %##s", e->qname.c);
2207
2208 if (!mDNSOpaque64IsZero(&llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2209 if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2210
2211 if (mDNSOpaque64IsZero(&e->id)) // don't regenerate random ID for retransmissions
2212 {
2213 // construct ID <time><random>
2214 gettimeofday(&t, NULL);
2215 e->id.l[0] = t.tv_sec;
2216 e->id.l[1] = random();
2217 }
2218
2219 // format response (query + LLQ opt rr)
2220 challenge.src.sin_addr.s_addr = 0; // unused
2221 InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
2222 end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
2223 if (!end) { Log("Error: putQuestion"); return; }
2224 FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
2225 end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
2226 if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2227 challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
2228 if (SendLLQ(d, &challenge, e->cli, NULL)) { Log("Error: LLQSetupChallenge"); return; }
2229 e->state = ChallengeSent;
2230 }
2231
2232 // Take action on an LLQ message from client. Entry must be initialized and in table
2233 mDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
2234 {
2235 switch(e->state)
2236 {
2237 case RequestReceived:
2238 if ( sock )
2239 {
2240 struct timeval t;
2241 gettimeofday(&t, NULL);
2242 e->id.l[0] = t.tv_sec; // construct ID <time><random>
2243 e->id.l[1] = random();
2244 llq->id = e->id;
2245 LLQCompleteHandshake( d, e, llq, msgID, sock );
2246
2247 // Set the state to established because we've just set the LLQ up using TCP
2248 e->state = Established;
2249 }
2250 else
2251 {
2252 LLQSetupChallenge(d, e, llq, msgID);
2253 }
2254 return;
2255 case ChallengeSent:
2256 if (mDNSOpaque64IsZero(&llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
2257 else LLQCompleteHandshake(d, e, llq, msgID, sock );
2258 return;
2259 case Established:
2260 if (mDNSOpaque64IsZero(&llq->id))
2261 {
2262 // client started over. reset state.
2263 LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->llqlease );
2264 if (!newe) return;
2265 DeleteLLQ(d, e);
2266 LLQSetupChallenge(d, newe, llq, msgID);
2267 return;
2268 }
2269 else if (llq->llqOp == kLLQOp_Setup)
2270 { LLQCompleteHandshake(d, e, llq, msgID, sock); return; } // Ack lost
2271 else if (llq->llqOp == kLLQOp_Refresh)
2272 { LLQRefresh(d, e, llq, msgID, sock); return; }
2273 else { Log("Unhandled message for established LLQ"); return; }
2274 }
2275 }
2276
2277 mDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, const mDNSOpaque64 *const id)
2278 {
2279 int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
2280 LLQEntry *ptr = d->LLQTable[bucket];
2281
2282 while(ptr)
2283 {
2284 if (((ptr->state == ChallengeSent && mDNSOpaque64IsZero(id) && (cli.sin_port == ptr->cli.sin_port)) || // zero-id due to packet loss OK in state ChallengeSent
2285 mDNSSameOpaque64(id, &ptr->id)) && // id match
2286 (cli.sin_addr.s_addr == ptr->cli.sin_addr.s_addr) && (qtype == ptr->qtype) && SameDomainName(&ptr->qname, qname)) // same source, type, qname
2287 return ptr;
2288 ptr = ptr->next;
2289 }
2290 return NULL;
2291 }
2292
2293 mDNSlocal int
2294 RecvNotify
2295 (
2296 DaemonInfo * d,
2297 PktMsg * pkt
2298 )
2299 {
2300 int res;
2301 int err = 0;
2302
2303 pkt->msg.h.flags.b[0] |= kDNSFlag0_QR_Response;
2304
2305 res = sendto( d->udpsd, &pkt->msg, pkt->len, 0, ( struct sockaddr* ) &pkt->src, sizeof( pkt->src ) );
2306 require_action( res == ( int ) pkt->len, exit, err = mStatus_UnknownErr; LogErr( "RecvNotify", "sendto" ) );
2307
2308 exit:
2309
2310 return err;
2311 }
2312
2313
2314 mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
2315 {
2316 DNSQuestion q;
2317 LargeCacheRecord opt;
2318 int i, err = -1;
2319 char addr[32];
2320 const mDNSu8 *qptr = pkt->msg.data;
2321 const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
2322 const mDNSu8 *aptr;
2323 LLQOptData *llq = NULL;
2324 LLQEntry *e = NULL;
2325
2326 HdrNToH(pkt);
2327 aptr = LocateAdditionals(&pkt->msg, end); // Can't do this until after HdrNToH(pkt);
2328 inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
2329
2330 VLog("Received LLQ msg from %s", addr);
2331 // sanity-check packet
2332 if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
2333 {
2334 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
2335 goto end;
2336 }
2337
2338 // Locate the OPT record.
2339 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2340 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2341 // but not necessarily the *last* entry in the Additional Section.
2342 for (i = 0; i < pkt->msg.h.numAdditionals; i++)
2343 {
2344 aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
2345 if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
2346 if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
2347 }
2348
2349 // validate OPT
2350 if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; }
2351 if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * DNSOpt_LLQData_Space) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
2352
2353 // dispatch each question
2354 for (i = 0; i < pkt->msg.h.numQuestions; i++)
2355 {
2356 qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
2357 if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
2358 llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt[0].u.llq + i; // point into OptData at index i
2359 if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
2360
2361 e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id);
2362 if (!e)
2363 {
2364 // no entry - if zero ID, create new
2365 e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->llqlease );
2366 if (!e) goto end;
2367 }
2368 UpdateLLQ(d, e, llq, pkt->msg.h.id, sock);
2369 }
2370 err = 0;
2371
2372 end:
2373 HdrHToN(pkt);
2374 return err;
2375 }
2376
2377
2378 mDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo ** key, mDNSu16 * rcode, mDNSu16 * tcode )
2379 {
2380 const mDNSu8 * lastPtr = NULL;
2381 const mDNSu8 * ptr = NULL;
2382 DomainAuthInfo * keys;
2383 mDNSu8 * end = ( mDNSu8* ) &pkt->msg + pkt->len;
2384 LargeCacheRecord lcr;
2385 mDNSBool hasTSIG = mDNSfalse;
2386 mDNSBool strip = mDNSfalse;
2387 mDNSBool ok = mDNSfalse;
2388 int i;
2389
2390 // Unused parameters
2391
2392 ( void ) d;
2393
2394 HdrNToH(pkt);
2395
2396 *key = NULL;
2397 bzero(&lcr, sizeof(lcr));
2398
2399 if ( pkt->msg.h.numAdditionals )
2400 {
2401 ptr = LocateAdditionals(&pkt->msg, end);
2402 if (ptr)
2403 {
2404 for (i = 0; i < pkt->msg.h.numAdditionals; i++)
2405 {
2406 lastPtr = ptr;
2407 ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2408 if (!ptr)
2409 {
2410 Log("Unable to read additional record");
2411 lastPtr = NULL;
2412 break;
2413 }
2414 }
2415
2416 hasTSIG = ( ptr && lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rrtype == kDNSType_TSIG );
2417 }
2418 else
2419 {
2420 LogMsg( "IsAuthorized: unable to find Additional section" );
2421 }
2422 }
2423
2424 // If we don't know what zone this is, then it's authorized.
2425
2426 if ( !pkt->zone )
2427 {
2428 ok = mDNStrue;
2429 strip = mDNSfalse;
2430 goto exit;
2431 }
2432
2433 if ( IsQuery( pkt ) )
2434 {
2435 keys = pkt->zone->queryKeys;
2436 strip = mDNStrue;
2437 }
2438 else if ( IsUpdate( pkt ) )
2439 {
2440 keys = pkt->zone->updateKeys;
2441 strip = mDNSfalse;
2442 }
2443 else
2444 {
2445 ok = mDNStrue;
2446 strip = mDNSfalse;
2447 goto exit;
2448 }
2449
2450 if ( pkt->isZonePublic )
2451 {
2452 ok = mDNStrue;
2453 goto exit;
2454 }
2455
2456 // If there are no keys, then we're authorized
2457
2458 if ( ( hasTSIG && !keys ) || ( !hasTSIG && keys ) )
2459 {
2460 Log( "Invalid TSIG spec %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
2461 *rcode = kDNSFlag1_RC_NotAuth;
2462 *tcode = TSIG_ErrBadKey;
2463 strip = mDNStrue;
2464 ok = mDNSfalse;
2465 goto exit;
2466 }
2467
2468 // Find the right key
2469
2470 for ( *key = keys; *key; *key = (*key)->next )
2471 {
2472 if ( SameDomainName( lcr.r.resrec.name, &(*key)->keyname ) )
2473 {
2474 break;
2475 }
2476 }
2477
2478 if ( !(*key) )
2479 {
2480 Log( "Invalid TSIG name %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
2481 *rcode = kDNSFlag1_RC_NotAuth;
2482 *tcode = TSIG_ErrBadKey;
2483 strip = mDNStrue;
2484 ok = mDNSfalse;
2485 goto exit;
2486 }
2487
2488 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2489 // lifting of message verification
2490
2491 pkt->msg.h.numAdditionals--;
2492
2493 HdrHToN( pkt );
2494
2495 ok = DNSDigest_VerifyMessage( &pkt->msg, ( mDNSu8* ) lastPtr, &lcr, (*key), rcode, tcode );
2496
2497 HdrNToH( pkt );
2498
2499 pkt->msg.h.numAdditionals++;
2500
2501 exit:
2502
2503 if ( hasTSIG && strip )
2504 {
2505 // Strip the TSIG from the message
2506
2507 pkt->msg.h.numAdditionals--;
2508 pkt->len = lastPtr - ( mDNSu8* ) ( &pkt->msg );
2509 }
2510
2511 HdrHToN(pkt);
2512
2513 return ok;
2514 }
2515
2516 // request handler wrappers for TCP and UDP requests
2517 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2518
2519 mDNSlocal void*
2520 UDPMessageHandler
2521 (
2522 void * vptr
2523 )
2524 {
2525 UDPContext * context = ( UDPContext* ) vptr;
2526 PktMsg * reply = NULL;
2527 int res;
2528 mStatus err;
2529
2530 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2531 // may give us a long answer that would require truncation for UDP delivery to client
2532
2533 reply = HandleRequest( context->d, &context->pkt );
2534 require_action( reply, exit, err = mStatus_UnknownErr );
2535
2536 res = sendto( context->sd, &reply->msg, reply->len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
2537 require_action_quiet( res == ( int ) reply->len, exit, LogErr( "UDPMessageHandler", "sendto" ) );
2538
2539 exit:
2540
2541 if ( reply )
2542 {
2543 free( reply );
2544 }
2545
2546 free( context );
2547
2548 pthread_exit( NULL );
2549
2550 return NULL;
2551 }
2552
2553
2554 mDNSlocal int
2555 RecvUDPMessage
2556 (
2557 DaemonInfo * self,
2558 int sd
2559 )
2560 {
2561 UDPContext * context = NULL;
2562 pthread_t tid;
2563 mDNSu16 rcode;
2564 mDNSu16 tcode;
2565 DomainAuthInfo * key;
2566 unsigned int clisize = sizeof( context->cliaddr );
2567 int res;
2568 mStatus err = mStatus_NoError;
2569
2570 context = malloc( sizeof( UDPContext ) );
2571 require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
2572
2573 mDNSPlatformMemZero( context, sizeof( *context ) );
2574 context->d = self;
2575 context->sd = sd;
2576
2577 res = recvfrom(sd, &context->pkt.msg, sizeof(context->pkt.msg), 0, (struct sockaddr *)&context->cliaddr, &clisize);
2578
2579 require_action( res >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvUDPMessage", "recvfrom" ) );
2580 context->pkt.len = res;
2581 require_action( clisize == sizeof( context->cliaddr ), exit, err = mStatus_UnknownErr ; Log( "Client address of unknown size %d", clisize ) );
2582 context->pkt.src = context->cliaddr;
2583
2584 // Set the zone in the packet
2585
2586 SetZone( context->d, &context->pkt );
2587
2588 // Notify messages handled by main thread
2589
2590 if ( IsNotify( &context->pkt ) )
2591 {
2592 int e = RecvNotify( self, &context->pkt );
2593 free(context);
2594 return e;
2595 }
2596 else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
2597 {
2598 if ( IsLLQRequest( &context->pkt ) )
2599 {
2600 // LLQ messages handled by main thread
2601 int e = RecvLLQ( self, &context->pkt, NULL );
2602 free(context);
2603 return e;
2604 }
2605
2606 if ( IsLLQAck(&context->pkt ) )
2607 {
2608 // !!!KRS need to do acks + retrans
2609
2610 free(context);
2611 return 0;
2612 }
2613
2614 err = pthread_create( &tid, NULL, UDPMessageHandler, context );
2615 require_action( !err, exit, LogErr( "RecvUDPMessage", "pthread_create" ) );
2616
2617 pthread_detach(tid);
2618 }
2619 else
2620 {
2621 PktMsg reply;
2622 int e;
2623
2624 memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
2625
2626 reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
2627 reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
2628
2629 e = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
2630 require_action_quiet( e == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
2631
2632 err = mStatus_NoAuth;
2633 }
2634
2635 exit:
2636
2637 if ( err && context )
2638 {
2639 free( context );
2640 }
2641
2642 return err;
2643 }
2644
2645
2646 mDNSlocal void
2647 FreeTCPContext
2648 (
2649 TCPContext * context
2650 )
2651 {
2652 if ( context )
2653 {
2654 if ( context->sock )
2655 {
2656 mDNSPlatformTCPCloseConnection( context->sock );
2657 }
2658
2659 free( context );
2660 }
2661 }
2662
2663
2664 mDNSlocal void*
2665 TCPMessageHandler
2666 (
2667 void * vptr
2668 )
2669 {
2670 TCPContext * context = ( TCPContext* ) vptr;
2671 PktMsg * reply = NULL;
2672 int res;
2673 char buf[32];
2674
2675 //!!!KRS if this read blocks indefinitely, we can run out of threads
2676 // read the request
2677
2678 reply = HandleRequest( context->d, &context->pkt );
2679 require_action_quiet( reply, exit, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
2680
2681 // deliver reply to client
2682
2683 res = SendPacket( context->sock, reply );
2684 require_action( res >= 0, exit, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
2685
2686 exit:
2687
2688 FreeTCPContext( context );
2689
2690 if ( reply )
2691 {
2692 free( reply );
2693 }
2694
2695 pthread_exit(NULL);
2696 }
2697
2698
2699 mDNSlocal void
2700 RecvTCPMessage
2701 (
2702 void * param
2703 )
2704 {
2705 TCPContext * context = ( TCPContext* ) param;
2706 mDNSu16 rcode;
2707 mDNSu16 tcode;
2708 pthread_t tid;
2709 DomainAuthInfo * key;
2710 PktMsg * pkt;
2711 mDNSBool closed;
2712 mDNSBool freeContext = mDNStrue;
2713 mStatus err = mStatus_NoError;
2714
2715 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2716 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2717 // wire. We'll let it do that, and wait for the next packet which will be ours.
2718
2719 pkt = RecvPacket( context->sock, &context->pkt, &closed );
2720 if (pkt) HdrNToH(pkt);
2721 require_action( pkt || !closed, exit, err = mStatus_UnknownErr; LogMsg( "client disconnected" ) );
2722
2723 if ( pkt )
2724 {
2725 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2726 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2727 // are sent over UDP
2728
2729 RemoveSourceFromEventLoop( context->d, context->sock );
2730
2731 // Set's the DNS Zone that is associated with this message
2732
2733 SetZone( context->d, &context->pkt );
2734
2735 // IsAuthorized will make sure the message is authorized for the designated zone.
2736 // After verifying the signature, it will strip the TSIG from the message
2737
2738 if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
2739 {
2740 if ( IsLLQRequest( &context->pkt ) )
2741 {
2742 // LLQ messages handled by main thread
2743 RecvLLQ( context->d, &context->pkt, context->sock);
2744 }
2745 else
2746 {
2747 err = pthread_create( &tid, NULL, TCPMessageHandler, context );
2748
2749 if ( err )
2750 {
2751 LogErr( "RecvTCPMessage", "pthread_create" );
2752 err = mStatus_NoError;
2753 goto exit;
2754 }
2755
2756 // Let the thread free the context
2757
2758 freeContext = mDNSfalse;
2759
2760 pthread_detach(tid);
2761 }
2762 }
2763 else
2764 {
2765 PktMsg reply;
2766
2767 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context->pkt.src.sin_addr ), pkt->zone->name.c );
2768
2769 memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
2770
2771 reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
2772 reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_Refused;
2773
2774 SendPacket( context->sock, &reply );
2775 }
2776 }
2777 else
2778 {
2779 freeContext = mDNSfalse;
2780 }
2781
2782 exit:
2783
2784 if ( err )
2785 {
2786 RemoveSourceFromEventLoop( context->d, context->sock );
2787 }
2788
2789 if ( freeContext )
2790 {
2791 FreeTCPContext( context );
2792 }
2793 }
2794
2795
2796 mDNSlocal int
2797 AcceptTCPConnection
2798 (
2799 DaemonInfo * self,
2800 int sd,
2801 TCPSocketFlags flags
2802 )
2803 {
2804 TCPContext * context = NULL;
2805 unsigned int clilen = sizeof( context->cliaddr);
2806 int newSock;
2807 mStatus err = mStatus_NoError;
2808
2809 context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
2810 require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
2811 mDNSPlatformMemZero( context, sizeof( sizeof( TCPContext ) ) );
2812 context->d = self;
2813 newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen );
2814 require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) );
2815
2816 context->sock = mDNSPlatformTCPAccept( flags, newSock );
2817 require_action( context->sock, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2818
2819 err = AddSourceToEventLoop( self, context->sock, RecvTCPMessage, context );
2820 require_action( !err, exit, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2821
2822 exit:
2823
2824 if ( err && context )
2825 {
2826 free( context );
2827 context = NULL;
2828 }
2829
2830 return err;
2831 }
2832
2833
2834 // main event loop
2835 // listen for incoming requests, periodically check table for expired records, respond to signals
2836 mDNSlocal int Run(DaemonInfo *d)
2837 {
2838 int staticMaxFD, nfds;
2839 fd_set rset;
2840 struct timeval timenow, timeout, EventTS, tablecheck = { 0, 0 };
2841 mDNSBool EventsPending = mDNSfalse;
2842
2843 VLog("Listening for requests...");
2844
2845 staticMaxFD = 0;
2846
2847 if ( d->tcpsd + 1 > staticMaxFD ) staticMaxFD = d->tcpsd + 1;
2848 if ( d->udpsd + 1 > staticMaxFD ) staticMaxFD = d->udpsd + 1;
2849 if ( d->tlssd + 1 > staticMaxFD ) staticMaxFD = d->tlssd + 1;
2850 if ( d->llq_tcpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_tcpsd + 1;
2851 if ( d->llq_udpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_udpsd + 1;
2852 if ( d->LLQEventListenSock + 1 > staticMaxFD ) staticMaxFD = d->LLQEventListenSock + 1;
2853
2854 while(1)
2855 {
2856 EventSource * source;
2857 int maxFD;
2858
2859 // set timeout
2860 timeout.tv_sec = timeout.tv_usec = 0;
2861 if (gettimeofday(&timenow, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
2862
2863 if (EventsPending)
2864 {
2865 if (timenow.tv_sec - EventTS.tv_sec >= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2866 { GenLLQEvents(d); EventsPending = mDNSfalse; } // events, we go ahead and do it now
2867 else timeout.tv_usec = 500000; // else do events after 1/2 second with no new events or LLQs
2868 }
2869 if (!EventsPending)
2870 {
2871 // if no pending events, timeout when we need to check for expired records
2872 if (tablecheck.tv_sec && timenow.tv_sec - tablecheck.tv_sec >= 0)
2873 { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; } // table check overdue
2874 if (!tablecheck.tv_sec) tablecheck.tv_sec = timenow.tv_sec + EXPIRATION_INTERVAL;
2875 timeout.tv_sec = tablecheck.tv_sec - timenow.tv_sec;
2876 }
2877
2878 FD_ZERO(&rset);
2879 FD_SET( d->tcpsd, &rset );
2880 FD_SET( d->udpsd, &rset );
2881 FD_SET( d->tlssd, &rset );
2882 FD_SET( d->llq_tcpsd, &rset );
2883 FD_SET( d->llq_udpsd, &rset );
2884 FD_SET( d->LLQEventListenSock, &rset );
2885
2886 maxFD = staticMaxFD;
2887
2888 for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
2889 {
2890 FD_SET( source->fd, &rset );
2891
2892 if ( source->fd > maxFD )
2893 {
2894 maxFD = source->fd;
2895 }
2896 }
2897
2898 nfds = select( maxFD + 1, &rset, NULL, NULL, &timeout);
2899 if (nfds < 0)
2900 {
2901 if (errno == EINTR)
2902 {
2903 if (terminate)
2904 {
2905 // close sockets to prevent clients from making new requests during shutdown
2906 close( d->tcpsd );
2907 close( d->udpsd );
2908 close( d->tlssd );
2909 close( d->llq_tcpsd );
2910 close( d->llq_udpsd );
2911 d->tcpsd = d->udpsd = d->tlssd = d->llq_tcpsd = d->llq_udpsd = -1;
2912 DeleteRecords(d, mDNStrue);
2913 return 0;
2914 }
2915 else if (dumptable)
2916 {
2917 Log( "Received SIGINFO" );
2918
2919 PrintLeaseTable(d);
2920 PrintLLQTable(d);
2921 PrintLLQAnswers(d);
2922 dumptable = 0;
2923 }
2924 else if (hangup)
2925 {
2926 int err;
2927
2928 Log( "Received SIGHUP" );
2929
2930 err = ParseConfig( d, cfgfile );
2931
2932 if ( err )
2933 {
2934 LogErr( "Run", "ParseConfig" );
2935 return -1;
2936 }
2937
2938 hangup = 0;
2939 }
2940 else
2941 {
2942 Log("Received unhandled signal - continuing");
2943 }
2944 }
2945 else
2946 {
2947 LogErr("Run", "select"); return -1;
2948 }
2949 }
2950 else if (nfds)
2951 {
2952 if (FD_ISSET(d->udpsd, &rset)) RecvUDPMessage( d, d->udpsd );
2953 if (FD_ISSET(d->llq_udpsd, &rset)) RecvUDPMessage( d, d->llq_udpsd );
2954 if (FD_ISSET(d->tcpsd, &rset)) AcceptTCPConnection( d, d->tcpsd, 0 );
2955 if (FD_ISSET(d->llq_tcpsd, &rset)) AcceptTCPConnection( d, d->llq_tcpsd, 0 );
2956 if (FD_ISSET(d->tlssd, &rset)) AcceptTCPConnection( d, d->tlssd, TCP_SOCKET_FLAGS );
2957 if (FD_ISSET(d->LLQEventListenSock, &rset))
2958 {
2959 // clear signalling data off socket
2960 char buf[256];
2961 recv(d->LLQEventListenSock, buf, 256, 0);
2962 if (!EventsPending)
2963 {
2964 EventsPending = mDNStrue;
2965 if (gettimeofday(&EventTS, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
2966 }
2967 }
2968
2969 for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
2970 {
2971 if ( FD_ISSET( source->fd, &rset ) )
2972 {
2973 source->callback( source->context );
2974 break; // in case we removed this guy from the event loop
2975 }
2976 }
2977 }
2978 else
2979 {
2980 // timeout
2981 if (EventsPending) { GenLLQEvents(d); EventsPending = mDNSfalse; }
2982 else { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; }
2983 }
2984 }
2985 return 0;
2986 }
2987
2988 // signal handler sets global variables, which are inspected by main event loop
2989 // (select automatically returns due to the handled signal)
2990 mDNSlocal void HndlSignal(int sig)
2991 {
2992 if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
2993 if (sig == INFO_SIGNAL) { dumptable = 1; return; }
2994 if (sig == SIGHUP) { hangup = 1; return; }
2995 }
2996
2997 mDNSlocal mStatus
2998 SetPublicSRV
2999 (
3000 DaemonInfo * d,
3001 const char * name
3002 )
3003 {
3004 DNameListElem * elem;
3005 mStatus err = mStatus_NoError;
3006
3007 elem = ( DNameListElem* ) malloc( sizeof( DNameListElem ) );
3008 require_action( elem, exit, err = mStatus_NoMemoryErr );
3009 MakeDomainNameFromDNSNameString( &elem->name, name );
3010 elem->next = d->public_names;
3011 d->public_names = elem;
3012
3013 exit:
3014
3015 return err;
3016 }
3017
3018
3019 int main(int argc, char *argv[])
3020 {
3021 int started_via_launchd = 0;
3022 DaemonInfo *d;
3023 struct rlimit rlim;
3024
3025 Log("dnsextd starting");
3026
3027 d = malloc(sizeof(*d));
3028 if (!d) { LogErr("main", "malloc"); exit(1); }
3029 mDNSPlatformMemZero(d, sizeof(DaemonInfo));
3030
3031 // Setup the public SRV record names
3032
3033 SetPublicSRV(d, "_dns-update._udp.");
3034 SetPublicSRV(d, "_dns-llq._udp.");
3035 SetPublicSRV(d, "_dns-update-tls._tcp.");
3036 SetPublicSRV(d, "_dns-query-tls._tcp.");
3037 SetPublicSRV(d, "_dns-llq-tls._tcp.");
3038
3039 // Setup signal handling
3040
3041 if (signal(SIGHUP, HndlSignal) == SIG_ERR) perror("Can't catch SIGHUP");
3042 if (signal(SIGTERM, HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
3043 if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
3044 if (signal(SIGINT, HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
3045 if (signal(SIGPIPE, SIG_IGN ) == SIG_ERR) perror("Can't ignore SIGPIPE");
3046
3047 // remove open file limit
3048 rlim.rlim_max = RLIM_INFINITY;
3049 rlim.rlim_cur = RLIM_INFINITY;
3050 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
3051 {
3052 LogErr("main", "setrlimit");
3053 Log("Using default file descriptor resource limit");
3054 }
3055
3056 if (argc > 1 && !strcasecmp(argv[1], "-launchd"))
3057 {
3058 Log("started_via_launchd");
3059 started_via_launchd = 1;
3060 argv++;
3061 argc--;
3062 }
3063 if (ProcessArgs(argc, argv, d) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3064
3065 if (!foreground && !started_via_launchd)
3066 {
3067 if (daemon(0,0))
3068 {
3069 LogErr("main", "daemon");
3070 foreground = 1;
3071 }
3072 }
3073
3074 if (InitLeaseTable(d) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3075 if (SetupSockets(d) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3076 if (SetUpdateSRV(d) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3077
3078 Run(d);
3079
3080 Log("dnsextd stopping");
3081
3082 if (ClearUpdateSRV(d) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3083 free(d);
3084 exit(0);
3085 }
3086
3087
3088 // These are stubbed out implementations of up-call routines that the various platform support layers
3089 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3090 // link this code in.
3091 //
3092 // It's an error for these routines to actually be called, so perhaps we should log any call
3093 // to them.
3094 void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
3095 void mDNS_ConfigChanged(mDNS *const m) { ( void ) m; }
3096 void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
3097 void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
3098 const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
3099 const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
3100 { ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
3101 DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const int serviceID, const mDNSAddr *addr, const mDNSIPPort port,
3102 mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSu16 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
3103 { ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; (void) cellIntf;
3104 (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
3105 void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
3106 void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
3107 { ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
3108 mDNSs32 mDNS_Execute (mDNS *const m) { ( void ) m; return 0; }
3109 mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
3110 mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3111 void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
3112 { ( void ) m; ( void ) set; ( void ) flapping; }
3113 const char * const mDNS_DomainTypeNames[1] = {};
3114 mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
3115 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
3116 { ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
3117 mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3118 mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
3119 { ( void ) m; ( void ) set; ( void ) flapping; return 0; }
3120 void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
3121 void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
3122 void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
3123 { ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
3124 mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
3125 mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
3126 const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
3127 { ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; ( void ) autoTunnel; return 0; }
3128 mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
3129 void TriggerEventCompletion(void);
3130 void TriggerEventCompletion() {}
3131 int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
3132 int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) { ( void ) rr; ( void ) q; return 1;}
3133 mDNS mDNSStorage;
3134
3135
3136 // For convenience when using the "strings" command, this is the last thing in the file
3137 // The "@(#) " pattern is a special prefix the "what" command looks for
3138 const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
3139
3140 #if _BUILDING_XCODE_PROJECT_
3141 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3142 const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
3143 asm (".desc ___crashreporter_info__, 0x10");
3144 #endif