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