1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 Change History (most recent first):
20 Revision 1.97 2009/01/13 05:31:34 mkrochma
21 <rdar://problem/6491367> Replace bzero, bcopy with mDNSPlatformMemZero, mDNSPlatformMemCopy, memset, memcpy
23 Revision 1.96 2009/01/13 00:45:41 cheshire
24 Uncommented "#ifdef NOT_HAVE_DAEMON" check
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)
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
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.
36 Revision 1.92 2008/11/13 19:09:36 cheshire
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
43 Revision 1.90 2008/10/03 18:18:57 cheshire
44 Define dummy "mDNS_ConfigChanged(mDNS *const m)" routine to avoid link errors
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
50 Revision 1.88 2008/03/06 21:26:11 cheshire
51 Moved duplicated STRINGIFY macro from individual C files to DNSCommon.h
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)
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.
60 Revision 1.85 2007/12/01 00:30:36 cheshire
61 Fixed compile warning: declaration of 'time' shadows a global declaration
63 Revision 1.84 2007/10/24 18:19:37 cheshire
64 Fixed header byte order bug sending update responses
66 Revision 1.83 2007/10/17 22:52:26 cheshire
67 Get rid of unused mDNS_UpdateLLQs()
69 Revision 1.82 2007/09/27 17:42:49 cheshire
70 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
72 Revision 1.81 2007/09/21 21:12:37 cheshire
73 DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
75 Revision 1.80 2007/09/18 19:09:02 cheshire
76 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
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
82 Revision 1.78 2007/06/20 01:10:13 cheshire
83 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
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
89 Revision 1.76 2007/05/01 23:53:26 cheshire
90 <rdar://problem/5175318> dnsextd should refuse updates without attached lease
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)
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.)
101 Revision 1.73 2007/04/22 06:02:03 cheshire
102 <rdar://problem/4615977> Query should immediately return failure when no server
104 Revision 1.72 2007/04/05 22:55:37 cheshire
105 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
107 Revision 1.71 2007/04/05 19:43:56 cheshire
108 Added ProgramName and comment about '-d' option
110 Revision 1.70 2007/04/05 18:34:40 cheshire
111 <rdar://problem/4838930> dnsextd gives "bind - Address already in use" error
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
116 Revision 1.68 2007/03/28 18:20:50 cheshire
119 Revision 1.67 2007/03/21 00:30:07 cheshire
120 <rdar://problem/4789455> Multiple errors in DNameList-related code
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"
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
128 Revision 1.64 2007/01/20 01:43:26 cheshire
129 <rdar://problem/4058383> Should not write log messages to /dev/console
131 Revision 1.63 2007/01/20 01:31:56 cheshire
134 Revision 1.62 2007/01/17 22:06:03 cheshire
135 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
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)
141 Revision 1.60 2007/01/05 08:07:29 cheshire
142 Remove unnecessary dummy udsserver_default_reg_domain_changed() routine
144 Revision 1.59 2007/01/05 05:46:47 cheshire
145 Remove unnecessary dummy udsserver_automatic_browse_domain_changed() routine
147 Revision 1.58 2007/01/04 23:11:54 cheshire
148 udsserver_default_browse_domain_changed renamed to udsserver_automatic_browse_domain_changed
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
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
157 Revision 1.55 2006/11/30 23:08:39 herscher
158 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
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
164 Revision 1.53 2006/11/17 23:55:09 cheshire
165 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
167 Revision 1.52 2006/11/17 04:27:51 cheshire
168 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
170 Revision 1.51 2006/11/17 03:50:18 cheshire
171 Add debugging loggin in SendPacket and UDPServerTransaction
173 Revision 1.50 2006/11/17 03:48:57 cheshire
174 <rdar://problem/4842493> dnsextd replying on wrong port
176 Revision 1.49 2006/11/03 06:12:44 herscher
177 Make sure all buffers passed to GetRRDisplayString_rdb are of length MaxMsg
179 Revision 1.48 2006/10/20 19:18:35 cheshire
180 <rdar://problem/4669228> dnsextd generates bogus SRV record with null target
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
185 Revision 1.46 2006/10/11 22:56:07 herscher
186 Tidy up the implementation of ZoneHandlesName
188 Revision 1.45 2006/08/22 03:28:57 herscher
189 <rdar://problem/4678717> Long-lived queries aren't working well in TOT.
191 Revision 1.44 2006/08/14 23:24:56 cheshire
192 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
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
198 Revision 1.42 2006/07/05 22:48:19 cheshire
199 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
204 #include "../mDNSShared/uds_daemon.h"
205 #include "../mDNSShared/dnssd_ipc.h"
206 #include "../mDNSCore/uDNS.h"
207 #include "../mDNSShared/DebugServices.h"
212 #include <sys/types.h>
213 #include <sys/socket.h>
214 #include <netinet/in.h>
215 #include <arpa/inet.h>
219 #include <sys/time.h>
220 #include <sys/resource.h>
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
229 // Compatibility workaround
231 #define AF_LOCAL AF_UNIX
237 mDNSexport
const char ProgramName
[] = "dnsextd";
239 #define LOOPBACK "127.0.0.1"
240 #if !defined(LISTENQ)
241 # define LISTENQ 128 // tcp connection backlog
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
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
255 // LLQ SOA poll interval (microseconds)
256 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
257 #define LLQ_MONITOR_INTERVAL 250000
259 #define INFO_SIGNAL SIGINFO
261 #define INFO_SIGNAL SIGUSR1
264 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
268 // Structs/fields that must be locked for thread safety are explicitly commented
271 // args passed to UDP request handler thread as void*
276 struct sockaddr_in cliaddr
;
281 // args passed to TCP request handler thread as void*
285 struct sockaddr_in cliaddr
;
286 TCPSocket
*sock
; // socket connected to client
290 // args passed to UpdateAnswerList thread as void*
295 } UpdateAnswerListArgs
;
301 // booleans to determine runtime output
302 // read-only after initialization (no mutex protection)
303 static mDNSBool foreground
= 0;
304 static mDNSBool verbose
= 0;
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;
311 // global for config file location
312 static char * cfgfile
= NULL
;
316 // Log messages are delivered to syslog unless -f option specified
319 // common message logging subroutine
320 mDNSlocal
void PrintLog(const char *buffer
)
324 fprintf(stderr
,"%s\n", buffer
);
329 openlog("dnsextd", LOG_CONS
, LOG_DAEMON
);
330 syslog(LOG_ERR
, "%s", buffer
);
335 // Verbose Logging (conditional on -v option)
336 mDNSlocal
void VLog(const char *format
, ...)
341 if (!verbose
) return;
342 va_start(ptr
,format
);
343 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
348 // Unconditional Logging
349 mDNSlocal
void Log(const char *format
, ...)
354 va_start(ptr
,format
);
355 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
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
)
365 char buf
[512], errbuf
[256];
366 strerror_r(errno
, errbuf
, sizeof(errbuf
));
367 snprintf(buf
, sizeof(buf
), "%s: %s - %s", fn
, operation
, errbuf
);
372 // Networking Utility Routines
375 // Convert DNS Message Header from Network to Host byte order
376 mDNSlocal
void HdrNToH(PktMsg
*pkt
)
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]);
386 // Convert DNS Message Header from Host to Network byte order
387 mDNSlocal
void HdrHToN(PktMsg
*pkt
)
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
;
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);
407 // Add socket to event loop
409 mDNSlocal mStatus
AddSourceToEventLoop( DaemonInfo
* self
, TCPSocket
*sock
, EventCallback callback
, void *context
)
411 EventSource
* newSource
;
412 mStatus err
= mStatus_NoError
;
414 if ( self
->eventSources
.LinkOffset
== 0 )
416 InitLinkedList( &self
->eventSources
, offsetof( EventSource
, next
));
419 newSource
= ( EventSource
*) malloc( sizeof *newSource
);
420 if ( newSource
== NULL
)
422 err
= mStatus_NoMemoryErr
;
426 newSource
->callback
= callback
;
427 newSource
->context
= context
;
428 newSource
->sock
= sock
;
429 newSource
->fd
= mDNSPlatformTCPGetFD( sock
);
431 AddToTail( &self
->eventSources
, newSource
);
439 // Remove socket from event loop
441 mDNSlocal mStatus
RemoveSourceFromEventLoop( DaemonInfo
* self
, TCPSocket
*sock
)
443 EventSource
* source
;
446 for ( source
= ( EventSource
* ) self
->eventSources
.Head
; source
; source
= source
->next
)
448 if ( source
->sock
== sock
)
450 RemoveFromList( &self
->eventSources
, source
);
453 err
= mStatus_NoError
;
458 err
= mStatus_NoSuchNameErr
;
465 // create a socket connected to nameserver
466 // caller terminates connection via close()
467 mDNSlocal TCPSocket
*ConnectToServer(DaemonInfo
*d
)
469 int ntries
= 0, retry
= 0;
473 mDNSIPPort port
= zeroIPPort
;
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
);
483 LogErr("ConnectToServer", "connect");
484 Log("ConnectToServer - retrying connection");
485 if (!retry
) retry
= 500000 + random() % 500000;
489 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries
); return NULL
; }
493 // send an entire block of data over a connected socket
494 mDNSlocal
int MySend(TCPSocket
*sock
, const void *msg
, int len
)
496 int selectval
, n
, nsent
= 0;
498 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
506 fd
= mDNSPlatformTCPGetFD( sock
);
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; }
513 n
= mDNSPlatformWriteTCP( sock
, ( char* ) msg
+ nsent
, len
- nsent
);
515 if (n
< 0) { LogErr("MySend", "send"); return -1; }
521 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
522 mDNSlocal
int SendPacket(TCPSocket
*sock
, PktMsg
*pkt
)
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;
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
);
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
)
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.
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
;
556 fd
= mDNSPlatformTCPGetFD( sock
);
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
))
564 Log("my_recv - timeout");
568 num_read
= mDNSPlatformReadTCP( sock
, ptr
, remaining
, closed
);
570 if (((num_read
== 0) && *closed
) || (num_read
< 0) || (num_read
> remaining
)) return -1;
571 if (num_read
== 0) return 0;
573 remaining
-= num_read
;
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
599 fd
= mDNSPlatformTCPGetFD( sock
);
601 nread
= my_recv( sock
, &msglen
, sizeof( msglen
), closed
);
603 require_action_quiet( nread
!= -1, exit
, err
= mStatus_UnknownErr
);
604 require_action_quiet( nread
> 0, exit
, err
= mStatus_NoError
);
606 msglen
= ntohs( msglen
);
607 require_action_quiet( nread
== sizeof( msglen
), exit
, err
= mStatus_UnknownErr
; Log( "Could not read length field of message") );
611 require_action_quiet( msglen
<= sizeof( storage
->msg
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: provided buffer too small." ) );
616 // buffer extra space to add an OPT RR
618 if ( msglen
> sizeof(DNSMessage
))
620 allocsize
= sizeof(PktMsg
) - sizeof(DNSMessage
) + msglen
;
624 allocsize
= sizeof(PktMsg
);
627 pkt
= malloc(allocsize
);
628 require_action_quiet( pkt
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvPacket", "malloc" ) );
629 mDNSPlatformMemZero( pkt
, sizeof( *pkt
) );
633 srclen
= sizeof(pkt
->src
);
635 if ( getpeername( fd
, ( struct sockaddr
* ) &pkt
->src
, &srclen
) || ( srclen
!= sizeof( pkt
->src
) ) )
637 LogErr("RecvPacket", "getpeername");
638 mDNSPlatformMemZero(&pkt
->src
, sizeof(pkt
->src
));
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
) );
650 if ( pkt
!= storage
)
671 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
673 if ( SameDomainName( &zone
->name
, name
) )
686 const domainname
* zname
,
687 const domainname
* dname
690 mDNSu16 i
= DomainNameLength( zname
);
691 mDNSu16 j
= DomainNameLength( dname
);
693 if ( ( i
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( j
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( i
> j
) || ( memcmp( zname
->c
, dname
->c
+ ( j
- i
), i
) != 0 ) )
702 mDNSlocal mDNSBool
IsQuery( PktMsg
* pkt
)
704 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
);
708 mDNSlocal mDNSBool
IsUpdate( PktMsg
* pkt
)
710 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_OP_Update
);
714 mDNSlocal mDNSBool
IsNotify(PktMsg
*pkt
)
716 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( mDNSu8
) ( kDNSFlag0_OP_Notify
);
720 mDNSlocal mDNSBool
IsLLQRequest(PktMsg
*pkt
)
722 const mDNSu8
*ptr
= NULL
, *end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
723 LargeCacheRecord lcr
;
725 mDNSBool result
= mDNSfalse
;
728 if ((mDNSu8
)(pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (mDNSu8
)(kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
)) goto end
;
730 if (!pkt
->msg
.h
.numAdditionals
) goto end
;
731 ptr
= LocateAdditionals(&pkt
->msg
, end
);
734 // find last Additional info.
735 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
737 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
738 if (!ptr
) { Log("Unable to read additional record"); goto end
; }
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
)
751 // !!!KRS implement properly
752 mDNSlocal mDNSBool
IsLLQAck(PktMsg
*pkt
)
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
;
767 DNameListElem
* elem
;
768 mDNSBool ret
= mDNSfalse
;
769 int i
= ( int ) DomainNameLength( &q
->qname
) - 1;
771 for ( elem
= self
->public_names
; elem
; elem
= elem
->next
)
773 int j
= ( int ) DomainNameLength( &elem
->name
) - 1;
777 for ( ; i
>= 0; i
--, j
-- )
779 if ( q
->qname
.c
[ i
] != elem
->name
.c
[ j
] )
803 const mDNSu8
* ptr
= pkt
->msg
.data
;
804 mDNSBool exception
= mDNSfalse
;
809 pkt
->isZonePublic
= mDNStrue
;
812 // Figure out what type of packet this is
814 QR_OP
= ( mDNSu8
) ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
816 if ( IsQuery( pkt
) )
818 DNSQuestion question
;
822 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
824 AppendDomainName( &zname
, &question
.qname
);
826 exception
= ( ( question
.qtype
== kDNSType_SOA
) || ( question
.qtype
== kDNSType_NS
) || ( ( question
.qtype
== kDNSType_SRV
) && IsPublicSRV( self
, &question
) ) );
828 else if ( IsUpdate( pkt
) )
830 DNSQuestion question
;
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.
835 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
837 AppendDomainName( &zname
, &question
.qname
);
839 exception
= mDNSfalse
;
842 if ( zname
.c
[0] != '\0' )
844 // Find the right zone
846 for ( pkt
->zone
= self
->zones
; pkt
->zone
; pkt
->zone
= pkt
->zone
->next
)
848 if ( ZoneHandlesName( &pkt
->zone
->name
, &zname
) )
850 VLog( "found correct zone %##s for query", pkt
->zone
->name
.c
);
852 pkt
->isZonePublic
= ( ( pkt
->zone
->type
== kDNSZonePublic
) || exception
);
854 VLog( "zone %##s is %s", pkt
->zone
->name
.c
, ( pkt
->isZonePublic
) ? "public" : "private" );
864 UDPServerTransaction(const DaemonInfo
*d
, const PktMsg
*request
, PktMsg
*reply
, mDNSBool
*trunc
)
867 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
870 mStatus err
= mStatus_NoError
;
878 sd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
879 require_action( sd
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "socket" ) );
881 // Send the packet to the nameserver
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" ) );
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" ) );
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
) );
905 // Check for truncation bit
907 if ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_TC
)
923 // Dynamic Update Utility Routines
926 // check if a request and server response complete a successful dynamic update
927 mDNSlocal mDNSBool
SuccessfulUpdateTransaction(PktMsg
*request
, PktMsg
*reply
)
930 char *vlogmsg
= NULL
;
933 if (!request
|| !reply
) { vlogmsg
= "NULL message"; goto failure
; }
934 if (request
->len
< sizeof(DNSMessageHeader
) || reply
->len
< sizeof(DNSMessageHeader
)) { vlogmsg
= "Malformatted message"; goto failure
; }
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
; }
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
; }
945 VLog("Successful update from %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32));
949 VLog("Request %s: %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32), vlogmsg
);
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
956 mDNSlocal CacheRecord
*CopyCacheRecord(const CacheRecord
*orig
, domainname
*name
)
959 size_t size
= sizeof(*cr
);
960 if (orig
->resrec
.rdlength
> InlineCacheRDSize
) size
+= orig
->resrec
.rdlength
- InlineCacheRDSize
;
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
;
972 // Lease Hashtable Utility Routines
975 // double hash table size
976 // caller must lock table prior to invocation
977 mDNSlocal
void RehashTable(DaemonInfo
*d
)
979 RRTableElem
*ptr
, *tmp
, **new;
980 int i
, bucket
, newnbuckets
= d
->nbuckets
* 2;
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
*));
987 for (i
= 0; i
< d
->nbuckets
; i
++)
992 bucket
= ptr
->rr
.resrec
.namehash
% newnbuckets
;
995 tmp
->next
= new[bucket
];
999 d
->nbuckets
= newnbuckets
;
1004 // print entire contents of hashtable, invoked via SIGINFO
1005 mDNSlocal
void PrintLeaseTable(DaemonInfo
*d
)
1009 char rrbuf
[MaxMsg
], addrbuf
[16];
1013 if (gettimeofday(&now
, NULL
)) { LogErr("PrintTable", "gettimeofday"); return; }
1014 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
1016 Log("Dumping Lease Table Contents (table contains %d resource records)", d
->nelems
);
1017 for (i
= 0; i
< d
->nbuckets
; i
++)
1019 for (ptr
= d
->table
[i
]; ptr
; ptr
= ptr
->next
)
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
));
1028 pthread_mutex_unlock(&d
->tablelock
);
1032 // Startup SRV Registration Routines
1033 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
1034 // the daemon accepts requests
1037 // delete all RRS of a given name/type
1038 mDNSlocal mDNSu8
*putRRSetDeletion(DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
, ResourceRecord
*rr
)
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
++;
1051 mDNSlocal mDNSu8
*PutUpdateSRV(DaemonInfo
*d
, DNSZone
* zone
, PktMsg
*pkt
, mDNSu8
*ptr
, char *regtype
, mDNSIPPort port
, mDNSBool registration
)
1054 char hostname
[1024], buf
[MaxMsg
];
1055 mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ sizeof(DNSMessage
);
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';
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
);
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
)
1081 TCPSocket
*sock
= NULL
;
1083 int err
= mStatus_NoError
;
1085 sock
= ConnectToServer( d
);
1086 require_action( sock
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: ConnectToServer failed" ) );
1088 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1091 mDNSu8
*ptr
= pkt
.msg
.data
;
1092 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1093 PktMsg
*reply
= NULL
;
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
;
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" ) );
1106 if ( zone
->type
== kDNSZonePrivate
)
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" ) );
1115 if ( !registration
)
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" ) );
1125 if ( !registration
)
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" ) );
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" ) );
1143 if ( zone
->updateKeys
)
1145 DNSDigest_SignMessage( &pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1146 require_action( ptr
, exit
, Log("UpdateSRV: Error constructing lease expiration update" ) );
1149 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1151 // send message, receive reply
1153 err
= SendPacket( sock
, &pkt
);
1154 require_action( !err
, exit
, Log( "UpdateSRV: SendPacket failed" ) );
1156 reply
= RecvPacket( sock
, NULL
, &closed
);
1157 require_action( reply
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: RecvPacket returned NULL" ) );
1159 ok
= SuccessfulUpdateTransaction( &pkt
, reply
);
1163 Log("SRV record registration failed with rcode %d", reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1173 mDNSPlatformTCPCloseConnection( sock
);
1179 // wrapper routines/macros
1180 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1182 // clear any existing records prior to registration
1183 mDNSlocal
int SetUpdateSRV(DaemonInfo
*d
)
1187 err
= ClearUpdateSRV(d
); // clear any existing record
1188 if (!err
) err
= UpdateSRV(d
, 1);
1193 // Argument Parsing and Configuration
1196 mDNSlocal
void PrintUsage(void)
1198 fprintf(stderr
, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1199 "Use \"dnsextd -h\" for help\n");
1202 mDNSlocal
void PrintHelp(void)
1204 fprintf(stderr
, "\n\n");
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"
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"
1217 "The options are as follows:\n\n"
1219 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1221 "-d Run daemon in foreground.\n\n"
1223 "-h Print help.\n\n"
1225 "-v Verbose output.\n\n"
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
)
1239 cfgfile
= strdup( CONFIG_FILE
);
1240 require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
);
1242 // defaults, may be overriden by command option
1244 // setup our sockaddr
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
);
1254 // setup nameserver's sockaddr
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
);
1266 d
->private_port
= PrivateDNSPort
;
1267 d
->llq_port
= DNSEXTPort
;
1269 while ((opt
= getopt(argc
, argv
, "f:hdv")) != -1)
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
;
1281 err
= ParseConfig( d
, cfgfile
);
1282 require_noerr( err
, arg_error
);
1284 // Make sure we've specified some zones
1286 require_action( d
->zones
, arg_error
, err
= mStatus_UnknownErr
);
1288 // if we have a shared secret, use it for the entire zone
1290 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1292 if ( zone
->updateKeys
)
1294 AssignDomainName( &zone
->updateKeys
->domain
, &zone
->name
);
1308 // Initialization Routines
1311 // Allocate memory, initialize locks and bookkeeping variables
1312 mDNSlocal
int InitLeaseTable(DaemonInfo
*d
)
1314 if (pthread_mutex_init(&d
->tablelock
, NULL
)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1315 d
->nbuckets
= LEASETABLE_INIT_NBUCKETS
;
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
);
1330 static const int kOn
= 1;
1332 mDNSBool
private = mDNSfalse
;
1333 struct sockaddr_in daddr
;
1337 // set up sockets on which we all ns requests
1339 self
->tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1340 require_action( dnssd_SocketValid(self
->tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
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" ) );
1347 err
= bind( self
->tcpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1348 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1350 err
= listen( self
->tcpsd
, LISTENQ
);
1351 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1353 self
->udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1354 require_action( dnssd_SocketValid(self
->udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
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" ) );
1361 err
= bind( self
->udpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1362 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->udpsd" ) );
1364 // set up sockets on which we receive llq requests
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
;
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" ) );
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" ) );
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" ) );
1382 err
= listen( self
->llq_tcpsd
, LISTENQ
);
1383 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
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" ) );
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" ) );
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" ) );
1396 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1398 err
= socketpair( AF_LOCAL
, SOCK_STREAM
, 0, sockpair
);
1399 require_action( !err
, exit
, LogErr( "SetupSockets", "socketpair" ) );
1401 self
->LLQEventListenSock
= sockpair
[0];
1402 self
->LLQEventNotifySock
= sockpair
[1];
1404 // set up socket on which we receive private requests
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
;
1413 self
->tlssd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1414 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
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" ) );
1421 err
= bind( self
->tlssd
, ( struct sockaddr
* ) &daddr
, sizeof( daddr
) );
1422 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tlssd" ) );
1424 err
= listen( self
->tlssd
, LISTENQ
);
1425 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1427 // Do we have any private zones?
1429 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
1431 if ( zone
->type
== kDNSZonePrivate
)
1440 err
= mDNSPlatformTLSSetupCerts();
1441 require_action( !err
, exit
, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1450 // periodic table updates
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
)
1459 mDNSu8
*ptr
= pkt
.msg
.data
;
1460 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1463 PktMsg
*reply
= NULL
;
1465 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, buf
));
1467 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1469 ptr
= putZone(&pkt
.msg
, ptr
, end
, zname
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
1471 ptr
= putDeletionRecord(&pkt
.msg
, ptr
, &rr
->resrec
);
1476 zone
= FindZone( d
, zname
);
1478 if ( zone
&& zone
->updateKeys
)
1480 DNSDigest_SignMessage(&pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
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" ) );
1492 if (!SuccessfulUpdateTransaction(&pkt
, reply
))
1493 Log("Expiration update failed with rcode %d", reply
? reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
: -1);
1496 if (!ptr
) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1497 if (reply
) free(reply
);
1500 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1501 mDNSlocal
void DeleteRecords(DaemonInfo
*d
, mDNSBool DeleteAll
)
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; }
1510 for (i
= 0; i
< d
->nbuckets
; i
++)
1512 RRTableElem
**ptr
= &d
->table
[i
];
1515 if (DeleteAll
|| (*ptr
)->expire
- now
.tv_sec
< 0)
1518 // delete record from server
1519 DeleteOneRecord(d
, &(*ptr
)->rr
, &(*ptr
)->zone
, sock
);
1521 *ptr
= (*ptr
)->next
;
1525 else ptr
= &(*ptr
)->next
;
1528 pthread_mutex_unlock(&d
->tablelock
);
1529 mDNSPlatformTCPCloseConnection( sock
);
1533 // main update request handling
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
)
1539 RRTableElem
**rptr
, *tmp
;
1540 int i
, allocsize
, bucket
;
1541 LargeCacheRecord lcr
;
1542 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1543 const mDNSu8
*ptr
, *end
;
1548 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
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
; }
1557 for (i
= 0; i
< pkt
->msg
.h
.mDNS_numUpdates
; i
++)
1559 mDNSBool DeleteAllRRSets
= mDNSfalse
, DeleteOneRRSet
= mDNSfalse
, DeleteOneRR
= mDNSfalse
;
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
];
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
;
1574 if (DeleteAllRRSets
|| DeleteOneRRSet
|| DeleteOneRR
)
1578 if (SameDomainName((*rptr
)->rr
.resrec
.name
, rr
->name
) &&
1580 (DeleteOneRRSet
&& (*rptr
)->rr
.resrec
.rrtype
== rr
->rrtype
) ||
1581 (DeleteOneRR
&& IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
))))
1584 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp
->rr
.resrec
, &tmp
->rr
.resrec
.rdata
->u
, buf
));
1585 *rptr
= (*rptr
)->next
;
1589 else rptr
= &(*rptr
)->next
;
1594 // see if add or refresh
1595 while (*rptr
&& !IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
)) rptr
= &(*rptr
)->next
;
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
));
1605 // New record - add to table
1606 if (d
->nelems
> d
->nbuckets
)
1609 bucket
= rr
->namehash
% d
->nbuckets
;
1610 rptr
= &d
->table
[bucket
];
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
;
1627 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1633 pthread_mutex_unlock(&d
->tablelock
);
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
)
1646 reply
= malloc(sizeof(*reply
));
1647 if (!reply
) { LogErr("FormatLeaseReply", "malloc"); return NULL
; }
1648 flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
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
;
1664 // pkt is thread-local, not requiring locking
1673 PktMsg
* reply
= NULL
;
1674 PktMsg
* leaseReply
;
1677 TCPSocket
* sock
= NULL
;
1680 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == kDNSFlag0_OP_Update
)
1682 int i
, adds
= 0, dels
= 0;
1683 const mDNSu8
*ptr
, *end
= (mDNSu8
*)&request
->msg
+ request
->len
;
1685 lease
= GetPktLease(&mDNSStorage
, &request
->msg
, end
);
1686 ptr
= LocateAuthorities(&request
->msg
, end
);
1687 for (i
= 0; i
< request
->msg
.h
.mDNS_numUpdates
; i
++)
1689 LargeCacheRecord lcr
;
1690 ptr
= GetLargeResourceRecord(NULL
, &request
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1691 if (lcr
.r
.resrec
.rroriginalttl
) adds
++; else dels
++;
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
);
1702 reply
->isZonePublic
= 0;
1703 InitializeDNSMessage(&reply
->msg
.h
, request
->msg
.h
.id
, UpdateRefused
);
1706 if (lease
> 7200) // Don't allow lease greater than two hours; typically 90-minute renewal period
1709 // Send msg to server, read reply
1711 if ( request
->len
<= 512 )
1715 if ( UDPServerTransaction( self
, request
, &buf
, &trunc
) < 0 )
1717 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1721 VLog("HandleRequest - answer truncated. Using TCP");
1725 reply
= &buf
; // success
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 ) ) );
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 ) ) );
1740 reply
= RecvPacket( sock
, &buf
, &closed
);
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
1748 if ( reply
&& ( ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
) ) )
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 ) ) );
1754 UpdateLeaseTable( request
, self
, lease
);
1758 leaseReply
= FormatLeaseReply( self
, reply
, lease
);
1762 Log("HandleRequest - unable to format lease reply");
1765 // %%% Looks like a potential memory leak -- who frees the original reply?
1769 // tell the main thread there was an update so it can send LLQs
1771 if ( send( self
->LLQEventNotifySock
, pingmsg
, sizeof( pingmsg
), 0 ) != sizeof( pingmsg
) )
1773 LogErr("HandleRequest", "send");
1781 mDNSPlatformTCPCloseConnection( sock
);
1784 if ( reply
== &buf
)
1786 reply
= malloc( sizeof( *reply
) );
1790 reply
->len
= buf
.len
;
1791 memcpy(&reply
->msg
, &buf
.msg
, buf
.len
);
1795 LogErr("HandleRequest", "malloc");
1804 // LLQ Support Routines
1807 // Set fields of an LLQ OPT Resource Record
1808 mDNSlocal
void FormatLLQOpt(AuthRecord
*opt
, int opcode
, const mDNSOpaque64
*const id
, mDNSs32 lease
)
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
;
1823 // Calculate effective remaining lease of an LLQ
1824 mDNSlocal mDNSu32
LLQLease(LLQEntry
*e
)
1828 gettimeofday(&t
, NULL
);
1829 if (e
->expire
< t
.tv_sec
) return 0;
1830 else return e
->expire
- t
.tv_sec
;
1833 mDNSlocal
void DeleteLLQ(DaemonInfo
*d
, LLQEntry
*e
)
1835 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
1836 LLQEntry
**ptr
= &d
->LLQTable
[bucket
];
1837 AnswerListElem
*a
= e
->AnswerList
;
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
);
1843 if (a
&& !(--a
->refcount
) && d
->AnswerTableCount
>= LLQ_TABLESIZE
)
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
1850 CacheRecord
*cr
= a
->KnownAnswers
, *tmp
;
1851 AnswerListElem
**tbl
= &d
->AnswerTable
[bucket
];
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");
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
;
1872 mDNSlocal
int SendLLQ(DaemonInfo
*d
, PktMsg
*pkt
, struct sockaddr_in dst
, TCPSocket
*sock
)
1881 if ( SendPacket( sock
, pkt
) != 0 )
1883 LogErr("DaemonInfo", "MySend");
1884 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1889 if (sendto(d
->llq_udpsd
, &pkt
->msg
, pkt
->len
, 0, (struct sockaddr
*)&dst
, sizeof(dst
)) != (int)pkt
->len
)
1891 LogErr("DaemonInfo", "sendto");
1892 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1901 mDNSlocal CacheRecord
*AnswerQuestion(DaemonInfo
*d
, AnswerListElem
*e
)
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
;
1913 VLog("Querying server for %##s type %d", e
->name
.c
, e
->type
);
1915 InitializeDNSMessage(&q
.msg
.h
, zeroID
, uQueryFlags
);
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
);
1927 if (UDPServerTransaction(d
, &q
, &buf
, &trunc
) < 0)
1928 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e
->name
.c
);
1930 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e
->name
.c
); e
->UseTCP
= mDNStrue
; }
1931 else reply
= &buf
; // success
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" ) );
1947 if (reply
) HdrNToH(reply
);
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
; }
1954 end
= (mDNSu8
*)&reply
->msg
+ reply
->len
;
1955 ansptr
= LocateAnswers(&reply
->msg
, end
);
1956 if (!ansptr
) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end
; }
1958 for (i
= 0; i
< reply
->msg
.h
.numAnswers
; i
++)
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
))
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
);
1969 CacheRecord
*cr
= CopyCacheRecord(&lcr
.r
, &e
->name
);
1970 if (!cr
) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end
; }
1971 cr
->next
= AnswerList
;
1977 if (reply
&& reply
!= &buf
) free(reply
);
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
)
1984 CacheRecord
*cr
, *NewAnswers
, **na
, **ka
; // "new answer", "known answer"
1985 DaemonInfo
*d
= ((UpdateAnswerListArgs
*)args
)->d
;
1986 AnswerListElem
*a
= ((UpdateAnswerListArgs
*)args
)->a
;
1991 // get up to date answers
1992 NewAnswers
= AnswerQuestion(d
, a
);
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
1998 // second pass - mark answers pre-existent
1999 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
2001 for (na
= &NewAnswers
; *na
; na
= &(*na
)->next
)
2003 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
))
2004 { (*ka
)->resrec
.rroriginalttl
= 0; break; } // 0 means no change
2008 // third pass - add new records to Event list
2012 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
2013 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
)) break;
2016 // answer is not in list - splice from NewAnswers list, add to Event list
2018 *na
= (*na
)->next
; // splice from list
2019 cr
->next
= a
->EventList
; // add spliced record to event list
2021 cr
->resrec
.rroriginalttl
= 1; // 1 means add
2023 else na
= &(*na
)->next
;
2026 // move all the removes from the answer list to the event list
2027 ka
= &a
->KnownAnswers
;
2030 if ((*ka
)->resrec
.rroriginalttl
== (unsigned)-1)
2034 cr
->next
= a
->EventList
;
2037 else ka
= &(*ka
)->next
;
2040 // lastly, free the remaining records (known answers) in NewAnswers list
2044 NewAnswers
= NewAnswers
->next
;
2051 mDNSlocal
void SendEvents(DaemonInfo
*d
, LLQEntry
*e
)
2055 mDNSu8
*end
= (mDNSu8
*)&response
.msg
.data
;
2057 char rrbuf
[MaxMsg
], addrbuf
[32];
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; }
2067 // put adds/removes in packet
2068 for (cr
= e
->AnswerList
->EventList
; cr
; cr
= cr
->next
)
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; }
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; }
2080 response
.len
= (int)(end
- (mDNSu8
*)&response
.msg
);
2081 if (SendLLQ(d
, &response
, e
->cli
, NULL
) < 0) LogMsg("Error: SendEvents - SendLLQ");
2084 mDNSlocal
void PrintLLQAnswers(DaemonInfo
*d
)
2089 Log("Printing LLQ Answer Table contents");
2091 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2093 AnswerListElem
*a
= d
->AnswerTable
[i
];
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
));
2106 mDNSlocal
void PrintLLQTable(DaemonInfo
*d
)
2112 Log("Printing LLQ table contents");
2114 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2123 case RequestReceived
: state
= "RequestReceived"; break;
2124 case ChallengeSent
: state
= "ChallengeSent"; break;
2125 case Established
: state
= "Established"; break;
2126 default: state
= "unknown";
2128 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
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
);
2137 // Send events to clients as a result of a change in the zone
2138 mDNSlocal
void GenLLQEvents(DaemonInfo
*d
)
2143 UpdateAnswerListArgs
*args
;
2145 VLog("Generating LLQ Events");
2147 gettimeofday(&t
, NULL
);
2149 // get all answers up to date
2150 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2152 AnswerListElem
*a
= d
->AnswerTable
[i
];
2155 args
= malloc(sizeof(*args
));
2156 if (!args
) { LogErr("GenLLQEvents", "malloc"); return; }
2159 if (pthread_create(&a
->tid
, NULL
, UpdateAnswerList
, args
) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
2165 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2167 AnswerListElem
*a
= d
->AnswerTable
[i
];
2170 if (pthread_join(a
->tid
, NULL
)) LogErr("GenLLQEvents", "pthread_join");
2175 // for each established LLQ, send events
2176 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2178 e
= &d
->LLQTable
[i
];
2181 if ((*e
)->expire
< t
.tv_sec
) DeleteLLQ(d
, *e
);
2184 if ((*e
)->state
== Established
&& (*e
)->AnswerList
->EventList
) SendEvents(d
, *e
);
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
++)
2193 AnswerListElem
*a
= d
->AnswerTable
[i
];
2198 CacheRecord
*cr
= a
->EventList
, *tmp
;
2203 if ((signed)tmp
->resrec
.rroriginalttl
< 0) free(tmp
);
2206 tmp
->next
= a
->KnownAnswers
;
2207 a
->KnownAnswers
= tmp
;
2208 tmp
->resrec
.rroriginalttl
= 0;
2211 a
->EventList
= NULL
;
2218 mDNSlocal
void SetAnswerList(DaemonInfo
*d
, LLQEntry
*e
)
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
;
2225 a
= malloc(sizeof(*a
));
2226 if (!a
) { LogErr("SetAnswerList", "malloc"); return; }
2227 AssignDomainName(&a
->name
, &e
->qname
);
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
);
2242 // Allocate LLQ entry, insert into table
2243 mDNSlocal LLQEntry
*NewLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, mDNSu32 lease
)
2247 int bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2250 e
= malloc(sizeof(*e
));
2251 if (!e
) { LogErr("NewLLQ", "malloc"); return NULL
; }
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
);
2256 // initialize structure
2258 AssignDomainName(&e
->qname
, qname
);
2260 e
->id
= zeroOpaque64
;
2261 e
->state
= RequestReceived
;
2262 e
->AnswerList
= NULL
;
2264 if (lease
< LLQ_MIN_LEASE
) lease
= LLQ_MIN_LEASE
;
2265 else if (lease
> LLQ_MAX_LEASE
) lease
= LLQ_MAX_LEASE
;
2267 gettimeofday(&t
, NULL
);
2268 e
->expire
= t
.tv_sec
+ (int)lease
;
2272 e
->next
= d
->LLQTable
[bucket
];
2273 d
->LLQTable
[bucket
] = e
;
2278 // Handle a refresh request from client
2279 mDNSlocal
void LLQRefresh(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2283 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
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
);
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
;
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; }
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; }
2307 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2308 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQRefresh");
2310 if (llq
->llqlease
) e
->state
= Established
;
2311 else DeleteLLQ(d
, e
);
2314 // Complete handshake with Ack an initial answers
2315 mDNSlocal
void LLQCompleteHandshake(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2321 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2322 char rrbuf
[MaxMsg
], addrbuf
[32];
2324 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
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
)
2333 Log("Incorrect challenge response from %s", addr
);
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
);
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; }
2346 if (e
->state
!= Established
) { SetAnswerList(d
, e
); e
->state
= Established
; }
2348 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2349 for (ptr
= e
->AnswerList
->KnownAnswers
; ptr
; ptr
= ptr
->next
)
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; }
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; }
2361 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2362 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQCompleteHandshake");
2365 mDNSlocal
void LLQSetupChallenge(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
)
2369 mDNSu8
*end
= challenge
.msg
.data
;
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
);
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
2378 if (mDNSOpaque64IsZero(&e
->id
)) // don't regenerate random ID for retransmissions
2380 // construct ID <time><random>
2381 gettimeofday(&t
, NULL
);
2382 e
->id
.l
[0] = t
.tv_sec
;
2383 e
->id
.l
[1] = random();
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
;
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
)
2404 case RequestReceived
:
2408 gettimeofday(&t
, NULL
);
2409 e
->id
.l
[0] = t
.tv_sec
; // construct ID <time><random>
2410 e
->id
.l
[1] = random();
2412 LLQCompleteHandshake( d
, e
, llq
, msgID
, sock
);
2414 // Set the state to established because we've just set the LLQ up using TCP
2415 e
->state
= Established
;
2419 LLQSetupChallenge(d
, e
, llq
, msgID
);
2423 if (mDNSOpaque64IsZero(&llq
->id
)) LLQSetupChallenge(d
, e
, llq
, msgID
); // challenge sent and lost
2424 else LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
);
2427 if (mDNSOpaque64IsZero(&llq
->id
))
2429 // client started over. reset state.
2430 LLQEntry
*newe
= NewLLQ(d
, e
->cli
, &e
->qname
, e
->qtype
, llq
->llqlease
);
2433 LLQSetupChallenge(d
, newe
, llq
, msgID
);
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; }
2444 mDNSlocal LLQEntry
*LookupLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, const mDNSOpaque64
*const id
)
2446 int bucket
= bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2447 LLQEntry
*ptr
= d
->LLQTable
[bucket
];
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
2470 pkt
->msg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
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" ) );
2481 mDNSlocal
int RecvLLQ( DaemonInfo
*d
, PktMsg
*pkt
, TCPSocket
*sock
)
2484 LargeCacheRecord opt
;
2487 const mDNSu8
*qptr
= pkt
->msg
.data
;
2488 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2490 LLQOptData
*llq
= NULL
;
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);
2497 VLog("Received LLQ msg from %s", addr
);
2498 // sanity-check packet
2499 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2501 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
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
++)
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;
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
); }
2520 // dispatch each question
2521 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
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
; }
2528 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2531 // no entry - if zero ID, create new
2532 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2535 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2545 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
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
;
2557 // Unused parameters
2565 if ( pkt
->msg
.h
.numAdditionals
)
2567 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2570 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2573 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2576 Log("Unable to read additional record");
2582 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2586 LogMsg( "IsAuthorized: unable to find Additional section" );
2590 // If we don't know what zone this is, then it's authorized.
2599 if ( IsQuery( pkt
) )
2601 keys
= pkt
->zone
->queryKeys
;
2604 else if ( IsUpdate( pkt
) )
2606 keys
= pkt
->zone
->updateKeys
;
2616 if ( pkt
->isZonePublic
)
2622 // If there are no keys, then we're authorized
2624 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
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
;
2634 // Find the right key
2636 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2638 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
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
;
2654 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2655 // lifting of message verification
2657 pkt
->msg
.h
.numAdditionals
--;
2661 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2665 pkt
->msg
.h
.numAdditionals
++;
2669 if ( hasTSIG
&& strip
)
2671 // Strip the TSIG from the message
2673 pkt
->msg
.h
.numAdditionals
--;
2674 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2682 // request handler wrappers for TCP and UDP requests
2683 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2691 UDPContext
* context
= ( UDPContext
* ) vptr
;
2692 PktMsg
* reply
= NULL
;
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
2699 reply
= HandleRequest( context
->d
, &context
->pkt
);
2700 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
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" ) );
2714 pthread_exit( NULL
);
2727 UDPContext
* context
= NULL
;
2731 DomainAuthInfo
* key
;
2732 unsigned int clisize
= sizeof( context
->cliaddr
);
2734 mStatus err
= mStatus_NoError
;
2736 context
= malloc( sizeof( UDPContext
) );
2737 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2739 mDNSPlatformMemZero( context
, sizeof( *context
) );
2743 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
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
;
2750 // Set the zone in the packet
2752 SetZone( context
->d
, &context
->pkt
);
2754 // Notify messages handled by main thread
2756 if ( IsNotify( &context
->pkt
) )
2758 int e
= RecvNotify( self
, &context
->pkt
);
2762 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2764 if ( IsLLQRequest( &context
->pkt
) )
2766 // LLQ messages handled by main thread
2767 int e
= RecvLLQ( self
, &context
->pkt
, NULL
);
2772 if ( IsLLQAck(&context
->pkt
) )
2774 // !!!KRS need to do acks + retrans
2780 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2781 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2783 pthread_detach(tid
);
2790 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
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
;
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" ) );
2798 err
= mStatus_NoAuth
;
2803 if ( err
&& context
)
2815 TCPContext
* context
2820 if ( context
->sock
)
2822 mDNSPlatformTCPCloseConnection( context
->sock
);
2836 TCPContext
* context
= ( TCPContext
* ) vptr
;
2837 PktMsg
* reply
= NULL
;
2841 //!!!KRS if this read blocks indefinitely, we can run out of threads
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 ) ) );
2847 // deliver reply to client
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 ) ) );
2854 FreeTCPContext( context
);
2871 TCPContext
* context
= ( TCPContext
* ) param
;
2875 DomainAuthInfo
* key
;
2878 mDNSBool freeContext
= mDNStrue
;
2879 mStatus err
= mStatus_NoError
;
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.
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" ) );
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
2895 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2897 // Set's the DNS Zone that is associated with this message
2899 SetZone( context
->d
, &context
->pkt
);
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
2904 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2906 if ( IsLLQRequest( &context
->pkt
) )
2908 // LLQ messages handled by main thread
2909 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2913 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2917 LogErr( "RecvTCPMessage", "pthread_create" );
2918 err
= mStatus_NoError
;
2922 // Let the thread free the context
2924 freeContext
= mDNSfalse
;
2926 pthread_detach(tid
);
2933 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2935 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
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
;
2940 SendPacket( context
->sock
, &reply
);
2945 freeContext
= mDNSfalse
;
2952 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2957 FreeTCPContext( context
);
2967 TCPSocketFlags flags
2970 TCPContext
* context
= NULL
;
2971 unsigned int clilen
= sizeof( context
->cliaddr
);
2973 mStatus err
= mStatus_NoError
;
2975 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2976 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2977 mDNSPlatformMemZero( context
, sizeof( sizeof( TCPContext
) ) );
2979 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2980 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2982 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2983 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2985 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2986 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2990 if ( err
&& context
)
3001 // listen for incoming requests, periodically check table for expired records, respond to signals
3002 mDNSlocal
int Run(DaemonInfo
*d
)
3004 int staticMaxFD
, nfds
;
3006 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
3007 mDNSBool EventsPending
= mDNSfalse
;
3009 VLog("Listening for requests...");
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;
3022 EventSource
* source
;
3026 timeout
.tv_sec
= timeout
.tv_usec
= 0;
3027 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
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
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
;
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
);
3052 maxFD
= staticMaxFD
;
3054 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3056 FD_SET( source
->fd
, &rset
);
3058 if ( source
->fd
> maxFD
)
3064 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
3071 // close sockets to prevent clients from making new requests during shutdown
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
);
3083 Log( "Received SIGINFO" );
3094 Log( "Received SIGHUP" );
3096 err
= ParseConfig( d
, cfgfile
);
3100 LogErr( "Run", "ParseConfig" );
3108 Log("Received unhandled signal - continuing");
3113 LogErr("Run", "select"); return -1;
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
))
3125 // clear signalling data off socket
3127 recv(d
->LLQEventListenSock
, buf
, 256, 0);
3130 EventsPending
= mDNStrue
;
3131 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
3135 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3137 if ( FD_ISSET( source
->fd
, &rset
) )
3139 source
->callback( source
->context
);
3140 break; // in case we removed this guy from the event loop
3147 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
3148 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
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
)
3158 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
3159 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
3160 if (sig
== SIGHUP
) { hangup
= 1; return; }
3170 DNameListElem
* elem
;
3171 mStatus err
= mStatus_NoError
;
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
;
3185 int main(int argc
, char *argv
[])
3187 int started_via_launchd
= 0;
3191 Log("dnsextd starting");
3193 d
= malloc(sizeof(*d
));
3194 if (!d
) { LogErr("main", "malloc"); exit(1); }
3195 mDNSPlatformMemZero(d
, sizeof(DaemonInfo
));
3197 // Setup the public SRV record names
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.");
3205 // Setup signal handling
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");
3213 // remove open file limit
3214 rlim
.rlim_max
= RLIM_INFINITY
;
3215 rlim
.rlim_cur
= RLIM_INFINITY
;
3216 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3218 LogErr("main", "setrlimit");
3219 Log("Using default file descriptor resource limit");
3222 if (!strcasecmp(argv
[1], "-launchd"))
3224 Log("started_via_launchd");
3225 started_via_launchd
= 1;
3229 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3231 if (!foreground
&& !started_via_launchd
)
3235 LogErr("main", "daemon");
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); }
3246 Log("dnsextd stopping");
3248 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
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.
3258 // It's an error for these routines to actually be called, so perhaps we should log any call
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; }
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__
")";
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");