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