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