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