]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSShared/dnsextd.c
mDNSResponder-1096.0.2.tar.gz
[apple/mdnsresponder.git] / mDNSShared / dnsextd.c
1 /*
2 * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #if __APPLE__
18 // In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
19 // error, which prevents compilation because we build with "-Werror".
20 // Since this is supposed to be portable cross-platform code, we don't care that daemon is
21 // deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
22 #define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
23 #endif
24
25 #include <signal.h>
26 #include <pthread.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <stdio.h>
34 #include <syslog.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <sys/resource.h>
38 #include <time.h>
39 #include <errno.h>
40
41 #if __APPLE__
42 #undef daemon
43 extern int daemon(int, int);
44 #endif
45
46 // Solaris doesn't have daemon(), so we define it here
47 #ifdef NOT_HAVE_DAEMON
48 #include "../mDNSPosix/mDNSUNP.h" // For daemon()
49 #endif // NOT_HAVE_DAEMON
50
51 #include "dnsextd.h"
52 #include "../mDNSShared/uds_daemon.h"
53 #include "../mDNSShared/dnssd_ipc.h"
54 #include "../mDNSCore/uDNS.h"
55 #include "../mDNSShared/DebugServices.h"
56
57 // Compatibility workaround
58 #ifndef AF_LOCAL
59 #define AF_LOCAL AF_UNIX
60 #endif
61
62 //
63 // Constants
64 //
65 mDNSexport const char ProgramName[] = "dnsextd";
66
67 #define LOOPBACK "127.0.0.1"
68 #if !defined(LISTENQ)
69 # define LISTENQ 128 // tcp connection backlog
70 #endif
71 #define RECV_BUFLEN 9000
72 #define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
73 #define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
74 #define SRV_TTL 7200 // TTL For _dns-update SRV records
75 #define CONFIG_FILE "/etc/dnsextd.conf"
76 #define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
77
78 // LLQ Lease bounds (seconds)
79 #define LLQ_MIN_LEASE (15 * 60)
80 #define LLQ_MAX_LEASE (120 * 60)
81 #define LLQ_LEASE_FUDGE 60
82
83 // LLQ SOA poll interval (microseconds)
84 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
85 #define LLQ_MONITOR_INTERVAL 250000
86 #ifdef SIGINFO
87 #define INFO_SIGNAL SIGINFO
88 #else
89 #define INFO_SIGNAL SIGUSR1
90 #endif
91
92 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
93
94 //
95 // Data Structures
96 // Structs/fields that must be locked for thread safety are explicitly commented
97 //
98
99 // args passed to UDP request handler thread as void*
100
101 typedef struct
102 {
103 PktMsg pkt;
104 struct sockaddr_in cliaddr;
105 DaemonInfo *d;
106 int sd;
107 } UDPContext;
108
109 // args passed to TCP request handler thread as void*
110 typedef struct
111 {
112 PktMsg pkt;
113 struct sockaddr_in cliaddr;
114 TCPSocket *sock; // socket connected to client
115 DaemonInfo *d;
116 } TCPContext;
117
118 // args passed to UpdateAnswerList thread as void*
119 typedef struct
120 {
121 DaemonInfo *d;
122 AnswerListElem *a;
123 } UpdateAnswerListArgs;
124
125 //
126 // Global Variables
127 //
128
129 // booleans to determine runtime output
130 // read-only after initialization (no mutex protection)
131 static mDNSBool foreground = 0;
132 static mDNSBool verbose = 0;
133
134 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
135 static mDNSBool terminate = 0;
136 static mDNSBool dumptable = 0;
137 static mDNSBool hangup = 0;
138
139 // global for config file location
140 static char * cfgfile = NULL;
141
142 //
143 // Logging Routines
144 // Log messages are delivered to syslog unless -f option specified
145 //
146
147 // common message logging subroutine
148 mDNSlocal void PrintLog(const char *buffer)
149 {
150 if (foreground)
151 {
152 fprintf(stderr,"%s\n", buffer);
153 fflush(stderr);
154 }
155 else
156 {
157 openlog("dnsextd", LOG_CONS, LOG_DAEMON);
158 syslog(LOG_ERR, "%s", buffer);
159 closelog();
160 }
161 }
162
163 // Verbose Logging (conditional on -v option)
164 mDNSlocal void VLog(const char *format, ...)
165 {
166 char buffer[512];
167 va_list ptr;
168
169 if (!verbose) return;
170 va_start(ptr,format);
171 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
172 va_end(ptr);
173 PrintLog(buffer);
174 }
175
176 // Unconditional Logging
177 mDNSlocal void Log(const char *format, ...)
178 {
179 char buffer[512];
180 va_list ptr;
181
182 va_start(ptr,format);
183 buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
184 va_end(ptr);
185 PrintLog(buffer);
186 }
187
188 // Error Logging
189 // prints message "dnsextd <function>: <operation> - <error message>"
190 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
191 mDNSlocal void LogErr(const char *fn, const char *operation)
192 {
193 char buf[512], errbuf[256];
194 strerror_r(errno, errbuf, sizeof(errbuf));
195 snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, errbuf);
196 PrintLog(buf);
197 }
198
199 //
200 // Networking Utility Routines
201 //
202
203 // Convert DNS Message Header from Network to Host byte order
204 mDNSlocal void HdrNToH(PktMsg *pkt)
205 {
206 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
207 mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
208 pkt->msg.h.numQuestions = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);
209 pkt->msg.h.numAnswers = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);
210 pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] << 8 | ptr[5]);
211 pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] << 8 | ptr[7]);
212 }
213
214 // Convert DNS Message Header from Host to Network byte order
215 mDNSlocal void HdrHToN(PktMsg *pkt)
216 {
217 mDNSu16 numQuestions = pkt->msg.h.numQuestions;
218 mDNSu16 numAnswers = pkt->msg.h.numAnswers;
219 mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
220 mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
221 mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
222
223 // Put all the integer values in IETF byte-order (MSB first, LSB second)
224 *ptr++ = (mDNSu8)(numQuestions >> 8);
225 *ptr++ = (mDNSu8)(numQuestions & 0xFF);
226 *ptr++ = (mDNSu8)(numAnswers >> 8);
227 *ptr++ = (mDNSu8)(numAnswers & 0xFF);
228 *ptr++ = (mDNSu8)(numAuthorities >> 8);
229 *ptr++ = (mDNSu8)(numAuthorities & 0xFF);
230 *ptr++ = (mDNSu8)(numAdditionals >> 8);
231 *ptr++ = (mDNSu8)(numAdditionals & 0xFF);
232 }
233
234
235 // Add socket to event loop
236
237 mDNSlocal mStatus AddSourceToEventLoop( DaemonInfo * self, TCPSocket *sock, EventCallback callback, void *context )
238 {
239 EventSource * newSource;
240 mStatus err = mStatus_NoError;
241
242 if ( self->eventSources.LinkOffset == 0 )
243 {
244 InitLinkedList( &self->eventSources, offsetof( EventSource, next));
245 }
246
247 newSource = ( EventSource*) malloc( sizeof *newSource );
248 if ( newSource == NULL )
249 {
250 err = mStatus_NoMemoryErr;
251 goto exit;
252 }
253
254 newSource->callback = callback;
255 newSource->context = context;
256 newSource->sock = sock;
257 newSource->fd = mDNSPlatformTCPGetFD( sock );
258
259 AddToTail( &self->eventSources, newSource );
260
261 exit:
262
263 return err;
264 }
265
266
267 // Remove socket from event loop
268
269 mDNSlocal mStatus RemoveSourceFromEventLoop( DaemonInfo * self, TCPSocket *sock )
270 {
271 EventSource * source;
272 mStatus err;
273
274 for ( source = ( EventSource* ) self->eventSources.Head; source; source = source->next )
275 {
276 if ( source->sock == sock )
277 {
278 RemoveFromList( &self->eventSources, source );
279
280 free( source );
281 err = mStatus_NoError;
282 goto exit;
283 }
284 }
285
286 err = mStatus_NoSuchNameErr;
287
288 exit:
289
290 return err;
291 }
292
293 // create a socket connected to nameserver
294 // caller terminates connection via close()
295 mDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
296 {
297 int ntries = 0, retry = 0;
298
299 while (1)
300 {
301 mDNSIPPort port = zeroIPPort;
302 int fd;
303
304 TCPSocket *sock = mDNSPlatformTCPSocket(0, mDNSAddrType_IPv4, &port, NULL, mDNSfalse );
305 if ( !sock ) { LogErr("ConnectToServer", "socket"); return NULL; }
306 fd = mDNSPlatformTCPGetFD( sock );
307 if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
308 mDNSPlatformTCPCloseConnection( sock );
309 if (++ntries < 10)
310 {
311 LogErr("ConnectToServer", "connect");
312 Log("ConnectToServer - retrying connection");
313 if (!retry) retry = 500000 + random() % 500000;
314 usleep(retry);
315 retry *= 2;
316 }
317 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries); return NULL; }
318 }
319 }
320
321 // send an entire block of data over a connected socket
322 mDNSlocal int MySend(TCPSocket *sock, const void *msg, int len)
323 {
324 int selectval, n, nsent = 0;
325 fd_set wset;
326 struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
327
328 while (nsent < len)
329 {
330 int fd;
331
332 FD_ZERO(&wset);
333
334 fd = mDNSPlatformTCPGetFD( sock );
335
336 FD_SET( fd, &wset );
337 selectval = select( fd+1, NULL, &wset, NULL, &timeout);
338 if (selectval < 0) { LogErr("MySend", "select"); return -1; }
339 if (!selectval || !FD_ISSET(fd, &wset)) { Log("MySend - timeout"); return -1; }
340
341 n = mDNSPlatformWriteTCP( sock, ( char* ) msg + nsent, len - nsent);
342
343 if (n < 0) { LogErr("MySend", "send"); return -1; }
344 nsent += n;
345 }
346 return 0;
347 }
348
349 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
350 mDNSlocal int SendPacket(TCPSocket *sock, PktMsg *pkt)
351 {
352 // send the lenth, in network byte order
353 mDNSu16 len = htons((mDNSu16)pkt->len);
354 if (MySend(sock, &len, sizeof(len)) < 0) return -1;
355
356 // send the message
357 VLog("SendPacket Q:%d A:%d A:%d A:%d ",
358 ntohs(pkt->msg.h.numQuestions),
359 ntohs(pkt->msg.h.numAnswers),
360 ntohs(pkt->msg.h.numAuthorities),
361 ntohs(pkt->msg.h.numAdditionals));
362 return MySend(sock, &pkt->msg, pkt->len);
363 }
364
365 // Receive len bytes, waiting until we have all of them.
366 // Returns number of bytes read (which should always be the number asked for).
367 static int my_recv(TCPSocket *sock, void *const buf, const int len, mDNSBool * closed)
368 {
369 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
370 // use an explicit while() loop instead.
371 // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
372 // arithmetic on "void *" pointers is compiler-dependent.
373
374 fd_set rset;
375 struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
376 int selectval, remaining = len;
377 char *ptr = (char *)buf;
378 ssize_t num_read;
379
380 while (remaining)
381 {
382 int fd;
383
384 fd = mDNSPlatformTCPGetFD( sock );
385
386 FD_ZERO(&rset);
387 FD_SET(fd, &rset);
388 selectval = select(fd+1, &rset, NULL, NULL, &timeout);
389 if (selectval < 0) { LogErr("my_recv", "select"); return -1; }
390 if (!selectval || !FD_ISSET(fd, &rset))
391 {
392 Log("my_recv - timeout");
393 return -1;
394 }
395
396 num_read = mDNSPlatformReadTCP( sock, ptr, remaining, closed );
397
398 if (((num_read == 0) && *closed) || (num_read < 0) || (num_read > remaining)) return -1;
399 if (num_read == 0) return 0;
400 ptr += num_read;
401 remaining -= num_read;
402 }
403 return(len);
404 }
405
406 // Return a DNS Message read off of a TCP socket, or NULL on failure
407 // If storage is non-null, result is placed in that buffer. Otherwise,
408 // returned value is allocated with Malloc, and contains sufficient extra
409 // storage for a Lease OPT RR
410
411 mDNSlocal PktMsg*
412 RecvPacket
413 (
414 TCPSocket * sock,
415 PktMsg * storage,
416 mDNSBool * closed
417 )
418 {
419 int nread;
420 int allocsize;
421 mDNSu16 msglen = 0;
422 PktMsg * pkt = NULL;
423 unsigned int srclen;
424 int fd;
425 mStatus err = 0;
426
427 fd = mDNSPlatformTCPGetFD( sock );
428
429 nread = my_recv( sock, &msglen, sizeof( msglen ), closed );
430
431 require_action_quiet( nread != -1, exit, err = mStatus_UnknownErr );
432 require_action_quiet( nread > 0, exit, err = mStatus_NoError );
433
434 msglen = ntohs( msglen );
435 require_action_quiet( nread == sizeof( msglen ), exit, err = mStatus_UnknownErr; Log( "Could not read length field of message") );
436
437 if ( storage )
438 {
439 require_action_quiet( msglen <= sizeof( storage->msg ), exit, err = mStatus_UnknownErr; Log( "RecvPacket: provided buffer too small." ) );
440 pkt = storage;
441 }
442 else
443 {
444 // buffer extra space to add an OPT RR
445
446 if ( msglen > sizeof(DNSMessage))
447 {
448 allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
449 }
450 else
451 {
452 allocsize = sizeof(PktMsg);
453 }
454
455 pkt = malloc(allocsize);
456 require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) );
457 mDNSPlatformMemZero( pkt, sizeof( *pkt ) );
458 }
459
460 pkt->len = msglen;
461 srclen = sizeof(pkt->src);
462
463 if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) )
464 {
465 LogErr("RecvPacket", "getpeername");
466 mDNSPlatformMemZero(&pkt->src, sizeof(pkt->src));
467 }
468
469 nread = my_recv(sock, &pkt->msg, msglen, closed );
470 require_action_quiet( nread >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvPacket", "recv" ) );
471 require_action_quiet( nread == msglen, exit, err = mStatus_UnknownErr ; Log( "Could not read entire message" ) );
472 require_action_quiet( pkt->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr ; Log( "RecvPacket: Message too short (%d bytes)", pkt->len ) );
473
474 exit:
475
476 if ( err && pkt )
477 {
478 if ( pkt != storage )
479 {
480 free(pkt);
481 }
482
483 pkt = NULL;
484 }
485
486 return pkt;
487 }
488
489
490 mDNSlocal DNSZone*
491 FindZone
492 (
493 DaemonInfo * self,
494 domainname * name
495 )
496 {
497 DNSZone * zone;
498
499 for ( zone = self->zones; zone; zone = zone->next )
500 {
501 if ( SameDomainName( &zone->name, name ) )
502 {
503 break;
504 }
505 }
506
507 return zone;
508 }
509
510
511 mDNSlocal mDNSBool
512 ZoneHandlesName
513 (
514 const domainname * zname,
515 const domainname * dname
516 )
517 {
518 mDNSu16 i = DomainNameLength( zname );
519 mDNSu16 j = DomainNameLength( dname );
520
521 if ( ( i == ( MAX_DOMAIN_NAME + 1 ) ) || ( j == ( MAX_DOMAIN_NAME + 1 ) ) || ( i > j ) || ( memcmp( zname->c, dname->c + ( j - i ), i ) != 0 ) )
522 {
523 return mDNSfalse;
524 }
525
526 return mDNStrue;
527 }
528
529
530 mDNSlocal mDNSBool IsQuery( PktMsg * pkt )
531 {
532 return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery );
533 }
534
535
536 mDNSlocal mDNSBool IsUpdate( PktMsg * pkt )
537 {
538 return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_OP_Update );
539 }
540
541
542 mDNSlocal mDNSBool IsNotify(PktMsg *pkt)
543 {
544 return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( mDNSu8) ( kDNSFlag0_OP_Notify );
545 }
546
547
548 mDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
549 {
550 const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
551 LargeCacheRecord lcr;
552 int i;
553 mDNSBool result = mDNSfalse;
554
555 HdrNToH(pkt);
556 if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
557
558 if (!pkt->msg.h.numAdditionals) goto end;
559 ptr = LocateAdditionals(&pkt->msg, end);
560 if (!ptr) goto end;
561
562 bzero(&lcr, sizeof(lcr));
563 // find last Additional info.
564 for (i = 0; i < pkt->msg.h.numAdditionals; i++)
565 {
566 ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
567 if (!ptr) { Log("Unable to read additional record"); goto end; }
568 }
569
570 if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= DNSOpt_LLQData_Space && lcr.r.resrec.rdata->u.opt[0].opt == kDNSOpt_LLQ )
571 {
572 result = mDNStrue;
573 }
574
575 end:
576 HdrHToN(pkt);
577 return result;
578 }
579
580 // !!!KRS implement properly
581 mDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
582 {
583 if ((pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery ) &&
584 pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
585 return mDNSfalse;
586 }
587
588
589 mDNSlocal mDNSBool
590 IsPublicSRV
591 (
592 DaemonInfo * self,
593 DNSQuestion * q
594 )
595 {
596 DNameListElem * elem;
597 mDNSBool ret = mDNSfalse;
598 int i = ( int ) DomainNameLength( &q->qname ) - 1;
599
600 for ( elem = self->public_names; elem; elem = elem->next )
601 {
602 int j = ( int ) DomainNameLength( &elem->name ) - 1;
603
604 if ( i > j )
605 {
606 for ( ; i >= 0; i--, j-- )
607 {
608 if ( q->qname.c[ i ] != elem->name.c[ j ] )
609 {
610 ret = mDNStrue;
611 goto exit;
612 }
613 }
614 }
615 }
616
617 exit:
618
619 return ret;
620 }
621
622
623 mDNSlocal void
624 SetZone
625 (
626 DaemonInfo * self,
627 PktMsg * pkt
628 )
629 {
630 domainname zname;
631 const mDNSu8 * ptr = pkt->msg.data;
632 mDNSBool exception = mDNSfalse;
633
634 // Initialize
635
636 pkt->zone = NULL;
637 pkt->isZonePublic = mDNStrue;
638 zname.c[0] = '\0';
639
640 // Figure out what type of packet this is
641
642 if ( IsQuery( pkt ) )
643 {
644 DNSQuestion question;
645
646 // It's a query
647
648 getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
649
650 AppendDomainName( &zname, &question.qname );
651
652 exception = ( ( question.qtype == kDNSType_SOA ) || ( question.qtype == kDNSType_NS ) || ( ( question.qtype == kDNSType_SRV ) && IsPublicSRV( self, &question ) ) );
653 }
654 else if ( IsUpdate( pkt ) )
655 {
656 DNSQuestion question;
657
658 // It's an update. The format of the zone section is the same as the format for the question section
659 // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
660
661 getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
662
663 AppendDomainName( &zname, &question.qname );
664
665 exception = mDNSfalse;
666 }
667
668 if ( zname.c[0] != '\0' )
669 {
670 // Find the right zone
671
672 for ( pkt->zone = self->zones; pkt->zone; pkt->zone = pkt->zone->next )
673 {
674 if ( ZoneHandlesName( &pkt->zone->name, &zname ) )
675 {
676 VLog( "found correct zone %##s for query", pkt->zone->name.c );
677
678 pkt->isZonePublic = ( ( pkt->zone->type == kDNSZonePublic ) || exception );
679
680 VLog( "zone %##s is %s", pkt->zone->name.c, ( pkt->isZonePublic ) ? "public" : "private" );
681
682 break;
683 }
684 }
685 }
686 }
687
688
689 mDNSlocal int
690 UDPServerTransaction(const DaemonInfo *d, const PktMsg *request, PktMsg *reply, mDNSBool *trunc)
691 {
692 fd_set rset;
693 struct timeval timeout = { 3, 0 }; // until we remove all calls from main thread, keep timeout short
694 int sd;
695 int res;
696 mStatus err = mStatus_NoError;
697
698 // Initialize
699
700 *trunc = mDNSfalse;
701
702 // Create a socket
703
704 sd = socket( AF_INET, SOCK_DGRAM, 0 );
705 require_action( sd >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "socket" ) );
706
707 // Send the packet to the nameserver
708
709 VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
710 ntohs(request->msg.h.numQuestions),
711 ntohs(request->msg.h.numAnswers),
712 ntohs(request->msg.h.numAuthorities),
713 ntohs(request->msg.h.numAdditionals));
714 res = sendto( sd, (char *)&request->msg, request->len, 0, ( struct sockaddr* ) &d->ns_addr, sizeof( d->ns_addr ) );
715 require_action( res == (int) request->len, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "sendto" ) );
716
717 // Wait for reply
718
719 FD_ZERO( &rset );
720 FD_SET( sd, &rset );
721 res = select( sd + 1, &rset, NULL, NULL, &timeout );
722 require_action( res >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "select" ) );
723 require_action( ( res > 0 ) && FD_ISSET( sd, &rset ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - timeout" ) );
724
725 // Receive reply
726
727 reply->len = recvfrom( sd, &reply->msg, sizeof(reply->msg), 0, NULL, NULL );
728 require_action( ( ( int ) reply->len ) >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "recvfrom" ) );
729 require_action( reply->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - Message too short (%d bytes)", reply->len ) );
730
731 // Check for truncation bit
732
733 if ( reply->msg.h.flags.b[0] & kDNSFlag0_TC )
734 {
735 *trunc = mDNStrue;
736 }
737
738 exit:
739
740 if ( sd >= 0 )
741 {
742 close( sd );
743 }
744
745 return err;
746 }
747
748 //
749 // Dynamic Update Utility Routines
750 //
751
752 // check if a request and server response complete a successful dynamic update
753 mDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
754 {
755 char buf[32];
756 char *vlogmsg = NULL;
757
758 // check messages
759 if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
760 if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
761
762 // check request operation
763 if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
764 { vlogmsg = "Request opcode not an update"; goto failure; }
765
766 // check result
767 if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask)) { vlogmsg = "Reply contains non-zero rcode"; goto failure; }
768 if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
769 { vlogmsg = "Reply opcode not an update response"; goto failure; }
770
771 VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
772 return mDNStrue;
773
774 failure:
775 VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
776 return mDNSfalse;
777 }
778
779 // Allocate an appropriately sized CacheRecord and copy data from original.
780 // Name pointer in CacheRecord object is set to point to the name specified
781 //
782 mDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
783 {
784 CacheRecord *cr;
785 size_t size = sizeof(*cr);
786 if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
787 cr = malloc(size);
788 if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
789 memcpy(cr, orig, size);
790 cr->resrec.rdata = (RData*)&cr->smallrdatastorage;
791 cr->resrec.name = name;
792
793 return cr;
794 }
795
796
797 //
798 // Lease Hashtable Utility Routines
799 //
800
801 // double hash table size
802 // caller must lock table prior to invocation
803 mDNSlocal void RehashTable(DaemonInfo *d)
804 {
805 RRTableElem *ptr, *tmp, **new;
806 int i, bucket, newnbuckets = d->nbuckets * 2;
807
808 VLog("Rehashing lease table (new size %d buckets)", newnbuckets);
809 new = malloc(sizeof(RRTableElem *) * newnbuckets);
810 if (!new) { LogErr("RehashTable", "malloc"); return; }
811 mDNSPlatformMemZero(new, newnbuckets * sizeof(RRTableElem *));
812
813 for (i = 0; i < d->nbuckets; i++)
814 {
815 ptr = d->table[i];
816 while (ptr)
817 {
818 bucket = ptr->rr.resrec.namehash % newnbuckets;
819 tmp = ptr;
820 ptr = ptr->next;
821 tmp->next = new[bucket];
822 new[bucket] = tmp;
823 }
824 }
825 d->nbuckets = newnbuckets;
826 free(d->table);
827 d->table = new;
828 }
829
830 // print entire contents of hashtable, invoked via SIGINFO
831 mDNSlocal void PrintLeaseTable(DaemonInfo *d)
832 {
833 int i;
834 RRTableElem *ptr;
835 char rrbuf[MaxMsg], addrbuf[16];
836 struct timeval now;
837 int hr, min, sec;
838
839 if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
840 if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
841
842 Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
843 for (i = 0; i < d->nbuckets; i++)
844 {
845 for (ptr = d->table[i]; ptr; ptr = ptr->next)
846 {
847 hr = ((ptr->expire - now.tv_sec) / 60) / 60;
848 min = ((ptr->expire - now.tv_sec) / 60) % 60;
849 sec = (ptr->expire - now.tv_sec) % 60;
850 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,
851 GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
852 }
853 }
854 pthread_mutex_unlock(&d->tablelock);
855 }
856
857 //
858 // Startup SRV Registration Routines
859 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
860 // the daemon accepts requests
861 //
862
863 // delete all RRS of a given name/type
864 mDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit, ResourceRecord *rr)
865 {
866 ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
867 if (!ptr || ptr + 10 >= limit) return NULL; // out of space
868 ptr[0] = (mDNSu8)(rr->rrtype >> 8);
869 ptr[1] = (mDNSu8)(rr->rrtype & 0xFF);
870 ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8);
871 ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY & 0xFF);
872 mDNSPlatformMemZero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
873 msg->h.mDNS_numUpdates++;
874 return ptr + 10;
875 }
876
877 mDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, DNSZone * zone, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSIPPort port, mDNSBool registration)
878 {
879 AuthRecord rr;
880 char hostname[1024], buf[MaxMsg];
881 mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
882
883 ( void ) d;
884
885 mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, AuthRecordAny, NULL, NULL);
886 rr.resrec.rrclass = kDNSClass_IN;
887 rr.resrec.rdata->u.srv.priority = 0;
888 rr.resrec.rdata->u.srv.weight = 0;
889 rr.resrec.rdata->u.srv.port = port;
890 if (gethostname(hostname, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
891 rr.resrec.rdata->u.srv.target.c[0] = '\0';
892
893 MakeDomainNameFromDNSNameString(&rr.namestorage, regtype);
894 AppendDomainName(&rr.namestorage, &zone->name);
895 VLog("%s %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
896 GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
897 if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
898 else ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
899 return ptr;
900 }
901
902
903 // perform dynamic update.
904 // specify deletion by passing false for the register parameter, otherwise register the records.
905 mDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
906 {
907 TCPSocket *sock = NULL;
908 DNSZone * zone;
909 int err = mStatus_NoError;
910
911 sock = ConnectToServer( d );
912 require_action( sock, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: ConnectToServer failed" ) );
913
914 for ( zone = d->zones; zone; zone = zone->next )
915 {
916 PktMsg pkt;
917 mDNSu8 *ptr = pkt.msg.data;
918 mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
919 PktMsg *reply = NULL;
920 mDNSBool closed;
921 mDNSBool ok;
922
923 // Initialize message
924 InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
925 pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
926 pkt.src.sin_family = AF_INET;
927
928 // format message body
929 ptr = putZone(&pkt.msg, ptr, end, &zone->name, mDNSOpaque16fromIntVal(kDNSClass_IN));
930 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
931
932 if ( zone->type == kDNSZonePrivate )
933 {
934 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls._tcp.", d->private_port, registration);
935 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
936 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls._tcp.", d->private_port, registration);
937 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
938 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls._tcp.", d->private_port, registration);
939 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
940
941 if ( !registration )
942 {
943 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
944 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
945 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
946 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
947 }
948 }
949 else
950 {
951 if ( !registration )
952 {
953 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls.", d->private_port, registration);
954 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
955 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls.", d->private_port, registration);
956 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
957 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls.", d->private_port, registration);
958 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
959 }
960
961 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
962 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
963 ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
964 require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
965 }
966
967 HdrHToN(&pkt);
968
969 if ( zone->updateKeys )
970 {
971 DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 );
972 require_action( ptr, exit, Log("UpdateSRV: Error constructing lease expiration update" ) );
973 }
974
975 pkt.len = ptr - (mDNSu8 *)&pkt.msg;
976
977 // send message, receive reply
978
979 err = SendPacket( sock, &pkt );
980 require_action( !err, exit, Log( "UpdateSRV: SendPacket failed" ) );
981
982 reply = RecvPacket( sock, NULL, &closed );
983 require_action( reply, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: RecvPacket returned NULL" ) );
984
985 ok = SuccessfulUpdateTransaction( &pkt, reply );
986
987 if ( !ok )
988 {
989 Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
990 }
991
992 free( reply );
993 }
994
995 exit:
996
997 if ( sock )
998 {
999 mDNSPlatformTCPCloseConnection( sock );
1000 }
1001
1002 return err;
1003 }
1004
1005 // wrapper routines/macros
1006 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1007
1008 // clear any existing records prior to registration
1009 mDNSlocal int SetUpdateSRV(DaemonInfo *d)
1010 {
1011 int err;
1012
1013 err = ClearUpdateSRV(d); // clear any existing record
1014 if (!err) err = UpdateSRV(d, 1);
1015 return err;
1016 }
1017
1018 //
1019 // Argument Parsing and Configuration
1020 //
1021
1022 mDNSlocal void PrintUsage(void)
1023 {
1024 fprintf(stderr, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1025 "Use \"dnsextd -h\" for help\n");
1026 }
1027
1028 mDNSlocal void PrintHelp(void)
1029 {
1030 fprintf(stderr, "\n\n");
1031 PrintUsage();
1032
1033 fprintf(stderr,
1034 "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
1035 "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
1036 "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
1037 "Discovery, Update Leases, and Long Lived Queries.)\n\n"
1038
1039 "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
1040 "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
1041 "primary master server for this zone.\n\n"
1042
1043 "The options are as follows:\n\n"
1044
1045 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1046
1047 "-d Run daemon in foreground.\n\n"
1048
1049 "-h Print help.\n\n"
1050
1051 "-v Verbose output.\n\n"
1052 );
1053 }
1054
1055
1056 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
1057 // returns 0 (success) if program is to continue execution
1058 // output control arguments (-f, -v) do not affect this routine
1059 mDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
1060 {
1061 DNSZone * zone;
1062 int opt;
1063 int err = 0;
1064
1065 cfgfile = strdup( CONFIG_FILE );
1066 require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr );
1067
1068 // defaults, may be overriden by command option
1069
1070 // setup our sockaddr
1071
1072 mDNSPlatformMemZero( &d->addr, sizeof( d->addr ) );
1073 d->addr.sin_addr.s_addr = zerov4Addr.NotAnInteger;
1074 d->addr.sin_port = UnicastDNSPort.NotAnInteger;
1075 d->addr.sin_family = AF_INET;
1076 #ifndef NOT_HAVE_SA_LEN
1077 d->addr.sin_len = sizeof( d->addr );
1078 #endif
1079
1080 // setup nameserver's sockaddr
1081
1082 mDNSPlatformMemZero(&d->ns_addr, sizeof(d->ns_addr));
1083 d->ns_addr.sin_family = AF_INET;
1084 inet_pton( AF_INET, LOOPBACK, &d->ns_addr.sin_addr );
1085 d->ns_addr.sin_port = NSIPCPort.NotAnInteger;
1086 #ifndef NOT_HAVE_SA_LEN
1087 d->ns_addr.sin_len = sizeof( d->ns_addr );
1088 #endif
1089
1090 // setup our ports
1091
1092 d->private_port = PrivateDNSPort;
1093 d->llq_port = DNSEXTPort;
1094
1095 while ((opt = getopt(argc, argv, "f:hdv")) != -1)
1096 {
1097 switch(opt)
1098 {
1099 case 'f': free( cfgfile ); cfgfile = strdup( optarg ); require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr ); break;
1100 case 'h': PrintHelp(); return -1;
1101 case 'd': foreground = 1; break; // Also used when launched via OS X's launchd mechanism
1102 case 'v': verbose = 1; break;
1103 default: goto arg_error;
1104 }
1105 }
1106
1107 err = ParseConfig( d, cfgfile );
1108 require_noerr( err, arg_error );
1109
1110 // Make sure we've specified some zones
1111
1112 require_action( d->zones, arg_error, err = mStatus_UnknownErr );
1113
1114 // if we have a shared secret, use it for the entire zone
1115
1116 for ( zone = d->zones; zone; zone = zone->next )
1117 {
1118 if ( zone->updateKeys )
1119 {
1120 AssignDomainName( &zone->updateKeys->domain, &zone->name );
1121 }
1122 }
1123
1124 return 0;
1125
1126 arg_error:
1127
1128 PrintUsage();
1129 return -1;
1130 }
1131
1132
1133 //
1134 // Initialization Routines
1135 //
1136
1137 // Allocate memory, initialize locks and bookkeeping variables
1138 mDNSlocal int InitLeaseTable(DaemonInfo *d)
1139 {
1140 if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1141 d->nbuckets = LEASETABLE_INIT_NBUCKETS;
1142 d->nelems = 0;
1143 d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
1144 if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; }
1145 mDNSPlatformMemZero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
1146 return 0;
1147 }
1148
1149
1150 mDNSlocal int
1151 SetupSockets
1152 (
1153 DaemonInfo * self
1154 )
1155 {
1156 static const int kOn = 1;
1157 int sockpair[2];
1158 mDNSBool private = mDNSfalse;
1159 struct sockaddr_in daddr;
1160 DNSZone * zone;
1161 mStatus err = 0;
1162
1163 // set up sockets on which we all ns requests
1164
1165 self->tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
1166 require_action( dnssd_SocketValid(self->tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
1167
1168 #if defined(SO_REUSEADDR)
1169 err = setsockopt(self->tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
1170 require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
1171 #endif
1172
1173 err = bind( self->tcpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
1174 require_action( !err, exit, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1175
1176 err = listen( self->tcpsd, LISTENQ );
1177 require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
1178
1179 self->udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
1180 require_action( dnssd_SocketValid(self->udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
1181
1182 #if defined(SO_REUSEADDR)
1183 err = setsockopt(self->udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
1184 require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
1185 #endif
1186
1187 err = bind( self->udpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
1188 require_action( !err, exit, LogErr( "SetupSockets", "bind self->udpsd" ) );
1189
1190 // set up sockets on which we receive llq requests
1191
1192 mDNSPlatformMemZero(&self->llq_addr, sizeof(self->llq_addr));
1193 self->llq_addr.sin_family = AF_INET;
1194 self->llq_addr.sin_addr.s_addr = zerov4Addr.NotAnInteger;
1195 self->llq_addr.sin_port = ( self->llq_port.NotAnInteger ) ? self->llq_port.NotAnInteger : DNSEXTPort.NotAnInteger;
1196
1197 if (self->llq_addr.sin_port == self->addr.sin_port)
1198 {
1199 self->llq_tcpsd = self->tcpsd;
1200 self->llq_udpsd = self->udpsd;
1201 }
1202 else
1203 {
1204 self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
1205 require_action( dnssd_SocketValid(self->llq_tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
1206
1207 #if defined(SO_REUSEADDR)
1208 err = setsockopt(self->llq_tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
1209 require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
1210 #endif
1211
1212 err = bind( self->llq_tcpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
1213 require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
1214
1215 err = listen( self->llq_tcpsd, LISTENQ );
1216 require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
1217
1218 self->llq_udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
1219 require_action( dnssd_SocketValid(self->llq_udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
1220
1221 #if defined(SO_REUSEADDR)
1222 err = setsockopt(self->llq_udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
1223 require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
1224 #endif
1225
1226 err = bind(self->llq_udpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
1227 require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
1228 }
1229
1230 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1231
1232 err = socketpair( AF_LOCAL, SOCK_STREAM, 0, sockpair );
1233 require_action( !err, exit, LogErr( "SetupSockets", "socketpair" ) );
1234
1235 self->LLQEventListenSock = sockpair[0];
1236 self->LLQEventNotifySock = sockpair[1];
1237
1238 // set up socket on which we receive private requests
1239
1240 self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
1241 require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
1242 mDNSPlatformMemZero(&daddr, sizeof(daddr));
1243 daddr.sin_family = AF_INET;
1244 daddr.sin_addr.s_addr = zerov4Addr.NotAnInteger;
1245 daddr.sin_port = ( self->private_port.NotAnInteger ) ? self->private_port.NotAnInteger : PrivateDNSPort.NotAnInteger;
1246
1247 self->tlssd = socket( AF_INET, SOCK_STREAM, 0 );
1248 require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
1249
1250 #if defined(SO_REUSEADDR)
1251 err = setsockopt(self->tlssd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
1252 require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
1253 #endif
1254
1255 err = bind( self->tlssd, ( struct sockaddr* ) &daddr, sizeof( daddr ) );
1256 require_action( !err, exit, LogErr( "SetupSockets", "bind self->tlssd" ) );
1257
1258 err = listen( self->tlssd, LISTENQ );
1259 require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
1260
1261 // Do we have any private zones?
1262
1263 for ( zone = self->zones; zone; zone = zone->next )
1264 {
1265 if ( zone->type == kDNSZonePrivate )
1266 {
1267 private = mDNStrue;
1268 break;
1269 }
1270 }
1271
1272 if ( private )
1273 {
1274 err = mDNSPlatformTLSSetupCerts();
1275 require_action( !err, exit, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1276 }
1277
1278 exit:
1279
1280 return err;
1281 }
1282
1283 //
1284 // periodic table updates
1285 //
1286
1287 // Delete a resource record from the nameserver via a dynamic update
1288 // sd is a socket already connected to the server
1289 mDNSlocal void DeleteOneRecord(DaemonInfo *d, CacheRecord *rr, domainname *zname, TCPSocket *sock)
1290 {
1291 DNSZone * zone;
1292 PktMsg pkt;
1293 mDNSu8 *ptr = pkt.msg.data;
1294 mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
1295 char buf[MaxMsg];
1296 mDNSBool closed;
1297 PktMsg *reply = NULL;
1298
1299 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));
1300
1301 InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
1302
1303 ptr = putZone(&pkt.msg, ptr, end, zname, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
1304 if (!ptr) goto end;
1305 ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
1306 if (!ptr) goto end;
1307
1308 HdrHToN(&pkt);
1309
1310 zone = FindZone( d, zname );
1311
1312 if ( zone && zone->updateKeys)
1313 {
1314 DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 );
1315 if (!ptr) goto end;
1316 }
1317
1318 pkt.len = ptr - (mDNSu8 *)&pkt.msg;
1319 pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
1320 pkt.src.sin_family = AF_INET;
1321 if (SendPacket( sock, &pkt)) { Log("DeleteOneRecord: SendPacket failed"); }
1322 reply = RecvPacket( sock, NULL, &closed );
1323 if (reply) HdrNToH(reply);
1324 require_action( reply, end, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
1325
1326 if (!SuccessfulUpdateTransaction(&pkt, reply))
1327 Log("Expiration update failed with rcode %d", reply ? reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask : -1);
1328
1329 end:
1330 if (!ptr) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1331 if (reply) free(reply);
1332 }
1333
1334 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1335 mDNSlocal void DeleteRecords(DaemonInfo *d, mDNSBool DeleteAll)
1336 {
1337 struct timeval now;
1338 int i;
1339 TCPSocket *sock = ConnectToServer(d);
1340 if (!sock) { Log("DeleteRecords: ConnectToServer failed"); return; }
1341 if (gettimeofday(&now, NULL)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
1342 if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
1343
1344 for (i = 0; i < d->nbuckets; i++)
1345 {
1346 RRTableElem **ptr = &d->table[i];
1347 while (*ptr)
1348 {
1349 if (DeleteAll || (*ptr)->expire - now.tv_sec < 0)
1350 {
1351 RRTableElem *fptr;
1352 // delete record from server
1353 DeleteOneRecord(d, &(*ptr)->rr, &(*ptr)->zone, sock);
1354 fptr = *ptr;
1355 *ptr = (*ptr)->next;
1356 free(fptr);
1357 d->nelems--;
1358 }
1359 else ptr = &(*ptr)->next;
1360 }
1361 }
1362 pthread_mutex_unlock(&d->tablelock);
1363 mDNSPlatformTCPCloseConnection( sock );
1364 }
1365
1366 //
1367 // main update request handling
1368 //
1369
1370 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
1371 mDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
1372 {
1373 int i, allocsize;
1374 LargeCacheRecord lcr;
1375 ResourceRecord *rr = &lcr.r.resrec;
1376 const mDNSu8 *ptr, *end;
1377 struct timeval tv;
1378 DNSQuestion zone;
1379 char buf[MaxMsg];
1380
1381 if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
1382 HdrNToH(pkt);
1383 ptr = pkt->msg.data;
1384 end = (mDNSu8 *)&pkt->msg + pkt->len;
1385 ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
1386 if (!ptr) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup; }
1387 ptr = LocateAuthorities(&pkt->msg, end);
1388 if (!ptr) { Log("UpdateLeaseTable: Format error"); goto cleanup; }
1389
1390 for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
1391 {
1392 mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
1393
1394 ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
1395 if (!ptr || lcr.r.resrec.RecordType == kDNSRecordTypePacketNegative) { Log("UpdateLeaseTable: GetLargeResourceRecord failed"); goto cleanup; }
1396 int bucket = rr->namehash % d->nbuckets;
1397 RRTableElem *tmp, **rptr = &d->table[bucket];
1398
1399 // handle deletions
1400 if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
1401 DeleteAllRRSets = mDNStrue; // delete all rrsets for a name
1402 else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
1403 DeleteOneRRSet = mDNStrue;
1404 else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE)
1405 DeleteOneRR = mDNStrue;
1406
1407 if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR)
1408 {
1409 while (*rptr)
1410 {
1411 if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
1412 (DeleteAllRRSets ||
1413 (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
1414 (DeleteOneRR && IdenticalResourceRecord(&(*rptr)->rr.resrec, rr))))
1415 {
1416 tmp = *rptr;
1417 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
1418 *rptr = (*rptr)->next;
1419 free(tmp);
1420 d->nelems--;
1421 }
1422 else rptr = &(*rptr)->next;
1423 }
1424 }
1425 else if (lease > 0)
1426 {
1427 // see if add or refresh
1428 while (*rptr && !IdenticalResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
1429 if (*rptr)
1430 {
1431 // refresh
1432 if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
1433 (*rptr)->expire = tv.tv_sec + (unsigned)lease;
1434 VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
1435 }
1436 else
1437 {
1438 // New record - add to table
1439 if (d->nelems > d->nbuckets)
1440 {
1441 RehashTable(d);
1442 bucket = rr->namehash % d->nbuckets;
1443 }
1444 if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
1445 allocsize = sizeof(RRTableElem);
1446 if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
1447 tmp = malloc(allocsize);
1448 if (!tmp) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
1449 memcpy(&tmp->rr, &lcr.r, sizeof(CacheRecord) + rr->rdlength - InlineCacheRDSize);
1450 tmp->rr.resrec.rdata = (RData *)&tmp->rr.smallrdatastorage;
1451 AssignDomainName(&tmp->name, rr->name);
1452 tmp->rr.resrec.name = &tmp->name;
1453 tmp->expire = tv.tv_sec + (unsigned)lease;
1454 tmp->cli.sin_addr = pkt->src.sin_addr;
1455 AssignDomainName(&tmp->zone, &zone.qname);
1456 tmp->next = d->table[bucket];
1457 d->table[bucket] = tmp;
1458 d->nelems++;
1459 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
1460 }
1461 }
1462 }
1463
1464 cleanup:
1465 pthread_mutex_unlock(&d->tablelock);
1466 HdrHToN(pkt);
1467 }
1468
1469 // Given a successful reply from a server, create a new reply that contains lease information
1470 // Replies are currently not signed !!!KRS change this
1471 mDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
1472 {
1473 PktMsg *const reply = malloc(sizeof(*reply));
1474 mDNSu8 *ptr;
1475 mDNSOpaque16 flags;
1476 (void)d; //unused
1477
1478 if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
1479 flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
1480 flags.b[1] = 0;
1481
1482 InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
1483 reply->src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // unused except for log messages
1484 reply->src.sin_family = AF_INET;
1485 ptr = putUpdateLease(&reply->msg, reply->msg.data, lease);
1486 if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }
1487 reply->len = ptr - (mDNSu8 *)&reply->msg;
1488 HdrHToN(reply);
1489 return reply;
1490 }
1491
1492
1493 // pkt is thread-local, not requiring locking
1494
1495 mDNSlocal PktMsg*
1496 HandleRequest
1497 (
1498 DaemonInfo * self,
1499 PktMsg * request
1500 )
1501 {
1502 PktMsg * reply = NULL;
1503 PktMsg * leaseReply;
1504 PktMsg buf;
1505 char addrbuf[32];
1506 TCPSocket * sock = NULL;
1507 mStatus err;
1508 mDNSu32 lease = 0;
1509 mDNSBool gotlease;
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 gotlease = GetPktLease(&mDNSStorage, &request->msg, end, &lease);
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 && !gotlease)
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 unsigned int i;
2319 int err = -1;
2320 char addr[32];
2321 const mDNSu8 *qptr = pkt->msg.data;
2322 const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
2323 const mDNSu8 *aptr;
2324 LLQOptData *llq = NULL;
2325 LLQEntry *e = NULL;
2326
2327 HdrNToH(pkt);
2328 aptr = LocateAdditionals(&pkt->msg, end); // Can't do this until after HdrNToH(pkt);
2329 inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
2330
2331 VLog("Received LLQ msg from %s", addr);
2332 // sanity-check packet
2333 if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
2334 {
2335 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
2336 goto end;
2337 }
2338
2339 // Locate the OPT record.
2340 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2341 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2342 // but not necessarily the *last* entry in the Additional Section.
2343 for (i = 0; i < pkt->msg.h.numAdditionals; i++)
2344 {
2345 aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
2346 if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %u", addr, i); goto end; }
2347 if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
2348 }
2349
2350 // validate OPT
2351 if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; }
2352 if (opt.r.resrec.rdlength < pkt->msg.h.numQuestions * DNSOpt_LLQData_Space) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr, opt.r.resrec.rdlength, pkt->msg.h.numQuestions); }
2353
2354 // dispatch each question
2355 for (i = 0; i < pkt->msg.h.numQuestions; i++)
2356 {
2357 qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
2358 if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %u", addr, i); goto end; }
2359 llq = &opt.r.resrec.rdata->u.opt[i].u.llq; // point into OptData at index i
2360 if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
2361
2362 e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id);
2363 if (!e)
2364 {
2365 // no entry - if zero ID, create new
2366 e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->llqlease );
2367 if (!e) goto end;
2368 }
2369 UpdateLLQ(d, e, llq, pkt->msg.h.id, sock);
2370 }
2371 err = 0;
2372
2373 end:
2374 HdrHToN(pkt);
2375 return err;
2376 }
2377
2378
2379 mDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo ** key, mDNSu16 * rcode, mDNSu16 * tcode )
2380 {
2381 const mDNSu8 * lastPtr = NULL;
2382 const mDNSu8 * ptr = NULL;
2383 DomainAuthInfo * keys;
2384 mDNSu8 * end = ( mDNSu8* ) &pkt->msg + pkt->len;
2385 LargeCacheRecord lcr;
2386 mDNSBool hasTSIG = mDNSfalse;
2387 mDNSBool strip = mDNSfalse;
2388 mDNSBool ok = mDNSfalse;
2389 int i;
2390
2391 // Unused parameters
2392
2393 ( void ) d;
2394
2395 HdrNToH(pkt);
2396
2397 *key = NULL;
2398 bzero(&lcr, sizeof(lcr));
2399
2400 if ( pkt->msg.h.numAdditionals )
2401 {
2402 ptr = LocateAdditionals(&pkt->msg, end);
2403 if (ptr)
2404 {
2405 for (i = 0; i < pkt->msg.h.numAdditionals; i++)
2406 {
2407 lastPtr = ptr;
2408 ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
2409 if (!ptr)
2410 {
2411 Log("Unable to read additional record");
2412 lastPtr = NULL;
2413 break;
2414 }
2415 }
2416
2417 hasTSIG = ( ptr && lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rrtype == kDNSType_TSIG );
2418 }
2419 else
2420 {
2421 LogMsg( "IsAuthorized: unable to find Additional section" );
2422 }
2423 }
2424
2425 // If we don't know what zone this is, then it's authorized.
2426
2427 if ( !pkt->zone )
2428 {
2429 ok = mDNStrue;
2430 strip = mDNSfalse;
2431 goto exit;
2432 }
2433
2434 if ( IsQuery( pkt ) )
2435 {
2436 keys = pkt->zone->queryKeys;
2437 strip = mDNStrue;
2438 }
2439 else if ( IsUpdate( pkt ) )
2440 {
2441 keys = pkt->zone->updateKeys;
2442 strip = mDNSfalse;
2443 }
2444 else
2445 {
2446 ok = mDNStrue;
2447 strip = mDNSfalse;
2448 goto exit;
2449 }
2450
2451 if ( pkt->isZonePublic )
2452 {
2453 ok = mDNStrue;
2454 goto exit;
2455 }
2456
2457 // If there are no keys, then we're authorized
2458
2459 if ( ( hasTSIG && !keys ) || ( !hasTSIG && keys ) )
2460 {
2461 Log( "Invalid TSIG spec %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
2462 *rcode = kDNSFlag1_RC_NotAuth;
2463 *tcode = TSIG_ErrBadKey;
2464 strip = mDNStrue;
2465 ok = mDNSfalse;
2466 goto exit;
2467 }
2468
2469 // Find the right key
2470
2471 for ( *key = keys; *key; *key = (*key)->next )
2472 {
2473 if ( SameDomainName( lcr.r.resrec.name, &(*key)->keyname ) )
2474 {
2475 break;
2476 }
2477 }
2478
2479 if ( !(*key) )
2480 {
2481 Log( "Invalid TSIG name %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
2482 *rcode = kDNSFlag1_RC_NotAuth;
2483 *tcode = TSIG_ErrBadKey;
2484 strip = mDNStrue;
2485 ok = mDNSfalse;
2486 goto exit;
2487 }
2488
2489 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2490 // lifting of message verification
2491
2492 pkt->msg.h.numAdditionals--;
2493
2494 HdrHToN( pkt );
2495
2496 ok = DNSDigest_VerifyMessage( &pkt->msg, ( mDNSu8* ) lastPtr, &lcr, (*key), rcode, tcode );
2497
2498 HdrNToH( pkt );
2499
2500 pkt->msg.h.numAdditionals++;
2501
2502 exit:
2503
2504 if ( hasTSIG && strip )
2505 {
2506 // Strip the TSIG from the message
2507
2508 pkt->msg.h.numAdditionals--;
2509 pkt->len = lastPtr - ( mDNSu8* ) ( &pkt->msg );
2510 }
2511
2512 HdrHToN(pkt);
2513
2514 return ok;
2515 }
2516
2517 // request handler wrappers for TCP and UDP requests
2518 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2519
2520 mDNSlocal void*
2521 UDPMessageHandler
2522 (
2523 void * vptr
2524 )
2525 {
2526 UDPContext * context = ( UDPContext* ) vptr;
2527 PktMsg * reply = NULL;
2528 int res;
2529 mStatus err;
2530
2531 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2532 // may give us a long answer that would require truncation for UDP delivery to client
2533
2534 reply = HandleRequest( context->d, &context->pkt );
2535 require_action( reply, exit, err = mStatus_UnknownErr );
2536
2537 res = sendto( context->sd, &reply->msg, reply->len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
2538 require_action_quiet( res == ( int ) reply->len, exit, LogErr( "UDPMessageHandler", "sendto" ) );
2539
2540 exit:
2541
2542 if ( reply )
2543 {
2544 free( reply );
2545 }
2546
2547 free( context );
2548
2549 pthread_exit( NULL );
2550
2551 return NULL;
2552 }
2553
2554
2555 mDNSlocal int
2556 RecvUDPMessage
2557 (
2558 DaemonInfo * self,
2559 int sd
2560 )
2561 {
2562 UDPContext * context = NULL;
2563 pthread_t tid;
2564 mDNSu16 rcode;
2565 mDNSu16 tcode;
2566 DomainAuthInfo * key;
2567 unsigned int clisize = sizeof( context->cliaddr );
2568 int res;
2569 mStatus err = mStatus_NoError;
2570
2571 context = malloc( sizeof( UDPContext ) );
2572 require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
2573
2574 mDNSPlatformMemZero( context, sizeof( *context ) );
2575 context->d = self;
2576 context->sd = sd;
2577
2578 res = recvfrom(sd, &context->pkt.msg, sizeof(context->pkt.msg), 0, (struct sockaddr *)&context->cliaddr, &clisize);
2579
2580 require_action( res >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvUDPMessage", "recvfrom" ) );
2581 context->pkt.len = res;
2582 require_action( clisize == sizeof( context->cliaddr ), exit, err = mStatus_UnknownErr ; Log( "Client address of unknown size %d", clisize ) );
2583 context->pkt.src = context->cliaddr;
2584
2585 // Set the zone in the packet
2586
2587 SetZone( context->d, &context->pkt );
2588
2589 // Notify messages handled by main thread
2590
2591 if ( IsNotify( &context->pkt ) )
2592 {
2593 int e = RecvNotify( self, &context->pkt );
2594 free(context);
2595 return e;
2596 }
2597 else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
2598 {
2599 if ( IsLLQRequest( &context->pkt ) )
2600 {
2601 // LLQ messages handled by main thread
2602 int e = RecvLLQ( self, &context->pkt, NULL );
2603 free(context);
2604 return e;
2605 }
2606
2607 if ( IsLLQAck(&context->pkt ) )
2608 {
2609 // !!!KRS need to do acks + retrans
2610
2611 free(context);
2612 return 0;
2613 }
2614
2615 err = pthread_create( &tid, NULL, UDPMessageHandler, context );
2616 require_action( !err, exit, LogErr( "RecvUDPMessage", "pthread_create" ) );
2617
2618 pthread_detach(tid);
2619 }
2620 else
2621 {
2622 PktMsg reply;
2623 int e;
2624
2625 memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
2626
2627 reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
2628 reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
2629
2630 e = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
2631 require_action_quiet( e == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
2632
2633 err = mStatus_NoAuth;
2634 }
2635
2636 exit:
2637
2638 if ( err && context )
2639 {
2640 free( context );
2641 }
2642
2643 return err;
2644 }
2645
2646
2647 mDNSlocal void
2648 FreeTCPContext
2649 (
2650 TCPContext * context
2651 )
2652 {
2653 if ( context )
2654 {
2655 if ( context->sock )
2656 {
2657 mDNSPlatformTCPCloseConnection( context->sock );
2658 }
2659
2660 free( context );
2661 }
2662 }
2663
2664
2665 mDNSlocal void*
2666 TCPMessageHandler
2667 (
2668 void * vptr
2669 )
2670 {
2671 TCPContext * context = ( TCPContext* ) vptr;
2672 PktMsg * reply = NULL;
2673 int res;
2674 char buf[32];
2675
2676 //!!!KRS if this read blocks indefinitely, we can run out of threads
2677 // read the request
2678
2679 reply = HandleRequest( context->d, &context->pkt );
2680 require_action_quiet( reply, exit, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
2681
2682 // deliver reply to client
2683
2684 res = SendPacket( context->sock, reply );
2685 require_action( res >= 0, exit, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
2686
2687 exit:
2688
2689 FreeTCPContext( context );
2690
2691 if ( reply )
2692 {
2693 free( reply );
2694 }
2695
2696 pthread_exit(NULL);
2697 }
2698
2699
2700 mDNSlocal void
2701 RecvTCPMessage
2702 (
2703 void * param
2704 )
2705 {
2706 TCPContext * context = ( TCPContext* ) param;
2707 mDNSu16 rcode;
2708 mDNSu16 tcode;
2709 pthread_t tid;
2710 DomainAuthInfo * key;
2711 PktMsg * pkt;
2712 mDNSBool closed;
2713 mDNSBool freeContext = mDNStrue;
2714 mStatus err = mStatus_NoError;
2715
2716 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2717 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2718 // wire. We'll let it do that, and wait for the next packet which will be ours.
2719
2720 pkt = RecvPacket( context->sock, &context->pkt, &closed );
2721 if (pkt) HdrNToH(pkt);
2722 require_action( pkt || !closed, exit, err = mStatus_UnknownErr; LogMsg( "client disconnected" ) );
2723
2724 if ( pkt )
2725 {
2726 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2727 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2728 // are sent over UDP
2729
2730 RemoveSourceFromEventLoop( context->d, context->sock );
2731
2732 // Set's the DNS Zone that is associated with this message
2733
2734 SetZone( context->d, &context->pkt );
2735
2736 // IsAuthorized will make sure the message is authorized for the designated zone.
2737 // After verifying the signature, it will strip the TSIG from the message
2738
2739 if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
2740 {
2741 if ( IsLLQRequest( &context->pkt ) )
2742 {
2743 // LLQ messages handled by main thread
2744 RecvLLQ( context->d, &context->pkt, context->sock);
2745 }
2746 else
2747 {
2748 err = pthread_create( &tid, NULL, TCPMessageHandler, context );
2749
2750 if ( err )
2751 {
2752 LogErr( "RecvTCPMessage", "pthread_create" );
2753 err = mStatus_NoError;
2754 goto exit;
2755 }
2756
2757 // Let the thread free the context
2758
2759 freeContext = mDNSfalse;
2760
2761 pthread_detach(tid);
2762 }
2763 }
2764 else
2765 {
2766 PktMsg reply;
2767
2768 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context->pkt.src.sin_addr ), pkt->zone->name.c );
2769
2770 memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
2771
2772 reply.msg.h.flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
2773 reply.msg.h.flags.b[1] = kDNSFlag1_RA | kDNSFlag1_RC_Refused;
2774
2775 SendPacket( context->sock, &reply );
2776 }
2777 }
2778 else
2779 {
2780 freeContext = mDNSfalse;
2781 }
2782
2783 exit:
2784
2785 if ( err )
2786 {
2787 RemoveSourceFromEventLoop( context->d, context->sock );
2788 }
2789
2790 if ( freeContext )
2791 {
2792 FreeTCPContext( context );
2793 }
2794 }
2795
2796
2797 mDNSlocal int
2798 AcceptTCPConnection
2799 (
2800 DaemonInfo * self,
2801 int sd,
2802 TCPSocketFlags flags
2803 )
2804 {
2805 TCPContext * context = NULL;
2806 unsigned int clilen = sizeof( context->cliaddr);
2807 int newSock;
2808 mStatus err = mStatus_NoError;
2809
2810 context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
2811 require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
2812 mDNSPlatformMemZero( context, sizeof( sizeof( TCPContext ) ) );
2813 context->d = self;
2814 newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen );
2815 require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) );
2816
2817 context->sock = mDNSPlatformTCPAccept( flags, newSock );
2818 require_action( context->sock, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2819
2820 err = AddSourceToEventLoop( self, context->sock, RecvTCPMessage, context );
2821 require_action( !err, exit, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2822
2823 exit:
2824
2825 if ( err && context )
2826 {
2827 free( context );
2828 context = NULL;
2829 }
2830
2831 return err;
2832 }
2833
2834
2835 // main event loop
2836 // listen for incoming requests, periodically check table for expired records, respond to signals
2837 mDNSlocal int Run(DaemonInfo *d)
2838 {
2839 int staticMaxFD, nfds;
2840 fd_set rset;
2841 struct timeval timenow, timeout, EventTS, tablecheck = { 0, 0 };
2842 mDNSBool EventsPending = mDNSfalse;
2843
2844 VLog("Listening for requests...");
2845
2846 staticMaxFD = 0;
2847
2848 if ( d->tcpsd + 1 > staticMaxFD ) staticMaxFD = d->tcpsd + 1;
2849 if ( d->udpsd + 1 > staticMaxFD ) staticMaxFD = d->udpsd + 1;
2850 if ( d->tlssd + 1 > staticMaxFD ) staticMaxFD = d->tlssd + 1;
2851 if ( d->llq_tcpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_tcpsd + 1;
2852 if ( d->llq_udpsd + 1 > staticMaxFD ) staticMaxFD = d->llq_udpsd + 1;
2853 if ( d->LLQEventListenSock + 1 > staticMaxFD ) staticMaxFD = d->LLQEventListenSock + 1;
2854
2855 while(1)
2856 {
2857 EventSource * source;
2858 int maxFD;
2859
2860 // set timeout
2861 timeout.tv_sec = timeout.tv_usec = 0;
2862 if (gettimeofday(&timenow, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
2863
2864 if (EventsPending)
2865 {
2866 if (timenow.tv_sec - EventTS.tv_sec >= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2867 { GenLLQEvents(d); EventsPending = mDNSfalse; } // events, we go ahead and do it now
2868 else timeout.tv_usec = 500000; // else do events after 1/2 second with no new events or LLQs
2869 }
2870 if (!EventsPending)
2871 {
2872 // if no pending events, timeout when we need to check for expired records
2873 if (tablecheck.tv_sec && timenow.tv_sec - tablecheck.tv_sec >= 0)
2874 { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; } // table check overdue
2875 if (!tablecheck.tv_sec) tablecheck.tv_sec = timenow.tv_sec + EXPIRATION_INTERVAL;
2876 timeout.tv_sec = tablecheck.tv_sec - timenow.tv_sec;
2877 }
2878
2879 FD_ZERO(&rset);
2880 FD_SET( d->tcpsd, &rset );
2881 FD_SET( d->udpsd, &rset );
2882 FD_SET( d->tlssd, &rset );
2883 FD_SET( d->llq_tcpsd, &rset );
2884 FD_SET( d->llq_udpsd, &rset );
2885 FD_SET( d->LLQEventListenSock, &rset );
2886
2887 maxFD = staticMaxFD;
2888
2889 for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
2890 {
2891 FD_SET( source->fd, &rset );
2892
2893 if ( source->fd > maxFD )
2894 {
2895 maxFD = source->fd;
2896 }
2897 }
2898
2899 nfds = select( maxFD + 1, &rset, NULL, NULL, &timeout);
2900 if (nfds < 0)
2901 {
2902 if (errno == EINTR)
2903 {
2904 if (terminate)
2905 {
2906 // close sockets to prevent clients from making new requests during shutdown
2907 close( d->tcpsd );
2908 close( d->udpsd );
2909 close( d->tlssd );
2910 close( d->llq_tcpsd );
2911 close( d->llq_udpsd );
2912 d->tcpsd = d->udpsd = d->tlssd = d->llq_tcpsd = d->llq_udpsd = -1;
2913 DeleteRecords(d, mDNStrue);
2914 return 0;
2915 }
2916 else if (dumptable)
2917 {
2918 Log( "Received SIGINFO" );
2919
2920 PrintLeaseTable(d);
2921 PrintLLQTable(d);
2922 PrintLLQAnswers(d);
2923 dumptable = 0;
2924 }
2925 else if (hangup)
2926 {
2927 int err;
2928
2929 Log( "Received SIGHUP" );
2930
2931 err = ParseConfig( d, cfgfile );
2932
2933 if ( err )
2934 {
2935 LogErr( "Run", "ParseConfig" );
2936 return -1;
2937 }
2938
2939 hangup = 0;
2940 }
2941 else
2942 {
2943 Log("Received unhandled signal - continuing");
2944 }
2945 }
2946 else
2947 {
2948 LogErr("Run", "select"); return -1;
2949 }
2950 }
2951 else if (nfds)
2952 {
2953 if (FD_ISSET(d->udpsd, &rset)) RecvUDPMessage( d, d->udpsd );
2954 if (FD_ISSET(d->llq_udpsd, &rset)) RecvUDPMessage( d, d->llq_udpsd );
2955 if (FD_ISSET(d->tcpsd, &rset)) AcceptTCPConnection( d, d->tcpsd, 0 );
2956 if (FD_ISSET(d->llq_tcpsd, &rset)) AcceptTCPConnection( d, d->llq_tcpsd, 0 );
2957 if (FD_ISSET(d->tlssd, &rset)) AcceptTCPConnection( d, d->tlssd, TCP_SOCKET_FLAGS );
2958 if (FD_ISSET(d->LLQEventListenSock, &rset))
2959 {
2960 // clear signalling data off socket
2961 char buf[256];
2962 recv(d->LLQEventListenSock, buf, 256, 0);
2963 if (!EventsPending)
2964 {
2965 EventsPending = mDNStrue;
2966 if (gettimeofday(&EventTS, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
2967 }
2968 }
2969
2970 for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
2971 {
2972 if ( FD_ISSET( source->fd, &rset ) )
2973 {
2974 source->callback( source->context );
2975 break; // in case we removed this guy from the event loop
2976 }
2977 }
2978 }
2979 else
2980 {
2981 // timeout
2982 if (EventsPending) { GenLLQEvents(d); EventsPending = mDNSfalse; }
2983 else { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; }
2984 }
2985 }
2986 return 0;
2987 }
2988
2989 // signal handler sets global variables, which are inspected by main event loop
2990 // (select automatically returns due to the handled signal)
2991 mDNSlocal void HndlSignal(int sig)
2992 {
2993 if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
2994 if (sig == INFO_SIGNAL) { dumptable = 1; return; }
2995 if (sig == SIGHUP) { hangup = 1; return; }
2996 }
2997
2998 mDNSlocal mStatus
2999 SetPublicSRV
3000 (
3001 DaemonInfo * d,
3002 const char * name
3003 )
3004 {
3005 DNameListElem * elem;
3006 mStatus err = mStatus_NoError;
3007
3008 elem = ( DNameListElem* ) malloc( sizeof( DNameListElem ) );
3009 require_action( elem, exit, err = mStatus_NoMemoryErr );
3010 MakeDomainNameFromDNSNameString( &elem->name, name );
3011 elem->next = d->public_names;
3012 d->public_names = elem;
3013
3014 exit:
3015
3016 return err;
3017 }
3018
3019
3020 int main(int argc, char *argv[])
3021 {
3022 int started_via_launchd = 0;
3023 DaemonInfo *d;
3024 struct rlimit rlim;
3025
3026 Log("dnsextd starting");
3027
3028 d = malloc(sizeof(*d));
3029 if (!d) { LogErr("main", "malloc"); exit(1); }
3030 mDNSPlatformMemZero(d, sizeof(DaemonInfo));
3031
3032 // Setup the public SRV record names
3033
3034 SetPublicSRV(d, "_dns-update._udp.");
3035 SetPublicSRV(d, "_dns-llq._udp.");
3036 SetPublicSRV(d, "_dns-update-tls._tcp.");
3037 SetPublicSRV(d, "_dns-query-tls._tcp.");
3038 SetPublicSRV(d, "_dns-llq-tls._tcp.");
3039
3040 // Setup signal handling
3041
3042 if (signal(SIGHUP, HndlSignal) == SIG_ERR) perror("Can't catch SIGHUP");
3043 if (signal(SIGTERM, HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
3044 if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
3045 if (signal(SIGINT, HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
3046 if (signal(SIGPIPE, SIG_IGN ) == SIG_ERR) perror("Can't ignore SIGPIPE");
3047
3048 // remove open file limit
3049 rlim.rlim_max = RLIM_INFINITY;
3050 rlim.rlim_cur = RLIM_INFINITY;
3051 if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
3052 {
3053 LogErr("main", "setrlimit");
3054 Log("Using default file descriptor resource limit");
3055 }
3056
3057 if (argc > 1 && !strcasecmp(argv[1], "-launchd"))
3058 {
3059 Log("started_via_launchd");
3060 started_via_launchd = 1;
3061 argv++;
3062 argc--;
3063 }
3064 if (ProcessArgs(argc, argv, d) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3065
3066 if (!foreground && !started_via_launchd)
3067 {
3068 if (daemon(0,0))
3069 {
3070 LogErr("main", "daemon");
3071 foreground = 1;
3072 }
3073 }
3074
3075 if (InitLeaseTable(d) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3076 if (SetupSockets(d) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3077 if (SetUpdateSRV(d) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3078
3079 Run(d);
3080
3081 Log("dnsextd stopping");
3082
3083 if (ClearUpdateSRV(d) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3084 free(d);
3085 exit(0);
3086 }
3087
3088
3089 // These are stubbed out implementations of up-call routines that the various platform support layers
3090 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3091 // link this code in.
3092 //
3093 // It's an error for these routines to actually be called, so perhaps we should log any call
3094 // to them.
3095 void mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
3096 void mDNS_ConfigChanged(mDNS *const m) { ( void ) m; }
3097 void mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
3098 void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
3099 const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
3100 const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
3101 { ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
3102 DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const int serviceID, const mDNSAddr *addr, const mDNSIPPort port,
3103 mDNSu32 scopedType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46, mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
3104 { ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scopedType; ( void ) timeout; (void) isCell; (void) isExpensive; (void) isConstrained; (void) isCLAT46;
3105 (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
3106 void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
3107 void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
3108 { ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
3109 mDNSs32 mDNS_Execute (mDNS *const m) { ( void ) m; return 0; }
3110 mDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
3111 mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3112 void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
3113 { ( void ) m; ( void ) set; ( void ) activationSpeed; }
3114 const char * const mDNS_DomainTypeNames[1] = {};
3115 mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
3116 const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
3117 { ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
3118 mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
3119 mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, InterfaceActivationSpeed activationSpeed)
3120 { ( void ) m; ( void ) set; ( void ) activationSpeed; return 0; }
3121 void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
3122 void mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
3123 void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router)
3124 { ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
3125 mStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
3126 mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
3127 const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
3128 { ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; return 0; }
3129 mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
3130 void TriggerEventCompletion(void);
3131 void TriggerEventCompletion() {}
3132 mDNS mDNSStorage;
3133
3134
3135 // For convenience when using the "strings" command, this is the last thing in the file
3136 // The "@(#) " pattern is a special prefix the "what" command looks for
3137 const char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
3138
3139 #if _BUILDING_XCODE_PROJECT_
3140 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3141 const char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
3142 asm (".desc ___crashreporter_info__, 0x10");
3143 #endif