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.82 2007/09/27 17:42:49 cheshire
21 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
23 Revision 1.81 2007/09/21 21:12:37 cheshire
24 DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
26 Revision 1.80 2007/09/18 19:09:02 cheshire
27 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
29 Revision 1.79 2007/07/11 02:59:58 cheshire
30 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
31 Add AutoTunnel parameter to mDNS_SetSecretForDomain
33 Revision 1.78 2007/06/20 01:10:13 cheshire
34 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
36 Revision 1.77 2007/05/15 21:57:17 cheshire
37 <rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
38 assuming that all negative values (or zero!) are invalid socket numbers
40 Revision 1.76 2007/05/01 23:53:26 cheshire
41 <rdar://problem/5175318> dnsextd should refuse updates without attached lease
43 Revision 1.75 2007/05/01 00:18:12 cheshire
44 Use "-launchd" instead of "-d" when starting via launchd
45 (-d sets foreground mode, which writes errors to stderr, which is ignored when starting via launchd)
47 Revision 1.74 2007/04/26 00:35:16 cheshire
48 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
49 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
50 inside the firewall may give answers where a public one gives none, and vice versa.)
52 Revision 1.73 2007/04/22 06:02:03 cheshire
53 <rdar://problem/4615977> Query should immediately return failure when no server
55 Revision 1.72 2007/04/05 22:55:37 cheshire
56 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
58 Revision 1.71 2007/04/05 19:43:56 cheshire
59 Added ProgramName and comment about '-d' option
61 Revision 1.70 2007/04/05 18:34:40 cheshire
62 <rdar://problem/4838930> dnsextd gives "bind - Address already in use" error
64 Revision 1.69 2007/03/28 21:14:08 cheshire
65 The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
67 Revision 1.68 2007/03/28 18:20:50 cheshire
70 Revision 1.67 2007/03/21 00:30:07 cheshire
71 <rdar://problem/4789455> Multiple errors in DNameList-related code
73 Revision 1.66 2007/03/20 17:07:16 cheshire
74 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
76 Revision 1.65 2007/02/07 19:32:00 cheshire
77 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
79 Revision 1.64 2007/01/20 01:43:26 cheshire
80 <rdar://problem/4058383> Should not write log messages to /dev/console
82 Revision 1.63 2007/01/20 01:31:56 cheshire
85 Revision 1.62 2007/01/17 22:06:03 cheshire
86 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
88 Revision 1.61 2007/01/05 08:30:54 cheshire
89 Trim excessive "$Log" checkin history from before 2006
90 (checkin history still available via "cvs log ..." of course)
92 Revision 1.60 2007/01/05 08:07:29 cheshire
93 Remove unnecessary dummy udsserver_default_reg_domain_changed() routine
95 Revision 1.59 2007/01/05 05:46:47 cheshire
96 Remove unnecessary dummy udsserver_automatic_browse_domain_changed() routine
98 Revision 1.58 2007/01/04 23:11:54 cheshire
99 udsserver_default_browse_domain_changed renamed to udsserver_automatic_browse_domain_changed
101 Revision 1.57 2007/01/04 01:41:48 cheshire
102 Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
104 Revision 1.56 2006/12/22 20:59:51 cheshire
105 <rdar://problem/4742742> Read *all* DNS keys from keychain,
106 not just key for the system-wide default registration domain
108 Revision 1.55 2006/11/30 23:08:39 herscher
109 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
111 Revision 1.54 2006/11/18 05:01:33 cheshire
112 Preliminary support for unifying the uDNS and mDNS code,
113 including caching of uDNS answers
115 Revision 1.53 2006/11/17 23:55:09 cheshire
116 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
118 Revision 1.52 2006/11/17 04:27:51 cheshire
119 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
121 Revision 1.51 2006/11/17 03:50:18 cheshire
122 Add debugging loggin in SendPacket and UDPServerTransaction
124 Revision 1.50 2006/11/17 03:48:57 cheshire
125 <rdar://problem/4842493> dnsextd replying on wrong port
127 Revision 1.49 2006/11/03 06:12:44 herscher
128 Make sure all buffers passed to GetRRDisplayString_rdb are of length MaxMsg
130 Revision 1.48 2006/10/20 19:18:35 cheshire
131 <rdar://problem/4669228> dnsextd generates bogus SRV record with null target
133 Revision 1.47 2006/10/20 05:43:51 herscher
134 LookupLLQ() needs to match on the port number when looking up the LLQ
136 Revision 1.46 2006/10/11 22:56:07 herscher
137 Tidy up the implementation of ZoneHandlesName
139 Revision 1.45 2006/08/22 03:28:57 herscher
140 <rdar://problem/4678717> Long-lived queries aren't working well in TOT.
142 Revision 1.44 2006/08/14 23:24:56 cheshire
143 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
145 Revision 1.43 2006/07/20 19:53:33 mkrochma
146 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
147 More fixes for private DNS
149 Revision 1.42 2006/07/05 22:48:19 cheshire
150 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
155 #include "../mDNSShared/uds_daemon.h"
156 #include "../mDNSShared/dnssd_ipc.h"
157 #include "../mDNSCore/uDNS.h"
158 #include "../mDNSShared/DebugServices.h"
163 #include <sys/types.h>
164 #include <sys/socket.h>
165 #include <netinet/in.h>
166 #include <arpa/inet.h>
170 #include <sys/time.h>
171 #include <sys/resource.h>
175 // Compatibility workaround
177 #define AF_LOCAL AF_UNIX
183 mDNSexport
const char ProgramName
[] = "dnsextd";
185 #define LOOPBACK "127.0.0.1"
186 #if !defined(LISTENQ)
187 # define LISTENQ 128 // tcp connection backlog
189 #define RECV_BUFLEN 9000
190 #define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
191 #define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
192 #define SRV_TTL 7200 // TTL For _dns-update SRV records
193 #define CONFIG_FILE "/etc/dnsextd.conf"
194 #define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
196 // LLQ Lease bounds (seconds)
197 #define LLQ_MIN_LEASE (15 * 60)
198 #define LLQ_MAX_LEASE (120 * 60)
199 #define LLQ_LEASE_FUDGE 60
201 // LLQ SOA poll interval (microseconds)
202 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
203 #define LLQ_MONITOR_INTERVAL 250000
205 #define INFO_SIGNAL SIGINFO
207 #define INFO_SIGNAL SIGUSR1
210 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
214 // Structs/fields that must be locked for thread safety are explicitly commented
217 // args passed to UDP request handler thread as void*
222 struct sockaddr_in cliaddr
;
227 // args passed to TCP request handler thread as void*
231 struct sockaddr_in cliaddr
;
232 TCPSocket
*sock
; // socket connected to client
236 // args passed to UpdateAnswerList thread as void*
241 } UpdateAnswerListArgs
;
247 // booleans to determine runtime output
248 // read-only after initialization (no mutex protection)
249 static mDNSBool foreground
= 0;
250 static mDNSBool verbose
= 0;
252 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
253 static mDNSBool terminate
= 0;
254 static mDNSBool dumptable
= 0;
255 static mDNSBool hangup
= 0;
257 // global for config file location
258 static char * cfgfile
= NULL
;
262 // Log messages are delivered to syslog unless -f option specified
265 // common message logging subroutine
266 mDNSlocal
void PrintLog(const char *buffer
)
270 fprintf(stderr
,"%s\n", buffer
);
275 openlog("dnsextd", LOG_CONS
, LOG_DAEMON
);
276 syslog(LOG_ERR
, "%s", buffer
);
281 // Verbose Logging (conditional on -v option)
282 mDNSlocal
void VLog(const char *format
, ...)
287 if (!verbose
) return;
288 va_start(ptr
,format
);
289 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
294 // Unconditional Logging
295 mDNSlocal
void Log(const char *format
, ...)
300 va_start(ptr
,format
);
301 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
307 // prints message "dnsextd <function>: <operation> - <error message>"
308 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
309 mDNSlocal
void LogErr(const char *fn
, const char *operation
)
311 char buf
[512], errbuf
[256];
312 strerror_r(errno
, errbuf
, sizeof(errbuf
));
313 snprintf(buf
, sizeof(buf
), "%s: %s - %s", fn
, operation
, errbuf
);
318 // Networking Utility Routines
321 // Convert DNS Message Header from Network to Host byte order
322 mDNSlocal
void HdrNToH(PktMsg
*pkt
)
324 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
325 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
326 pkt
->msg
.h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
327 pkt
->msg
.h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
328 pkt
->msg
.h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
329 pkt
->msg
.h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
332 // Convert DNS Message Header from Host to Network byte order
333 mDNSlocal
void HdrHToN(PktMsg
*pkt
)
335 mDNSu16 numQuestions
= pkt
->msg
.h
.numQuestions
;
336 mDNSu16 numAnswers
= pkt
->msg
.h
.numAnswers
;
337 mDNSu16 numAuthorities
= pkt
->msg
.h
.numAuthorities
;
338 mDNSu16 numAdditionals
= pkt
->msg
.h
.numAdditionals
;
339 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
341 // Put all the integer values in IETF byte-order (MSB first, LSB second)
342 *ptr
++ = (mDNSu8
)(numQuestions
>> 8);
343 *ptr
++ = (mDNSu8
)(numQuestions
& 0xFF);
344 *ptr
++ = (mDNSu8
)(numAnswers
>> 8);
345 *ptr
++ = (mDNSu8
)(numAnswers
& 0xFF);
346 *ptr
++ = (mDNSu8
)(numAuthorities
>> 8);
347 *ptr
++ = (mDNSu8
)(numAuthorities
& 0xFF);
348 *ptr
++ = (mDNSu8
)(numAdditionals
>> 8);
349 *ptr
++ = (mDNSu8
)(numAdditionals
& 0xFF);
353 // Add socket to event loop
355 mDNSlocal mStatus
AddSourceToEventLoop( DaemonInfo
* self
, TCPSocket
*sock
, EventCallback callback
, void *context
)
357 EventSource
* newSource
;
358 mStatus err
= mStatus_NoError
;
360 if ( self
->eventSources
.LinkOffset
== 0 )
362 InitLinkedList( &self
->eventSources
, offsetof( EventSource
, next
));
365 newSource
= ( EventSource
*) malloc( sizeof *newSource
);
366 if ( newSource
== NULL
)
368 err
= mStatus_NoMemoryErr
;
372 newSource
->callback
= callback
;
373 newSource
->context
= context
;
374 newSource
->sock
= sock
;
375 newSource
->fd
= mDNSPlatformTCPGetFD( sock
);
377 AddToTail( &self
->eventSources
, newSource
);
385 // Remove socket from event loop
387 mDNSlocal mStatus
RemoveSourceFromEventLoop( DaemonInfo
* self
, TCPSocket
*sock
)
389 EventSource
* source
;
392 for ( source
= ( EventSource
* ) self
->eventSources
.Head
; source
; source
= source
->next
)
394 if ( source
->sock
== sock
)
396 RemoveFromList( &self
->eventSources
, source
);
399 err
= mStatus_NoError
;
404 err
= mStatus_NoSuchNameErr
;
411 // create a socket connected to nameserver
412 // caller terminates connection via close()
413 mDNSlocal TCPSocket
*ConnectToServer(DaemonInfo
*d
)
415 int ntries
= 0, retry
= 0;
419 mDNSIPPort port
= zeroIPPort
;
422 TCPSocket
*sock
= mDNSPlatformTCPSocket( NULL
, 0, &port
);
423 if ( !sock
) { LogErr("ConnectToServer", "socket"); return NULL
; }
424 fd
= mDNSPlatformTCPGetFD( sock
);
425 if (!connect( fd
, (struct sockaddr
*)&d
->ns_addr
, sizeof(d
->ns_addr
))) return sock
;
426 mDNSPlatformTCPCloseConnection( sock
);
429 LogErr("ConnectToServer", "connect");
430 Log("ConnectToServer - retrying connection");
431 if (!retry
) retry
= 500000 + random() % 500000;
435 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries
); return NULL
; }
439 // send an entire block of data over a connected socket
440 mDNSlocal
int MySend(TCPSocket
*sock
, const void *msg
, int len
)
442 int selectval
, n
, nsent
= 0;
444 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
452 fd
= mDNSPlatformTCPGetFD( sock
);
455 selectval
= select( fd
+1, NULL
, &wset
, NULL
, &timeout
);
456 if (selectval
< 0) { LogErr("MySend", "select"); return -1; }
457 if (!selectval
|| !FD_ISSET(fd
, &wset
)) { Log("MySend - timeout"); return -1; }
459 n
= mDNSPlatformWriteTCP( sock
, ( char* ) msg
+ nsent
, len
- nsent
);
461 if (n
< 0) { LogErr("MySend", "send"); return -1; }
467 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
468 mDNSlocal
int SendPacket(TCPSocket
*sock
, PktMsg
*pkt
)
470 // send the lenth, in network byte order
471 mDNSu16 len
= htons((mDNSu16
)pkt
->len
);
472 if (MySend(sock
, &len
, sizeof(len
)) < 0) return -1;
475 VLog("SendPacket Q:%d A:%d A:%d A:%d ",
476 ntohs(pkt
->msg
.h
.numQuestions
),
477 ntohs(pkt
->msg
.h
.numAnswers
),
478 ntohs(pkt
->msg
.h
.numAuthorities
),
479 ntohs(pkt
->msg
.h
.numAdditionals
));
480 return MySend(sock
, &pkt
->msg
, pkt
->len
);
483 // Receive len bytes, waiting until we have all of them.
484 // Returns number of bytes read (which should always be the number asked for).
485 static int my_recv(TCPSocket
*sock
, void *const buf
, const int len
, mDNSBool
* closed
)
487 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
488 // use an explicit while() loop instead.
489 // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
490 // arithmetic on "void *" pointers is compiler-dependent.
493 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
494 int selectval
, remaining
= len
;
495 char *ptr
= (char *)buf
;
502 fd
= mDNSPlatformTCPGetFD( sock
);
506 selectval
= select(fd
+1, &rset
, NULL
, NULL
, &timeout
);
507 if (selectval
< 0) { LogErr("my_recv", "select"); return -1; }
508 if (!selectval
|| !FD_ISSET(fd
, &rset
))
510 Log("my_recv - timeout");
514 num_read
= mDNSPlatformReadTCP( sock
, ptr
, remaining
, closed
);
516 if (((num_read
== 0) && *closed
) || (num_read
< 0) || (num_read
> remaining
)) return -1;
517 if (num_read
== 0) return 0;
519 remaining
-= num_read
;
524 // Return a DNS Message read off of a TCP socket, or NULL on failure
525 // If storage is non-null, result is placed in that buffer. Otherwise,
526 // returned value is allocated with Malloc, and contains sufficient extra
527 // storage for a Lease OPT RR
545 fd
= mDNSPlatformTCPGetFD( sock
);
547 nread
= my_recv( sock
, &msglen
, sizeof( msglen
), closed
);
549 require_action_quiet( nread
!= -1, exit
, err
= mStatus_UnknownErr
);
550 require_action_quiet( nread
> 0, exit
, err
= mStatus_NoError
);
552 msglen
= ntohs( msglen
);
553 require_action_quiet( nread
== sizeof( msglen
), exit
, err
= mStatus_UnknownErr
; Log( "Could not read length field of message") );
557 require_action_quiet( msglen
<= sizeof( storage
->msg
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: provided buffer too small." ) );
562 // buffer extra space to add an OPT RR
564 if ( msglen
> sizeof(DNSMessage
))
566 allocsize
= sizeof(PktMsg
) - sizeof(DNSMessage
) + msglen
;
570 allocsize
= sizeof(PktMsg
);
573 pkt
= malloc(allocsize
);
574 require_action_quiet( pkt
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvPacket", "malloc" ) );
575 bzero( pkt
, sizeof( *pkt
) );
579 srclen
= sizeof(pkt
->src
);
581 if ( getpeername( fd
, ( struct sockaddr
* ) &pkt
->src
, &srclen
) || ( srclen
!= sizeof( pkt
->src
) ) )
583 LogErr("RecvPacket", "getpeername");
584 bzero(&pkt
->src
, sizeof(pkt
->src
));
587 nread
= my_recv(sock
, &pkt
->msg
, msglen
, closed
);
588 require_action_quiet( nread
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvPacket", "recv" ) );
589 require_action_quiet( nread
== msglen
, exit
, err
= mStatus_UnknownErr
; Log( "Could not read entire message" ) );
590 require_action_quiet( pkt
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: Message too short (%d bytes)", pkt
->len
) );
596 if ( pkt
!= storage
)
617 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
619 if ( SameDomainName( &zone
->name
, name
) )
632 const domainname
* zname
,
633 const domainname
* dname
636 mDNSu16 i
= DomainNameLength( zname
);
637 mDNSu16 j
= DomainNameLength( dname
);
639 if ( ( i
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( j
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( i
> j
) || ( memcmp( zname
->c
, dname
->c
+ ( j
- i
), i
) != 0 ) )
648 mDNSlocal mDNSBool
IsQuery( PktMsg
* pkt
)
650 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
);
654 mDNSlocal mDNSBool
IsUpdate( PktMsg
* pkt
)
656 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_OP_Update
);
660 mDNSlocal mDNSBool
IsNotify(PktMsg
*pkt
)
662 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( mDNSu8
) ( kDNSFlag0_OP_Notify
);
666 mDNSlocal mDNSBool
IsLLQRequest(PktMsg
*pkt
)
668 const mDNSu8
*ptr
= NULL
, *end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
669 LargeCacheRecord lcr
;
671 mDNSBool result
= mDNSfalse
;
674 if ((mDNSu8
)(pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (mDNSu8
)(kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
)) goto end
;
676 if (!pkt
->msg
.h
.numAdditionals
) goto end
;
677 ptr
= LocateAdditionals(&pkt
->msg
, end
);
680 // find last Additional info.
681 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
683 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
684 if (!ptr
) { Log("Unable to read additional record"); goto end
; }
687 if ( lcr
.r
.resrec
.rrtype
== kDNSType_OPT
&& lcr
.r
.resrec
.rdlength
>= LLQ_OPT_RDLEN
&& lcr
.r
.resrec
.rdata
->u
.opt
.opt
== kDNSOpt_LLQ
)
697 // !!!KRS implement properly
698 mDNSlocal mDNSBool
IsLLQAck(PktMsg
*pkt
)
700 if ((pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
) &&
701 pkt
->msg
.h
.numQuestions
&& !pkt
->msg
.h
.numAnswers
&& !pkt
->msg
.h
.numAuthorities
) return mDNStrue
;
713 DNameListElem
* elem
;
714 mDNSBool ret
= mDNSfalse
;
715 int i
= ( int ) DomainNameLength( &q
->qname
) - 1;
717 for ( elem
= self
->public_names
; elem
; elem
= elem
->next
)
719 int j
= ( int ) DomainNameLength( &elem
->name
) - 1;
723 for ( ; i
>= 0; i
--, j
-- )
725 if ( q
->qname
.c
[ i
] != elem
->name
.c
[ j
] )
749 const mDNSu8
* ptr
= pkt
->msg
.data
;
750 mDNSBool exception
= mDNSfalse
;
755 pkt
->isZonePublic
= mDNStrue
;
758 // Figure out what type of packet this is
760 QR_OP
= ( mDNSu8
) ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
762 if ( IsQuery( pkt
) )
764 DNSQuestion question
;
768 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
770 AppendDomainName( &zname
, &question
.qname
);
772 exception
= ( ( question
.qtype
== kDNSType_SOA
) || ( question
.qtype
== kDNSType_NS
) || ( ( question
.qtype
== kDNSType_SRV
) && IsPublicSRV( self
, &question
) ) );
774 else if ( IsUpdate( pkt
) )
776 DNSQuestion question
;
778 // It's an update. The format of the zone section is the same as the format for the question section
779 // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
781 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
783 AppendDomainName( &zname
, &question
.qname
);
785 exception
= mDNSfalse
;
788 if ( zname
.c
[0] != '\0' )
790 // Find the right zone
792 for ( pkt
->zone
= self
->zones
; pkt
->zone
; pkt
->zone
= pkt
->zone
->next
)
794 if ( ZoneHandlesName( &pkt
->zone
->name
, &zname
) )
796 VLog( "found correct zone %##s for query", pkt
->zone
->name
.c
);
798 pkt
->isZonePublic
= ( ( pkt
->zone
->type
== kDNSZonePublic
) || exception
);
800 VLog( "zone %##s is %s", pkt
->zone
->name
.c
, ( pkt
->isZonePublic
) ? "public" : "private" );
810 UDPServerTransaction(const DaemonInfo
*d
, const PktMsg
*request
, PktMsg
*reply
, mDNSBool
*trunc
)
813 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
816 mStatus err
= mStatus_NoError
;
824 sd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
825 require_action( sd
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "socket" ) );
827 // Send the packet to the nameserver
829 VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
830 ntohs(request
->msg
.h
.numQuestions
),
831 ntohs(request
->msg
.h
.numAnswers
),
832 ntohs(request
->msg
.h
.numAuthorities
),
833 ntohs(request
->msg
.h
.numAdditionals
));
834 res
= sendto( sd
, (char *)&request
->msg
, request
->len
, 0, ( struct sockaddr
* ) &d
->ns_addr
, sizeof( d
->ns_addr
) );
835 require_action( res
== (int) request
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "sendto" ) );
841 res
= select( sd
+ 1, &rset
, NULL
, NULL
, &timeout
);
842 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "select" ) );
843 require_action( ( res
> 0 ) && FD_ISSET( sd
, &rset
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - timeout" ) );
847 reply
->len
= recvfrom( sd
, &reply
->msg
, sizeof(reply
->msg
), 0, NULL
, NULL
);
848 require_action( ( ( int ) reply
->len
) >= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "recvfrom" ) );
849 require_action( reply
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - Message too short (%d bytes)", reply
->len
) );
851 // Check for truncation bit
853 if ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_TC
)
869 // Dynamic Update Utility Routines
872 // check if a request and server response complete a successful dynamic update
873 mDNSlocal mDNSBool
SuccessfulUpdateTransaction(PktMsg
*request
, PktMsg
*reply
)
876 char *vlogmsg
= NULL
;
879 if (!request
|| !reply
) { vlogmsg
= "NULL message"; goto failure
; }
880 if (request
->len
< sizeof(DNSMessageHeader
) || reply
->len
< sizeof(DNSMessageHeader
)) { vlogmsg
= "Malformatted message"; goto failure
; }
882 // check request operation
883 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
))
884 { vlogmsg
= "Request opcode not an update"; goto failure
; }
887 if ((reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)) { vlogmsg
= "Reply contains non-zero rcode"; goto failure
; }
888 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
))
889 { vlogmsg
= "Reply opcode not an update response"; goto failure
; }
891 VLog("Successful update from %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32));
895 VLog("Request %s: %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32), vlogmsg
);
899 // Allocate an appropriately sized CacheRecord and copy data from original.
900 // Name pointer in CacheRecord object is set to point to the name specified
902 mDNSlocal CacheRecord
*CopyCacheRecord(const CacheRecord
*orig
, domainname
*name
)
905 size_t size
= sizeof(*cr
);
906 if (orig
->resrec
.rdlength
> InlineCacheRDSize
) size
+= orig
->resrec
.rdlength
- InlineCacheRDSize
;
908 if (!cr
) { LogErr("CopyCacheRecord", "malloc"); return NULL
; }
909 memcpy(cr
, orig
, size
);
910 cr
->resrec
.rdata
= (RData
*)&cr
->rdatastorage
;
911 cr
->resrec
.name
= name
;
918 // Lease Hashtable Utility Routines
921 // double hash table size
922 // caller must lock table prior to invocation
923 mDNSlocal
void RehashTable(DaemonInfo
*d
)
925 RRTableElem
*ptr
, *tmp
, **new;
926 int i
, bucket
, newnbuckets
= d
->nbuckets
* 2;
928 VLog("Rehashing lease table (new size %d buckets)", newnbuckets
);
929 new = malloc(sizeof(RRTableElem
*) * newnbuckets
);
930 if (!new) { LogErr("RehashTable", "malloc"); return; }
931 bzero(new, newnbuckets
* sizeof(RRTableElem
*));
933 for (i
= 0; i
< d
->nbuckets
; i
++)
938 bucket
= ptr
->rr
.resrec
.namehash
% newnbuckets
;
941 tmp
->next
= new[bucket
];
945 d
->nbuckets
= newnbuckets
;
950 // print entire contents of hashtable, invoked via SIGINFO
951 mDNSlocal
void PrintLeaseTable(DaemonInfo
*d
)
955 char rrbuf
[MaxMsg
], addrbuf
[16];
959 if (gettimeofday(&now
, NULL
)) { LogErr("PrintTable", "gettimeofday"); return; }
960 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
962 Log("Dumping Lease Table Contents (table contains %d resource records)", d
->nelems
);
963 for (i
= 0; i
< d
->nbuckets
; i
++)
965 for (ptr
= d
->table
[i
]; ptr
; ptr
= ptr
->next
)
967 hr
= ((ptr
->expire
- now
.tv_sec
) / 60) / 60;
968 min
= ((ptr
->expire
- now
.tv_sec
) / 60) % 60;
969 sec
= (ptr
->expire
- now
.tv_sec
) % 60;
970 Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET
, &ptr
->cli
.sin_addr
, addrbuf
, 16), hr
, min
, sec
,
971 GetRRDisplayString_rdb(&ptr
->rr
.resrec
, &ptr
->rr
.resrec
.rdata
->u
, rrbuf
));
974 pthread_mutex_unlock(&d
->tablelock
);
978 // Startup SRV Registration Routines
979 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
980 // the daemon accepts requests
983 // delete all RRS of a given name/type
984 mDNSlocal mDNSu8
*putRRSetDeletion(DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
, ResourceRecord
*rr
)
986 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
987 if (!ptr
|| ptr
+ 10 >= limit
) return NULL
; // out of space
988 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
989 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
990 ptr
[2] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
>> 8);
991 ptr
[3] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
& 0xFF);
992 bzero(ptr
+4, sizeof(rr
->rroriginalttl
) + sizeof(rr
->rdlength
)); // zero ttl/rdata
993 msg
->h
.mDNS_numUpdates
++;
997 mDNSlocal mDNSu8
*PutUpdateSRV(DaemonInfo
*d
, DNSZone
* zone
, PktMsg
*pkt
, mDNSu8
*ptr
, char *regtype
, mDNSIPPort port
, mDNSBool registration
)
1000 char hostname
[1024], buf
[MaxMsg
];
1001 mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ sizeof(DNSMessage
);
1005 mDNS_SetupResourceRecord(&rr
, NULL
, 0, kDNSType_SRV
, SRV_TTL
, kDNSRecordTypeUnique
, NULL
, NULL
);
1006 rr
.resrec
.rrclass
= kDNSClass_IN
;
1007 rr
.resrec
.rdata
->u
.srv
.priority
= 0;
1008 rr
.resrec
.rdata
->u
.srv
.weight
= 0;
1009 rr
.resrec
.rdata
->u
.srv
.port
= port
;
1010 if (gethostname(hostname
, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr
.resrec
.rdata
->u
.srv
.target
, hostname
))
1011 rr
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0';
1013 MakeDomainNameFromDNSNameString(&rr
.namestorage
, regtype
);
1014 AppendDomainName(&rr
.namestorage
, &zone
->name
);
1015 VLog("%s %s", registration
? "Registering SRV record" : "Deleting existing RRSet",
1016 GetRRDisplayString_rdb(&rr
.resrec
, &rr
.resrec
.rdata
->u
, buf
));
1017 if (registration
) ptr
= PutResourceRecord(&pkt
->msg
, ptr
, &pkt
->msg
.h
.mDNS_numUpdates
, &rr
.resrec
);
1018 else ptr
= putRRSetDeletion(&pkt
->msg
, ptr
, end
, &rr
.resrec
);
1023 // perform dynamic update.
1024 // specify deletion by passing false for the register parameter, otherwise register the records.
1025 mDNSlocal
int UpdateSRV(DaemonInfo
*d
, mDNSBool registration
)
1027 TCPSocket
*sock
= NULL
;
1029 int err
= mStatus_NoError
;
1031 sock
= ConnectToServer( d
);
1032 require_action( sock
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: ConnectToServer failed" ) );
1034 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1037 mDNSu8
*ptr
= pkt
.msg
.data
;
1038 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1039 PktMsg
*reply
= NULL
;
1043 // Initialize message
1044 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1045 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1046 pkt
.src
.sin_family
= AF_INET
;
1048 // format message body
1049 ptr
= putZone(&pkt
.msg
, ptr
, end
, &zone
->name
, mDNSOpaque16fromIntVal(kDNSClass_IN
));
1050 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1052 if ( zone
->type
== kDNSZonePrivate
)
1054 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls._tcp.", d
->private_port
, registration
);
1055 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1056 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls._tcp.", d
->private_port
, registration
);
1057 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1058 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls._tcp.", d
->private_port
, registration
);
1059 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1061 if ( !registration
)
1063 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
1064 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1065 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
1066 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1071 if ( !registration
)
1073 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls.", d
->private_port
, registration
);
1074 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1075 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls.", d
->private_port
, registration
);
1076 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1077 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls.", d
->private_port
, registration
);
1078 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1081 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
1082 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1083 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
1084 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1089 if ( zone
->updateKeys
)
1091 ptr
= DNSDigest_SignMessage( &pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1092 require_action( ptr
, exit
, Log("UpdateSRV: Error constructing lease expiration update" ) );
1095 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1097 // send message, receive reply
1099 err
= SendPacket( sock
, &pkt
);
1100 require_action( !err
, exit
, Log( "UpdateSRV: SendPacket failed" ) );
1102 reply
= RecvPacket( sock
, NULL
, &closed
);
1103 require_action( reply
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: RecvPacket returned NULL" ) );
1105 ok
= SuccessfulUpdateTransaction( &pkt
, reply
);
1109 Log("SRV record registration failed with rcode %d", reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1119 mDNSPlatformTCPCloseConnection( sock
);
1125 // wrapper routines/macros
1126 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1128 // clear any existing records prior to registration
1129 mDNSlocal
int SetUpdateSRV(DaemonInfo
*d
)
1133 err
= ClearUpdateSRV(d
); // clear any existing record
1134 if (!err
) err
= UpdateSRV(d
, 1);
1139 // Argument Parsing and Configuration
1142 mDNSlocal
void PrintUsage(void)
1144 fprintf(stderr
, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1145 "Use \"dnsextd -h\" for help\n");
1148 mDNSlocal
void PrintHelp(void)
1150 fprintf(stderr
, "\n\n");
1154 "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
1155 "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
1156 "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
1157 "Discovery, Update Leases, and Long Lived Queries.)\n\n"
1159 "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
1160 "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
1161 "primary master server for this zone.\n\n"
1163 "The options are as follows:\n\n"
1165 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1167 "-d Run daemon in foreground.\n\n"
1169 "-h Print help.\n\n"
1171 "-v Verbose output.\n\n"
1176 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
1177 // returns 0 (success) if program is to continue execution
1178 // output control arguments (-f, -v) do not affect this routine
1179 mDNSlocal
int ProcessArgs(int argc
, char *argv
[], DaemonInfo
*d
)
1185 cfgfile
= strdup( CONFIG_FILE
);
1186 require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
);
1188 // defaults, may be overriden by command option
1190 // setup our sockaddr
1192 bzero( &d
->addr
, sizeof( d
->addr
) );
1193 d
->addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1194 d
->addr
.sin_port
= UnicastDNSPort
.NotAnInteger
;
1195 d
->addr
.sin_family
= AF_INET
;
1196 #ifndef NOT_HAVE_SA_LEN
1197 d
->addr
.sin_len
= sizeof( d
->addr
);
1200 // setup nameserver's sockaddr
1202 bzero(&d
->ns_addr
, sizeof(d
->ns_addr
));
1203 d
->ns_addr
.sin_family
= AF_INET
;
1204 inet_pton( AF_INET
, LOOPBACK
, &d
->ns_addr
.sin_addr
);
1205 d
->ns_addr
.sin_port
= NSIPCPort
.NotAnInteger
;
1206 #ifndef NOT_HAVE_SA_LEN
1207 d
->ns_addr
.sin_len
= sizeof( d
->ns_addr
);
1212 d
->private_port
= PrivateDNSPort
;
1213 d
->llq_port
= DNSEXTPort
;
1215 while ((opt
= getopt(argc
, argv
, "f:hdv")) != -1)
1219 case 'f': free( cfgfile
); cfgfile
= strdup( optarg
); require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
); break;
1220 case 'h': PrintHelp(); return -1;
1221 case 'd': foreground
= 1; break; // Also used when launched via OS X's launchd mechanism
1222 case 'v': verbose
= 1; break;
1223 default: goto arg_error
;
1227 err
= ParseConfig( d
, cfgfile
);
1228 require_noerr( err
, arg_error
);
1230 // Make sure we've specified some zones
1232 require_action( d
->zones
, arg_error
, err
= mStatus_UnknownErr
);
1234 // if we have a shared secret, use it for the entire zone
1236 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1238 if ( zone
->updateKeys
)
1240 AssignDomainName( &zone
->updateKeys
->domain
, &zone
->name
);
1254 // Initialization Routines
1257 // Allocate memory, initialize locks and bookkeeping variables
1258 mDNSlocal
int InitLeaseTable(DaemonInfo
*d
)
1260 if (pthread_mutex_init(&d
->tablelock
, NULL
)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1261 d
->nbuckets
= LEASETABLE_INIT_NBUCKETS
;
1263 d
->table
= malloc(sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1264 if (!d
->table
) { LogErr("InitLeaseTable", "malloc"); return -1; }
1265 bzero(d
->table
, sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1276 static const int kOn
= 1;
1278 mDNSBool
private = mDNSfalse
;
1279 struct sockaddr_in daddr
;
1283 // set up sockets on which we all ns requests
1285 self
->tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1286 require_action( dnssd_SocketValid(self
->tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1288 #if defined(SO_REUSEADDR)
1289 err
= setsockopt(self
->tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1290 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
1293 err
= bind( self
->tcpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1294 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1296 err
= listen( self
->tcpsd
, LISTENQ
);
1297 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1299 self
->udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1300 require_action( dnssd_SocketValid(self
->udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1302 #if defined(SO_REUSEADDR)
1303 err
= setsockopt(self
->udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1304 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
1307 err
= bind( self
->udpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1308 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->udpsd" ) );
1310 // set up sockets on which we receive llq requests
1312 bzero(&self
->llq_addr
, sizeof(self
->llq_addr
));
1313 self
->llq_addr
.sin_family
= AF_INET
;
1314 self
->llq_addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1315 self
->llq_addr
.sin_port
= ( self
->llq_port
.NotAnInteger
) ? self
->llq_port
.NotAnInteger
: DNSEXTPort
.NotAnInteger
;
1317 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1318 require_action( dnssd_SocketValid(self
->llq_tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1320 #if defined(SO_REUSEADDR)
1321 err
= setsockopt(self
->llq_tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1322 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
1325 err
= bind( self
->llq_tcpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1326 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
1328 err
= listen( self
->llq_tcpsd
, LISTENQ
);
1329 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1331 self
->llq_udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1332 require_action( dnssd_SocketValid(self
->llq_udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1334 #if defined(SO_REUSEADDR)
1335 err
= setsockopt(self
->llq_udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1336 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
1339 err
= bind(self
->llq_udpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1340 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
1342 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1344 err
= socketpair( AF_LOCAL
, SOCK_STREAM
, 0, sockpair
);
1345 require_action( !err
, exit
, LogErr( "SetupSockets", "socketpair" ) );
1347 self
->LLQEventListenSock
= sockpair
[0];
1348 self
->LLQEventNotifySock
= sockpair
[1];
1350 // set up socket on which we receive private requests
1352 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1353 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1354 bzero(&daddr
, sizeof(daddr
));
1355 daddr
.sin_family
= AF_INET
;
1356 daddr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1357 daddr
.sin_port
= ( self
->private_port
.NotAnInteger
) ? self
->private_port
.NotAnInteger
: PrivateDNSPort
.NotAnInteger
;
1359 self
->tlssd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1360 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1362 #if defined(SO_REUSEADDR)
1363 err
= setsockopt(self
->tlssd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1364 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
1367 err
= bind( self
->tlssd
, ( struct sockaddr
* ) &daddr
, sizeof( daddr
) );
1368 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tlssd" ) );
1370 err
= listen( self
->tlssd
, LISTENQ
);
1371 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1373 // Do we have any private zones?
1375 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
1377 if ( zone
->type
== kDNSZonePrivate
)
1386 err
= mDNSPlatformTLSSetupCerts();
1387 require_action( !err
, exit
, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1396 // periodic table updates
1399 // Delete a resource record from the nameserver via a dynamic update
1400 // sd is a socket already connected to the server
1401 mDNSlocal
void DeleteOneRecord(DaemonInfo
*d
, CacheRecord
*rr
, domainname
*zname
, TCPSocket
*sock
)
1405 mDNSu8
*ptr
= pkt
.msg
.data
;
1406 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1409 PktMsg
*reply
= NULL
;
1411 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, buf
));
1413 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1415 ptr
= putZone(&pkt
.msg
, ptr
, end
, zname
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
1417 ptr
= putDeletionRecord(&pkt
.msg
, ptr
, &rr
->resrec
);
1422 zone
= FindZone( d
, zname
);
1424 if ( zone
&& zone
->updateKeys
)
1426 ptr
= DNSDigest_SignMessage(&pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1430 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1431 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1432 pkt
.src
.sin_family
= AF_INET
;
1433 if (SendPacket( sock
, &pkt
)) { Log("DeleteOneRecord: SendPacket failed"); }
1434 reply
= RecvPacket( sock
, NULL
, &closed
);
1435 if (reply
) HdrNToH(reply
);
1436 require_action( reply
, end
, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
1438 if (!SuccessfulUpdateTransaction(&pkt
, reply
))
1439 Log("Expiration update failed with rcode %d", reply
? reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
: -1);
1442 if (!ptr
) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1443 if (reply
) free(reply
);
1446 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1447 mDNSlocal
void DeleteRecords(DaemonInfo
*d
, mDNSBool DeleteAll
)
1451 TCPSocket
*sock
= ConnectToServer(d
);
1452 if (!sock
) { Log("DeleteRecords: ConnectToServer failed"); return; }
1453 if (gettimeofday(&now
, NULL
)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
1454 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
1456 for (i
= 0; i
< d
->nbuckets
; i
++)
1458 RRTableElem
**ptr
= &d
->table
[i
];
1461 if (DeleteAll
|| (*ptr
)->expire
- now
.tv_sec
< 0)
1464 // delete record from server
1465 DeleteOneRecord(d
, &(*ptr
)->rr
, &(*ptr
)->zone
, sock
);
1467 *ptr
= (*ptr
)->next
;
1471 else ptr
= &(*ptr
)->next
;
1474 pthread_mutex_unlock(&d
->tablelock
);
1475 mDNSPlatformTCPCloseConnection( sock
);
1479 // main update request handling
1482 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
1483 mDNSlocal
void UpdateLeaseTable(PktMsg
*pkt
, DaemonInfo
*d
, mDNSs32 lease
)
1485 RRTableElem
**rptr
, *tmp
;
1486 int i
, allocsize
, bucket
;
1487 LargeCacheRecord lcr
;
1488 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1489 const mDNSu8
*ptr
, *end
;
1490 struct timeval time
;
1494 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
1496 ptr
= pkt
->msg
.data
;
1497 end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
1498 ptr
= getQuestion(&pkt
->msg
, ptr
, end
, 0, &zone
);
1499 if (!ptr
) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup
; }
1500 ptr
= LocateAuthorities(&pkt
->msg
, end
);
1501 if (!ptr
) { Log("UpdateLeaseTable: Format error"); goto cleanup
; }
1503 for (i
= 0; i
< pkt
->msg
.h
.mDNS_numUpdates
; i
++)
1505 mDNSBool DeleteAllRRSets
= mDNSfalse
, DeleteOneRRSet
= mDNSfalse
, DeleteOneRR
= mDNSfalse
;
1507 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1508 if (!ptr
) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup
; }
1509 bucket
= rr
->namehash
% d
->nbuckets
;
1510 rptr
= &d
->table
[bucket
];
1513 if (rr
->rrtype
== kDNSQType_ANY
&& !rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1514 DeleteAllRRSets
= mDNStrue
; // delete all rrsets for a name
1515 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1516 DeleteOneRRSet
= mDNStrue
;
1517 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSClass_NONE
)
1518 DeleteOneRR
= mDNStrue
;
1520 if (DeleteAllRRSets
|| DeleteOneRRSet
|| DeleteOneRR
)
1524 if (SameDomainName((*rptr
)->rr
.resrec
.name
, rr
->name
) &&
1526 (DeleteOneRRSet
&& (*rptr
)->rr
.resrec
.rrtype
== rr
->rrtype
) ||
1527 (DeleteOneRR
&& SameResourceRecord(&(*rptr
)->rr
.resrec
, rr
))))
1530 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp
->rr
.resrec
, &tmp
->rr
.resrec
.rdata
->u
, buf
));
1531 *rptr
= (*rptr
)->next
;
1535 else rptr
= &(*rptr
)->next
;
1540 // see if add or refresh
1541 while (*rptr
&& !SameResourceRecord(&(*rptr
)->rr
.resrec
, rr
)) rptr
= &(*rptr
)->next
;
1545 if (gettimeofday(&time
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1546 (*rptr
)->expire
= time
.tv_sec
+ (unsigned)lease
;
1547 VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1551 // New record - add to table
1552 if (d
->nelems
> d
->nbuckets
)
1555 bucket
= rr
->namehash
% d
->nbuckets
;
1556 rptr
= &d
->table
[bucket
];
1558 if (gettimeofday(&time
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1559 allocsize
= sizeof(RRTableElem
);
1560 if (rr
->rdlength
> InlineCacheRDSize
) allocsize
+= (rr
->rdlength
- InlineCacheRDSize
);
1561 tmp
= malloc(allocsize
);
1562 if (!tmp
) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup
; }
1563 memcpy(&tmp
->rr
, &lcr
.r
, sizeof(CacheRecord
) + rr
->rdlength
- InlineCacheRDSize
);
1564 tmp
->rr
.resrec
.rdata
= (RData
*)&tmp
->rr
.rdatastorage
;
1565 AssignDomainName(&tmp
->name
, rr
->name
);
1566 tmp
->rr
.resrec
.name
= &tmp
->name
;
1567 tmp
->expire
= time
.tv_sec
+ (unsigned)lease
;
1568 tmp
->cli
.sin_addr
= pkt
->src
.sin_addr
;
1569 AssignDomainName(&tmp
->zone
, &zone
.qname
);
1570 tmp
->next
= d
->table
[bucket
];
1571 d
->table
[bucket
] = tmp
;
1573 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1579 pthread_mutex_unlock(&d
->tablelock
);
1583 // Given a successful reply from a server, create a new reply that contains lease information
1584 // Replies are currently not signed !!!KRS change this
1585 mDNSlocal PktMsg
*FormatLeaseReply(DaemonInfo
*d
, PktMsg
*orig
, mDNSu32 lease
)
1592 reply
= malloc(sizeof(*reply
));
1593 if (!reply
) { LogErr("FormatLeaseReply", "malloc"); return NULL
; }
1594 flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
1597 InitializeDNSMessage(&reply
->msg
.h
, orig
->msg
.h
.id
, flags
);
1598 reply
->src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // unused except for log messages
1599 reply
->src
.sin_family
= AF_INET
;
1600 ptr
= reply
->msg
.data
;
1601 end
= (mDNSu8
*)&reply
->msg
+ sizeof(DNSMessage
);
1602 ptr
= putUpdateLease(&reply
->msg
, ptr
, lease
);
1603 if (!ptr
) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply
); return NULL
; }
1604 reply
->len
= ptr
- (mDNSu8
*)&reply
->msg
;
1609 // pkt is thread-local, not requiring locking
1618 PktMsg
* reply
= NULL
;
1619 PktMsg
* leaseReply
;
1622 TCPSocket
* sock
= NULL
;
1625 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == kDNSFlag0_OP_Update
)
1627 int i
, adds
= 0, dels
= 0;
1628 const mDNSu8
*ptr
, *end
= (mDNSu8
*)&request
->msg
+ request
->len
;
1630 lease
= GetPktLease(NULL
, &request
->msg
, end
);
1631 ptr
= LocateAuthorities(&request
->msg
, end
);
1632 for (i
= 0; i
< request
->msg
.h
.mDNS_numUpdates
; i
++)
1634 LargeCacheRecord lcr
;
1635 ptr
= GetLargeResourceRecord(NULL
, &request
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1636 if (lcr
.r
.resrec
.rroriginalttl
) adds
++; else dels
++;
1641 static const mDNSOpaque16 UpdateRefused
= { { kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
, kDNSFlag1_RC_Refused
} };
1642 Log("Rejecting Update Request with %d additions but no lease", adds
);
1643 reply
= malloc(sizeof(*reply
));
1644 bzero(&reply
->src
, sizeof(reply
->src
));
1645 reply
->len
= sizeof(DNSMessageHeader
);
1647 reply
->isZonePublic
= 0;
1648 InitializeDNSMessage(&reply
->msg
.h
, request
->msg
.h
.id
, UpdateRefused
);
1651 if (lease
> 1200) // Don't allow lease greater than 20 minutes
1654 // Send msg to server, read reply
1656 if ( request
->len
<= 512 )
1660 if ( UDPServerTransaction( self
, request
, &buf
, &trunc
) < 0 )
1662 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1666 VLog("HandleRequest - answer truncated. Using TCP");
1670 reply
= &buf
; // success
1679 sock
= ConnectToServer( self
);
1680 require_action_quiet( sock
, exit
, err
= mStatus_UnknownErr
; Log( "Discarding request from %s due to connection errors", inet_ntop( AF_INET
, &request
->src
.sin_addr
, addrbuf
, 32 ) ) );
1682 res
= SendPacket( sock
, request
);
1683 require_action_quiet( res
>= 0, exit
, err
= mStatus_UnknownErr
; Log( "Couldn't relay message from %s to server. Discarding.", inet_ntop(AF_INET
, &request
->src
.sin_addr
, addrbuf
, 32 ) ) );
1685 reply
= RecvPacket( sock
, &buf
, &closed
);
1688 // IMPORTANT: reply is in network byte order at this point in the code
1689 // We keep it this way because we send it back to the client in the same form
1693 if ( reply
&& ( ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
) ) )
1696 mDNSBool ok
= SuccessfulUpdateTransaction( request
, reply
);
1697 require_action( ok
, exit
, err
= mStatus_UnknownErr
; VLog( "Message from %s not a successful update.", inet_ntop(AF_INET
, &request
->src
.sin_addr
, addrbuf
, 32 ) ) );
1699 UpdateLeaseTable( request
, self
, lease
);
1703 leaseReply
= FormatLeaseReply( self
, reply
, lease
);
1707 Log("HandleRequest - unable to format lease reply");
1710 // %%% Looks like a potential memory leak -- who frees the original reply?
1714 // tell the main thread there was an update so it can send LLQs
1716 if ( send( self
->LLQEventNotifySock
, pingmsg
, sizeof( pingmsg
), 0 ) != sizeof( pingmsg
) )
1718 LogErr("HandleRequest", "send");
1726 mDNSPlatformTCPCloseConnection( sock
);
1729 if ( reply
== &buf
)
1731 reply
= malloc( sizeof( *reply
) );
1735 reply
->len
= buf
.len
;
1736 memcpy(&reply
->msg
, &buf
.msg
, buf
.len
);
1740 LogErr("HandleRequest", "malloc");
1749 // LLQ Support Routines
1752 // Set fields of an LLQ OPT Resource Record
1753 mDNSlocal
void FormatLLQOpt(AuthRecord
*opt
, int opcode
, const mDNSOpaque64
*const id
, mDNSs32 lease
)
1755 bzero(opt
, sizeof(*opt
));
1756 mDNS_SetupResourceRecord(opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
1757 opt
->resrec
.rrclass
= NormalMaxDNSMessageData
;
1758 opt
->resrec
.rdlength
= LLQ_OPT_RDLEN
;
1759 opt
->resrec
.rdestimate
= LLQ_OPT_RDLEN
;
1760 opt
->resrec
.rdata
->u
.opt
.opt
= kDNSOpt_LLQ
;
1761 opt
->resrec
.rdata
->u
.opt
.optlen
= sizeof(LLQOptData
);
1762 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.vers
= kLLQ_Vers
;
1763 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.llqOp
= opcode
;
1764 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.err
= LLQErr_NoError
;
1765 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.id
= *id
;
1766 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.llqlease
= lease
;
1769 // Calculate effective remaining lease of an LLQ
1770 mDNSlocal mDNSu32
LLQLease(LLQEntry
*e
)
1774 gettimeofday(&t
, NULL
);
1775 if (e
->expire
< t
.tv_sec
) return 0;
1776 else return e
->expire
- t
.tv_sec
;
1779 mDNSlocal
void DeleteLLQ(DaemonInfo
*d
, LLQEntry
*e
)
1781 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
1782 LLQEntry
**ptr
= &d
->LLQTable
[bucket
];
1783 AnswerListElem
*a
= e
->AnswerList
;
1786 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1787 VLog("Deleting LLQ table entry for %##s client %s", e
->qname
.c
, addr
);
1789 if (a
&& !(--a
->refcount
) && d
->AnswerTableCount
>= LLQ_TABLESIZE
)
1791 // currently, generating initial answers blocks the main thread, so we keep the answer list
1792 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1793 // if the ref count drops to zero AND there are more table elements than buckets
1794 // !!!KRS update this when we make the table dynamically growable
1796 CacheRecord
*cr
= a
->KnownAnswers
, *tmp
;
1797 AnswerListElem
**tbl
= &d
->AnswerTable
[bucket
];
1806 while (*tbl
&& *tbl
!= a
) tbl
= &(*tbl
)->next
;
1807 if (*tbl
) { *tbl
= (*tbl
)->next
; free(a
); d
->AnswerTableCount
--; }
1808 else Log("Error: DeleteLLQ - AnswerList not found in table");
1811 // remove LLQ from table, free memory
1812 while(*ptr
&& *ptr
!= e
) ptr
= &(*ptr
)->next
;
1813 if (!*ptr
) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1814 *ptr
= (*ptr
)->next
;
1818 mDNSlocal
int SendLLQ(DaemonInfo
*d
, PktMsg
*pkt
, struct sockaddr_in dst
, TCPSocket
*sock
)
1827 if ( SendPacket( sock
, pkt
) != 0 )
1829 LogErr("DaemonInfo", "MySend");
1830 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1835 if (sendto(d
->llq_udpsd
, &pkt
->msg
, pkt
->len
, 0, (struct sockaddr
*)&dst
, sizeof(dst
)) != (int)pkt
->len
)
1837 LogErr("DaemonInfo", "sendto");
1838 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1847 mDNSlocal CacheRecord
*AnswerQuestion(DaemonInfo
*d
, AnswerListElem
*e
)
1851 TCPSocket
*sock
= NULL
;
1852 const mDNSu8
*ansptr
;
1853 mDNSu8
*end
= q
.msg
.data
;
1854 PktMsg buf
, *reply
= NULL
;
1855 LargeCacheRecord lcr
;
1856 CacheRecord
*AnswerList
= NULL
;
1859 VLog("Querying server for %##s type %d", e
->name
.c
, e
->type
);
1861 InitializeDNSMessage(&q
.msg
.h
, zeroID
, uQueryFlags
);
1863 end
= putQuestion(&q
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->name
, e
->type
, kDNSClass_IN
);
1864 if (!end
) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end
; }
1865 q
.len
= (int)(end
- (mDNSu8
*)&q
.msg
);
1873 if (UDPServerTransaction(d
, &q
, &buf
, &trunc
) < 0)
1874 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e
->name
.c
);
1876 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e
->name
.c
); e
->UseTCP
= mDNStrue
; }
1877 else reply
= &buf
; // success
1884 sock
= ConnectToServer(d
);
1885 if (!sock
) { Log("AnswerQuestion: ConnectToServer failed"); goto end
; }
1886 if (SendPacket( sock
, &q
)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock
); goto end
; }
1887 reply
= RecvPacket( sock
, NULL
, &closed
);
1888 mDNSPlatformTCPCloseConnection( sock
);
1889 require_action( reply
, end
, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1893 if (reply
) HdrNToH(reply
);
1895 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
))
1896 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end
; }
1897 rcode
= (mDNSu8
)(reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1898 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e
->name
.c
, e
->type
, rcode
); goto end
; }
1900 end
= (mDNSu8
*)&reply
->msg
+ reply
->len
;
1901 ansptr
= LocateAnswers(&reply
->msg
, end
);
1902 if (!ansptr
) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end
; }
1904 for (i
= 0; i
< reply
->msg
.h
.numAnswers
; i
++)
1906 ansptr
= GetLargeResourceRecord(NULL
, &reply
->msg
, ansptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1907 if (!ansptr
) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end
; }
1908 if (lcr
.r
.resrec
.rrtype
!= e
->type
|| lcr
.r
.resrec
.rrclass
!= kDNSClass_IN
|| !SameDomainName(lcr
.r
.resrec
.name
, &e
->name
))
1910 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1911 lcr
.r
.resrec
.name
->c
, lcr
.r
.resrec
.rrtype
, e
->name
.c
, e
->type
);
1915 CacheRecord
*cr
= CopyCacheRecord(&lcr
.r
, &e
->name
);
1916 if (!cr
) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end
; }
1917 cr
->next
= AnswerList
;
1923 if (reply
&& reply
!= &buf
) free(reply
);
1927 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1928 mDNSlocal
void *UpdateAnswerList(void *args
)
1930 CacheRecord
*cr
, *NewAnswers
, **na
, **ka
; // "new answer", "known answer"
1931 DaemonInfo
*d
= ((UpdateAnswerListArgs
*)args
)->d
;
1932 AnswerListElem
*a
= ((UpdateAnswerListArgs
*)args
)->a
;
1937 // get up to date answers
1938 NewAnswers
= AnswerQuestion(d
, a
);
1940 // first pass - mark all answers for deletion
1941 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1942 (*ka
)->resrec
.rroriginalttl
= (unsigned)-1; // -1 means delete
1944 // second pass - mark answers pre-existent
1945 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1947 for (na
= &NewAnswers
; *na
; na
= &(*na
)->next
)
1949 if (SameResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
))
1950 { (*ka
)->resrec
.rroriginalttl
= 0; break; } // 0 means no change
1954 // third pass - add new records to Event list
1958 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1959 if (SameResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
)) break;
1962 // answer is not in list - splice from NewAnswers list, add to Event list
1964 *na
= (*na
)->next
; // splice from list
1965 cr
->next
= a
->EventList
; // add spliced record to event list
1967 cr
->resrec
.rroriginalttl
= 1; // 1 means add
1969 else na
= &(*na
)->next
;
1972 // move all the removes from the answer list to the event list
1973 ka
= &a
->KnownAnswers
;
1976 if ((*ka
)->resrec
.rroriginalttl
== (unsigned)-1)
1980 cr
->next
= a
->EventList
;
1983 else ka
= &(*ka
)->next
;
1986 // lastly, free the remaining records (known answers) in NewAnswers list
1990 NewAnswers
= NewAnswers
->next
;
1997 mDNSlocal
void SendEvents(DaemonInfo
*d
, LLQEntry
*e
)
2001 mDNSu8
*end
= (mDNSu8
*)&response
.msg
.data
;
2003 char rrbuf
[MaxMsg
], addrbuf
[32];
2006 // Should this really be random? Do we use the msgID on the receiving end?
2007 msgID
.NotAnInteger
= random();
2008 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2009 InitializeDNSMessage(&response
.msg
.h
, msgID
, ResponseFlags
);
2010 end
= putQuestion(&response
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2011 if (!end
) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
2013 // put adds/removes in packet
2014 for (cr
= e
->AnswerList
->EventList
; cr
; cr
= cr
->next
)
2016 if (verbose
) GetRRDisplayString_rdb(&cr
->resrec
, &cr
->resrec
.rdata
->u
, rrbuf
);
2017 VLog("%s (%s): %s", addrbuf
, (mDNSs32
)cr
->resrec
.rroriginalttl
< 0 ? "Remove": "Add", rrbuf
);
2018 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAnswers
, &cr
->resrec
, cr
->resrec
.rroriginalttl
);
2019 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
2022 FormatLLQOpt(&opt
, kLLQOp_Event
, &e
->id
, LLQLease(e
));
2023 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2024 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
2026 response
.len
= (int)(end
- (mDNSu8
*)&response
.msg
);
2027 if (SendLLQ(d
, &response
, e
->cli
, NULL
) < 0) LogMsg("Error: SendEvents - SendLLQ");
2030 mDNSlocal
void PrintLLQAnswers(DaemonInfo
*d
)
2035 Log("Printing LLQ Answer Table contents");
2037 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2039 AnswerListElem
*a
= d
->AnswerTable
[i
];
2043 const CacheRecord
*rr
= a
->KnownAnswers
;
2044 while (rr
) { ancount
++; rr
= rr
->next
; }
2045 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a
, a
->name
.c
, a
->type
, a
->refcount
, ancount
);
2046 for (rr
= a
->KnownAnswers
; rr
; rr
= rr
->next
) Log("\t%s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, rrbuf
));
2052 mDNSlocal
void PrintLLQTable(DaemonInfo
*d
)
2058 Log("Printing LLQ table contents");
2060 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2069 case RequestReceived
: state
= "RequestReceived"; break;
2070 case ChallengeSent
: state
= "ChallengeSent"; break;
2071 case Established
: state
= "Established"; break;
2072 default: state
= "unknown";
2074 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2076 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
2077 addr
, state
, e
->qname
.c
, e
->qtype
, e
->lease
, LLQLease(e
), e
->AnswerList
);
2083 // Send events to clients as a result of a change in the zone
2084 mDNSlocal
void GenLLQEvents(DaemonInfo
*d
)
2089 UpdateAnswerListArgs
*args
;
2091 VLog("Generating LLQ Events");
2093 gettimeofday(&t
, NULL
);
2095 // get all answers up to date
2096 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2098 AnswerListElem
*a
= d
->AnswerTable
[i
];
2101 args
= malloc(sizeof(*args
));
2102 if (!args
) { LogErr("GenLLQEvents", "malloc"); return; }
2105 if (pthread_create(&a
->tid
, NULL
, UpdateAnswerList
, args
) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
2111 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2113 AnswerListElem
*a
= d
->AnswerTable
[i
];
2116 if (pthread_join(a
->tid
, NULL
)) LogErr("GenLLQEvents", "pthread_join");
2121 // for each established LLQ, send events
2122 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2124 e
= &d
->LLQTable
[i
];
2127 if ((*e
)->expire
< t
.tv_sec
) DeleteLLQ(d
, *e
);
2130 if ((*e
)->state
== Established
&& (*e
)->AnswerList
->EventList
) SendEvents(d
, *e
);
2136 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2137 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2139 AnswerListElem
*a
= d
->AnswerTable
[i
];
2144 CacheRecord
*cr
= a
->EventList
, *tmp
;
2149 if ((signed)tmp
->resrec
.rroriginalttl
< 0) free(tmp
);
2152 tmp
->next
= a
->KnownAnswers
;
2153 a
->KnownAnswers
= tmp
;
2154 tmp
->resrec
.rroriginalttl
= 0;
2157 a
->EventList
= NULL
;
2164 mDNSlocal
void SetAnswerList(DaemonInfo
*d
, LLQEntry
*e
)
2166 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
2167 AnswerListElem
*a
= d
->AnswerTable
[bucket
];
2168 while (a
&& (a
->type
!= e
->qtype
||!SameDomainName(&a
->name
, &e
->qname
))) a
= a
->next
;
2171 a
= malloc(sizeof(*a
));
2172 if (!a
) { LogErr("SetAnswerList", "malloc"); return; }
2173 AssignDomainName(&a
->name
, &e
->qname
);
2176 a
->EventList
= NULL
;
2177 a
->UseTCP
= mDNSfalse
;
2178 a
->next
= d
->AnswerTable
[bucket
];
2179 d
->AnswerTable
[bucket
] = a
;
2180 d
->AnswerTableCount
++;
2181 a
->KnownAnswers
= AnswerQuestion(d
, a
);
2188 // Allocate LLQ entry, insert into table
2189 mDNSlocal LLQEntry
*NewLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, mDNSu32 lease
)
2193 int bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2196 e
= malloc(sizeof(*e
));
2197 if (!e
) { LogErr("NewLLQ", "malloc"); return NULL
; }
2199 inet_ntop(AF_INET
, &cli
.sin_addr
, addr
, 32);
2200 VLog("Allocating LLQ entry for client %s question %##s type %d", addr
, qname
->c
, qtype
);
2202 // initialize structure
2204 AssignDomainName(&e
->qname
, qname
);
2206 e
->id
= zeroOpaque64
;
2207 e
->state
= RequestReceived
;
2208 e
->AnswerList
= NULL
;
2210 if (lease
< LLQ_MIN_LEASE
) lease
= LLQ_MIN_LEASE
;
2211 else if (lease
> LLQ_MAX_LEASE
) lease
= LLQ_MAX_LEASE
;
2213 gettimeofday(&t
, NULL
);
2214 e
->expire
= t
.tv_sec
+ (int)lease
;
2218 e
->next
= d
->LLQTable
[bucket
];
2219 d
->LLQTable
[bucket
] = e
;
2224 // Handle a refresh request from client
2225 mDNSlocal
void LLQRefresh(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2229 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2232 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2233 VLog("%s LLQ for %##s from %s", llq
->llqlease
? "Refreshing" : "Deleting", e
->qname
.c
, addr
);
2238 if (llq
->llqlease
< LLQ_MIN_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2239 else if (llq
->llqlease
> LLQ_MAX_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2240 gettimeofday(&t
, NULL
);
2241 e
->expire
= t
.tv_sec
+ llq
->llqlease
;
2244 ack
.src
.sin_addr
.s_addr
= 0; // unused
2245 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2246 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2247 if (!end
) { Log("Error: putQuestion"); return; }
2249 FormatLLQOpt(&opt
, kLLQOp_Refresh
, &e
->id
, llq
->llqlease
? LLQLease(e
) : 0);
2250 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2251 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2253 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2254 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQRefresh");
2256 if (llq
->llqlease
) e
->state
= Established
;
2257 else DeleteLLQ(d
, e
);
2260 // Complete handshake with Ack an initial answers
2261 mDNSlocal
void LLQCompleteHandshake(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2267 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2268 char rrbuf
[MaxMsg
], addrbuf
[32];
2270 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2272 if (!mDNSSameOpaque64(&llq
->id
, &e
->id
) ||
2273 llq
->vers
!= kLLQ_Vers
||
2274 llq
->llqOp
!= kLLQOp_Setup
||
2275 llq
->err
!= LLQErr_NoError
||
2276 llq
->llqlease
> e
->lease
+ LLQ_LEASE_FUDGE
||
2277 llq
->llqlease
< e
->lease
- LLQ_LEASE_FUDGE
)
2279 Log("Incorrect challenge response from %s", addr
);
2283 if (e
->state
== Established
) VLog("Retransmitting LLQ ack + answers for %##s", e
->qname
.c
);
2284 else VLog("Delivering LLQ ack + answers for %##s", e
->qname
.c
);
2286 // format ack + answers
2287 ack
.src
.sin_addr
.s_addr
= 0; // unused
2288 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2289 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2290 if (!end
) { Log("Error: putQuestion"); return; }
2292 if (e
->state
!= Established
) { SetAnswerList(d
, e
); e
->state
= Established
; }
2294 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2295 for (ptr
= e
->AnswerList
->KnownAnswers
; ptr
; ptr
= ptr
->next
)
2297 if (verbose
) GetRRDisplayString_rdb(&ptr
->resrec
, &ptr
->resrec
.rdata
->u
, rrbuf
);
2298 VLog("%s Intitial Answer - %s", addr
, rrbuf
);
2299 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAnswers
, &ptr
->resrec
, 1);
2300 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2303 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2304 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2305 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2307 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2308 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQCompleteHandshake");
2311 mDNSlocal
void LLQSetupChallenge(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
)
2315 mDNSu8
*end
= challenge
.msg
.data
;
2318 if (e
->state
== ChallengeSent
) VLog("Retransmitting LLQ setup challenge for %##s", e
->qname
.c
);
2319 else VLog("Sending LLQ setup challenge for %##s", e
->qname
.c
);
2321 if (!mDNSOpaque64IsZero(&llq
->id
)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2322 if (llq
->llqOp
!= kLLQOp_Setup
) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2324 if (mDNSOpaque64IsZero(&e
->id
)) // don't regenerate random ID for retransmissions
2326 // construct ID <time><random>
2327 gettimeofday(&t
, NULL
);
2328 e
->id
.l
[0] = t
.tv_sec
;
2329 e
->id
.l
[1] = random();
2332 // format response (query + LLQ opt rr)
2333 challenge
.src
.sin_addr
.s_addr
= 0; // unused
2334 InitializeDNSMessage(&challenge
.msg
.h
, msgID
, ResponseFlags
);
2335 end
= putQuestion(&challenge
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2336 if (!end
) { Log("Error: putQuestion"); return; }
2337 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2338 end
= PutResourceRecordTTLJumbo(&challenge
.msg
, end
, &challenge
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2339 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2340 challenge
.len
= (int)(end
- (mDNSu8
*)&challenge
.msg
);
2341 if (SendLLQ(d
, &challenge
, e
->cli
, NULL
)) { Log("Error: LLQSetupChallenge"); return; }
2342 e
->state
= ChallengeSent
;
2345 // Take action on an LLQ message from client. Entry must be initialized and in table
2346 mDNSlocal
void UpdateLLQ(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2350 case RequestReceived
:
2354 gettimeofday(&t
, NULL
);
2355 e
->id
.l
[0] = t
.tv_sec
; // construct ID <time><random>
2356 e
->id
.l
[1] = random();
2358 LLQCompleteHandshake( d
, e
, llq
, msgID
, sock
);
2360 // Set the state to established because we've just set the LLQ up using TCP
2361 e
->state
= Established
;
2365 LLQSetupChallenge(d
, e
, llq
, msgID
);
2369 if (mDNSOpaque64IsZero(&llq
->id
)) LLQSetupChallenge(d
, e
, llq
, msgID
); // challenge sent and lost
2370 else LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
);
2373 if (mDNSOpaque64IsZero(&llq
->id
))
2375 // client started over. reset state.
2376 LLQEntry
*newe
= NewLLQ(d
, e
->cli
, &e
->qname
, e
->qtype
, llq
->llqlease
);
2379 LLQSetupChallenge(d
, newe
, llq
, msgID
);
2382 else if (llq
->llqOp
== kLLQOp_Setup
)
2383 { LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
); return; } // Ack lost
2384 else if (llq
->llqOp
== kLLQOp_Refresh
)
2385 { LLQRefresh(d
, e
, llq
, msgID
, sock
); return; }
2386 else { Log("Unhandled message for established LLQ"); return; }
2390 mDNSlocal LLQEntry
*LookupLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, const mDNSOpaque64
*const id
)
2392 int bucket
= bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2393 LLQEntry
*ptr
= d
->LLQTable
[bucket
];
2397 if (((ptr
->state
== ChallengeSent
&& mDNSOpaque64IsZero(id
) && (cli
.sin_port
== ptr
->cli
.sin_port
)) || // zero-id due to packet loss OK in state ChallengeSent
2398 mDNSSameOpaque64(id
, &ptr
->id
)) && // id match
2399 (cli
.sin_addr
.s_addr
== ptr
->cli
.sin_addr
.s_addr
) && (qtype
== ptr
->qtype
) && SameDomainName(&ptr
->qname
, qname
)) // same source, type, qname
2416 pkt
->msg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
2418 res
= sendto( d
->udpsd
, &pkt
->msg
, pkt
->len
, 0, ( struct sockaddr
* ) &pkt
->src
, sizeof( pkt
->src
) );
2419 require_action( res
== ( int ) pkt
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvNotify", "sendto" ) );
2427 mDNSlocal
int RecvLLQ( DaemonInfo
*d
, PktMsg
*pkt
, TCPSocket
*sock
)
2430 LargeCacheRecord opt
;
2433 const mDNSu8
*qptr
= pkt
->msg
.data
;
2434 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2436 LLQOptData
*llq
= NULL
;
2440 aptr
= LocateAdditionals(&pkt
->msg
, end
); // Can't do this until after HdrNToH(pkt);
2441 inet_ntop(AF_INET
, &pkt
->src
.sin_addr
, addr
, 32);
2443 VLog("Received LLQ msg from %s", addr
);
2444 // sanity-check packet
2445 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2447 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
2451 // Locate the OPT record.
2452 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2453 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2454 // but not necessarily the *last* entry in the Additional Section.
2455 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2457 aptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, aptr
, end
, 0, kDNSRecordTypePacketAdd
, &opt
);
2458 if (!aptr
) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr
, i
); goto end
; }
2459 if (opt
.r
.resrec
.rrtype
== kDNSType_OPT
) break;
2463 if (opt
.r
.resrec
.rrtype
!= kDNSType_OPT
) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr
); goto end
; }
2464 if (opt
.r
.resrec
.rdlength
< pkt
->msg
.h
.numQuestions
* LLQ_OPT_RDLEN
) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr
, opt
.r
.resrec
.rdlength
, pkt
->msg
.h
.numQuestions
); }
2466 // dispatch each question
2467 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
2469 qptr
= getQuestion(&pkt
->msg
, qptr
, end
, 0, &q
);
2470 if (!qptr
) { Log("Malformatted LLQ from %s: cannot read question %d", addr
, i
); goto end
; }
2471 llq
= (LLQOptData
*)&opt
.r
.resrec
.rdata
->u
.opt
.OptData
.llq
+ i
; // point into OptData at index i
2472 if (llq
->vers
!= kLLQ_Vers
) { Log("LLQ from %s contains bad version %d (expected %d)", addr
, llq
->vers
, kLLQ_Vers
); goto end
; }
2474 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2477 // no entry - if zero ID, create new
2478 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2481 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2491 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
2493 const mDNSu8
* lastPtr
= NULL
;
2494 const mDNSu8
* ptr
= NULL
;
2495 DomainAuthInfo
* keys
;
2496 mDNSu8
* end
= ( mDNSu8
* ) &pkt
->msg
+ pkt
->len
;
2497 LargeCacheRecord lcr
;
2498 mDNSBool hasTSIG
= mDNSfalse
;
2499 mDNSBool strip
= mDNSfalse
;
2500 mDNSBool ok
= mDNSfalse
;
2503 // Unused parameters
2511 if ( pkt
->msg
.h
.numAdditionals
)
2513 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2516 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2519 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2522 Log("Unable to read additional record");
2528 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2532 LogMsg( "IsAuthorized: unable to find Additional section" );
2536 // If we don't know what zone this is, then it's authorized.
2545 if ( IsQuery( pkt
) )
2547 keys
= pkt
->zone
->queryKeys
;
2550 else if ( IsUpdate( pkt
) )
2552 keys
= pkt
->zone
->updateKeys
;
2562 if ( pkt
->isZonePublic
)
2568 // If there are no keys, then we're authorized
2570 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
2572 Log( "Invalid TSIG spec %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2573 *rcode
= kDNSFlag1_RC_NotAuth
;
2574 *tcode
= TSIG_ErrBadKey
;
2580 // Find the right key
2582 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2584 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
2592 Log( "Invalid TSIG name %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2593 *rcode
= kDNSFlag1_RC_NotAuth
;
2594 *tcode
= TSIG_ErrBadKey
;
2600 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2601 // lifting of message verification
2603 pkt
->msg
.h
.numAdditionals
--;
2607 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2611 pkt
->msg
.h
.numAdditionals
++;
2615 if ( hasTSIG
&& strip
)
2617 // Strip the TSIG from the message
2619 pkt
->msg
.h
.numAdditionals
--;
2620 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2628 // request handler wrappers for TCP and UDP requests
2629 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2637 UDPContext
* context
= ( UDPContext
* ) vptr
;
2638 PktMsg
* reply
= NULL
;
2642 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2643 // may give us a long answer that would require truncation for UDP delivery to client
2645 reply
= HandleRequest( context
->d
, &context
->pkt
);
2646 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
2648 res
= sendto( context
->sd
, &reply
->msg
, reply
->len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2649 require_action_quiet( res
== ( int ) reply
->len
, exit
, LogErr( "UDPMessageHandler", "sendto" ) );
2660 pthread_exit( NULL
);
2673 UDPContext
* context
= NULL
;
2677 DomainAuthInfo
* key
;
2678 unsigned int clisize
= sizeof( context
->cliaddr
);
2680 mStatus err
= mStatus_NoError
;
2682 context
= malloc( sizeof( UDPContext
) );
2683 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2685 bzero( context
, sizeof( *context
) );
2689 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
2691 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvUDPMessage", "recvfrom" ) );
2692 context
->pkt
.len
= res
;
2693 require_action( clisize
== sizeof( context
->cliaddr
), exit
, err
= mStatus_UnknownErr
; Log( "Client address of unknown size %d", clisize
) );
2694 context
->pkt
.src
= context
->cliaddr
;
2696 // Set the zone in the packet
2698 SetZone( context
->d
, &context
->pkt
);
2700 // Notify messages handled by main thread
2702 if ( IsNotify( &context
->pkt
) )
2704 int err
= RecvNotify( self
, &context
->pkt
);
2708 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2710 if ( IsLLQRequest( &context
->pkt
) )
2712 // LLQ messages handled by main thread
2714 int err
= RecvLLQ( self
, &context
->pkt
, NULL
);
2719 if ( IsLLQAck(&context
->pkt
) )
2721 // !!!KRS need to do acks + retrans
2727 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2728 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2730 pthread_detach(tid
);
2737 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2739 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2740 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_NXDomain
;
2742 res
= sendto( sd
, &reply
.msg
, reply
.len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2743 require_action_quiet( res
== ( int ) reply
.len
, exit
, LogErr( "RecvUDPMessage", "sendto" ) );
2745 err
= mStatus_NoAuth
;
2750 if ( err
&& context
)
2762 TCPContext
* context
2767 if ( context
->sock
)
2769 mDNSPlatformTCPCloseConnection( context
->sock
);
2783 TCPContext
* context
= ( TCPContext
* ) vptr
;
2784 PktMsg
* reply
= NULL
;
2788 //!!!KRS if this read blocks indefinitely, we can run out of threads
2791 reply
= HandleRequest( context
->d
, &context
->pkt
);
2792 require_action_quiet( reply
, exit
, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2794 // deliver reply to client
2796 res
= SendPacket( context
->sock
, reply
);
2797 require_action( res
>= 0, exit
, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2801 FreeTCPContext( context
);
2818 TCPContext
* context
= ( TCPContext
* ) param
;
2822 DomainAuthInfo
* key
;
2825 mDNSBool freeContext
= mDNStrue
;
2826 mStatus err
= mStatus_NoError
;
2828 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2829 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2830 // wire. We'll let it do that, and wait for the next packet which will be ours.
2832 pkt
= RecvPacket( context
->sock
, &context
->pkt
, &closed
);
2833 if (pkt
) HdrNToH(pkt
);
2834 require_action( pkt
|| !closed
, exit
, err
= mStatus_UnknownErr
; LogMsg( "client disconnected" ) );
2838 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2839 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2840 // are sent over UDP
2842 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2844 // Set's the DNS Zone that is associated with this message
2846 SetZone( context
->d
, &context
->pkt
);
2848 // IsAuthorized will make sure the message is authorized for the designated zone.
2849 // After verifying the signature, it will strip the TSIG from the message
2851 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2853 if ( IsLLQRequest( &context
->pkt
) )
2855 // LLQ messages handled by main thread
2856 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2860 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2864 LogErr( "RecvTCPMessage", "pthread_create" );
2865 err
= mStatus_NoError
;
2869 // Let the thread free the context
2871 freeContext
= mDNSfalse
;
2873 pthread_detach(tid
);
2880 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2882 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2884 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2885 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_Refused
;
2887 SendPacket( context
->sock
, &reply
);
2892 freeContext
= mDNSfalse
;
2899 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2904 FreeTCPContext( context
);
2914 TCPSocketFlags flags
2917 TCPContext
* context
= NULL
;
2918 unsigned int clilen
= sizeof( context
->cliaddr
);
2920 mStatus err
= mStatus_NoError
;
2922 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2923 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2924 bzero( context
, sizeof( sizeof( TCPContext
) ) );
2926 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2927 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2929 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2930 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2932 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2933 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2937 if ( err
&& context
)
2948 // listen for incoming requests, periodically check table for expired records, respond to signals
2949 mDNSlocal
int Run(DaemonInfo
*d
)
2951 int staticMaxFD
, nfds
;
2953 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
2954 mDNSBool EventsPending
= mDNSfalse
;
2956 VLog("Listening for requests...");
2960 if ( d
->tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tcpsd
+ 1;
2961 if ( d
->udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->udpsd
+ 1;
2962 if ( d
->tlssd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tlssd
+ 1;
2963 if ( d
->llq_tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_tcpsd
+ 1;
2964 if ( d
->llq_udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_udpsd
+ 1;
2965 if ( d
->LLQEventListenSock
+ 1 > staticMaxFD
) staticMaxFD
= d
->LLQEventListenSock
+ 1;
2969 EventSource
* source
;
2973 timeout
.tv_sec
= timeout
.tv_usec
= 0;
2974 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2978 if (timenow
.tv_sec
- EventTS
.tv_sec
>= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2979 { GenLLQEvents(d
); EventsPending
= mDNSfalse
; } // events, we go ahead and do it now
2980 else timeout
.tv_usec
= 500000; // else do events after 1/2 second with no new events or LLQs
2984 // if no pending events, timeout when we need to check for expired records
2985 if (tablecheck
.tv_sec
&& timenow
.tv_sec
- tablecheck
.tv_sec
>= 0)
2986 { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; } // table check overdue
2987 if (!tablecheck
.tv_sec
) tablecheck
.tv_sec
= timenow
.tv_sec
+ EXPIRATION_INTERVAL
;
2988 timeout
.tv_sec
= tablecheck
.tv_sec
- timenow
.tv_sec
;
2992 FD_SET( d
->tcpsd
, &rset
);
2993 FD_SET( d
->udpsd
, &rset
);
2994 FD_SET( d
->tlssd
, &rset
);
2995 FD_SET( d
->llq_tcpsd
, &rset
);
2996 FD_SET( d
->llq_udpsd
, &rset
);
2997 FD_SET( d
->LLQEventListenSock
, &rset
);
2999 maxFD
= staticMaxFD
;
3001 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3003 FD_SET( source
->fd
, &rset
);
3005 if ( source
->fd
> maxFD
)
3011 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
3018 // close sockets to prevent clients from making new requests during shutdown
3022 close( d
->llq_tcpsd
);
3023 close( d
->llq_udpsd
);
3024 d
->tcpsd
= d
->udpsd
= d
->tlssd
= d
->llq_tcpsd
= d
->llq_udpsd
= -1;
3025 DeleteRecords(d
, mDNStrue
);
3030 Log( "Received SIGINFO" );
3041 Log( "Received SIGHUP" );
3043 err
= ParseConfig( d
, cfgfile
);
3047 LogErr( "Run", "ParseConfig" );
3055 Log("Received unhandled signal - continuing");
3060 LogErr("Run", "select"); return -1;
3065 if (FD_ISSET(d
->udpsd
, &rset
)) RecvUDPMessage( d
, d
->udpsd
);
3066 if (FD_ISSET(d
->llq_udpsd
, &rset
)) RecvUDPMessage( d
, d
->llq_udpsd
);
3067 if (FD_ISSET(d
->tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->tcpsd
, 0 );
3068 if (FD_ISSET(d
->llq_tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->llq_tcpsd
, 0 );
3069 if (FD_ISSET(d
->tlssd
, &rset
)) AcceptTCPConnection( d
, d
->tlssd
, TCP_SOCKET_FLAGS
);
3070 if (FD_ISSET(d
->LLQEventListenSock
, &rset
))
3072 // clear signalling data off socket
3074 recv(d
->LLQEventListenSock
, buf
, 256, 0);
3077 EventsPending
= mDNStrue
;
3078 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
3082 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3084 if ( FD_ISSET( source
->fd
, &rset
) )
3086 source
->callback( source
->context
);
3087 break; // in case we removed this guy from the event loop
3094 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
3095 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
3101 // signal handler sets global variables, which are inspected by main event loop
3102 // (select automatically returns due to the handled signal)
3103 mDNSlocal
void HndlSignal(int sig
)
3105 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
3106 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
3107 if (sig
== SIGHUP
) { hangup
= 1; return; }
3117 DNameListElem
* elem
;
3118 mStatus err
= mStatus_NoError
;
3120 elem
= ( DNameListElem
* ) malloc( sizeof( DNameListElem
) );
3121 require_action( elem
, exit
, err
= mStatus_NoMemoryErr
);
3122 MakeDomainNameFromDNSNameString( &elem
->name
, name
);
3123 elem
->next
= d
->public_names
;
3124 d
->public_names
= elem
;
3132 int main(int argc
, char *argv
[])
3134 int started_via_launchd
= 0;
3138 Log("dnsextd starting");
3140 d
= malloc(sizeof(*d
));
3141 if (!d
) { LogErr("main", "malloc"); exit(1); }
3142 bzero(d
, sizeof(DaemonInfo
));
3144 // Setup the public SRV record names
3146 SetPublicSRV(d
, "_dns-update._udp.");
3147 SetPublicSRV(d
, "_dns-llq._udp.");
3148 SetPublicSRV(d
, "_dns-update-tls._tcp.");
3149 SetPublicSRV(d
, "_dns-query-tls._tcp.");
3150 SetPublicSRV(d
, "_dns-llq-tls._tcp.");
3152 // Setup signal handling
3154 if (signal(SIGHUP
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGHUP");
3155 if (signal(SIGTERM
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGTERM");
3156 if (signal(INFO_SIGNAL
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINFO");
3157 if (signal(SIGINT
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINT");
3158 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) perror("Can't ignore SIGPIPE");
3160 // remove open file limit
3161 rlim
.rlim_max
= RLIM_INFINITY
;
3162 rlim
.rlim_cur
= RLIM_INFINITY
;
3163 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3165 LogErr("main", "setrlimit");
3166 Log("Using default file descriptor resource limit");
3169 if (!strcasecmp(argv
[1], "-launchd"))
3171 Log("started_via_launchd");
3172 started_via_launchd
= 1;
3176 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3178 if (!foreground
&& !started_via_launchd
)
3182 LogErr("main", "daemon");
3187 if (InitLeaseTable(d
) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3188 if (SetupSockets(d
) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3189 if (SetUpdateSRV(d
) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3193 Log("dnsextd stopping");
3195 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3201 // These are stubbed out implementations of up-call routines that the various platform support layers
3202 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3203 // link this code in.
3205 // It's an error for these routines to actually be called, so perhaps we should log any call
3207 void mDNSCoreInitComplete( mDNS
* const m
, mStatus result
) { ( void ) m
; ( void ) result
; }
3208 void mDNSCoreMachineSleep(mDNS
* const m
, mDNSBool wake
) { ( void ) m
; ( void ) wake
; }
3209 void mDNSCoreReceive(mDNS
*const m
, void *const msg
, const mDNSu8
*const end
,
3210 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
,
3211 const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID iid
)
3212 { ( void ) m
; ( void ) msg
; ( void ) end
; ( void ) srcaddr
; ( void ) srcport
; ( void ) dstaddr
; ( void ) dstport
; ( void ) iid
; }
3213 DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
)
3214 { ( void ) m
; ( void ) d
; ( void ) interface
; ( void ) addr
; ( void ) port
; return(NULL
); }
3215 void mDNS_AddSearchDomain(const domainname
*const domain
) { (void)domain
; }
3216 void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3217 { ( void ) m
; ( void ) fqdn
; ( void ) StatusCallback
; ( void ) StatusContext
; }
3218 mDNSs32
mDNS_Execute (mDNS
*const m
) { ( void ) m
; return 0; }
3219 mDNSs32
mDNS_TimeNow(const mDNS
*const m
) { ( void ) m
; return 0; }
3220 mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3221 void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3222 { ( void ) m
; ( void ) set
; ( void ) flapping
; }
3223 const char * const mDNS_DomainTypeNames
[1] = {};
3224 mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
3225 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
3226 { ( void ) m
; ( void ) question
; ( void ) DomainType
; ( void ) dom
; ( void ) InterfaceID
; ( void ) Callback
; ( void ) Context
; return 0; }
3227 mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3228 mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3229 { ( void ) m
; ( void ) set
; ( void ) flapping
; return 0; }
3230 void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
) { ( void ) m
; ( void ) fqdn
; }
3231 void mDNS_SetFQDN(mDNS
* const m
) { ( void ) m
; }
3232 void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3233 { ( void ) m
; ( void ) v4addr
; ( void ) v6addr
; ( void ) router
; }
3234 mStatus
uDNS_SetupDNSConfig( mDNS
*const m
) { ( void ) m
; return 0; }
3235 mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
3236 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, mDNSBool AutoTunnel
)
3237 { ( void ) m
; ( void ) info
; ( void ) domain
; ( void ) keyname
; ( void ) b64keydata
; ( void ) AutoTunnel
; return 0; }
3238 mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
) { ( void ) m
; ( void ) question
; return 0; }
3239 void mDNS_UpdateLLQs(mDNS
* const m
) { ( void ) m
; }
3243 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
3244 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
3245 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
3246 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
3247 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
3249 // For convenience when using the "strings" command, this is the last thing in the file
3250 // The "@(#) " pattern is a special prefix the "what" command looks for
3251 const char mDNSResponderVersionString_SCCS
[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
3253 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3254 const char *__crashreporter_info__
= mDNSResponderVersionString_SCCS
+ 5;
3255 asm(".desc ___crashreporter_info__, 0x10");