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