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.87 2007/12/17 23:34:50 cheshire
21 Don't need to set ptr to result of DNSDigest_SignMessage -- ptr is updated anyway (it's passed by reference)
23 Revision 1.86 2007/12/13 20:22:34 cheshire
24 Got rid of redundant SameResourceRecord() routine; replaced calls to this
25 with calls to IdenticalResourceRecord() which does exactly the same thing.
27 Revision 1.85 2007/12/01 00:30:36 cheshire
28 Fixed compile warning: declaration of 'time' shadows a global declaration
30 Revision 1.84 2007/10/24 18:19:37 cheshire
31 Fixed header byte order bug sending update responses
33 Revision 1.83 2007/10/17 22:52:26 cheshire
34 Get rid of unused mDNS_UpdateLLQs()
36 Revision 1.82 2007/09/27 17:42:49 cheshire
37 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
39 Revision 1.81 2007/09/21 21:12:37 cheshire
40 DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
42 Revision 1.80 2007/09/18 19:09:02 cheshire
43 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
45 Revision 1.79 2007/07/11 02:59:58 cheshire
46 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
47 Add AutoTunnel parameter to mDNS_SetSecretForDomain
49 Revision 1.78 2007/06/20 01:10:13 cheshire
50 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
52 Revision 1.77 2007/05/15 21:57:17 cheshire
53 <rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
54 assuming that all negative values (or zero!) are invalid socket numbers
56 Revision 1.76 2007/05/01 23:53:26 cheshire
57 <rdar://problem/5175318> dnsextd should refuse updates without attached lease
59 Revision 1.75 2007/05/01 00:18:12 cheshire
60 Use "-launchd" instead of "-d" when starting via launchd
61 (-d sets foreground mode, which writes errors to stderr, which is ignored when starting via launchd)
63 Revision 1.74 2007/04/26 00:35:16 cheshire
64 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
65 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
66 inside the firewall may give answers where a public one gives none, and vice versa.)
68 Revision 1.73 2007/04/22 06:02:03 cheshire
69 <rdar://problem/4615977> Query should immediately return failure when no server
71 Revision 1.72 2007/04/05 22:55:37 cheshire
72 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
74 Revision 1.71 2007/04/05 19:43:56 cheshire
75 Added ProgramName and comment about '-d' option
77 Revision 1.70 2007/04/05 18:34:40 cheshire
78 <rdar://problem/4838930> dnsextd gives "bind - Address already in use" error
80 Revision 1.69 2007/03/28 21:14:08 cheshire
81 The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
83 Revision 1.68 2007/03/28 18:20:50 cheshire
86 Revision 1.67 2007/03/21 00:30:07 cheshire
87 <rdar://problem/4789455> Multiple errors in DNameList-related code
89 Revision 1.66 2007/03/20 17:07:16 cheshire
90 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
92 Revision 1.65 2007/02/07 19:32:00 cheshire
93 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
95 Revision 1.64 2007/01/20 01:43:26 cheshire
96 <rdar://problem/4058383> Should not write log messages to /dev/console
98 Revision 1.63 2007/01/20 01:31:56 cheshire
101 Revision 1.62 2007/01/17 22:06:03 cheshire
102 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
104 Revision 1.61 2007/01/05 08:30:54 cheshire
105 Trim excessive "$Log" checkin history from before 2006
106 (checkin history still available via "cvs log ..." of course)
108 Revision 1.60 2007/01/05 08:07:29 cheshire
109 Remove unnecessary dummy udsserver_default_reg_domain_changed() routine
111 Revision 1.59 2007/01/05 05:46:47 cheshire
112 Remove unnecessary dummy udsserver_automatic_browse_domain_changed() routine
114 Revision 1.58 2007/01/04 23:11:54 cheshire
115 udsserver_default_browse_domain_changed renamed to udsserver_automatic_browse_domain_changed
117 Revision 1.57 2007/01/04 01:41:48 cheshire
118 Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
120 Revision 1.56 2006/12/22 20:59:51 cheshire
121 <rdar://problem/4742742> Read *all* DNS keys from keychain,
122 not just key for the system-wide default registration domain
124 Revision 1.55 2006/11/30 23:08:39 herscher
125 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
127 Revision 1.54 2006/11/18 05:01:33 cheshire
128 Preliminary support for unifying the uDNS and mDNS code,
129 including caching of uDNS answers
131 Revision 1.53 2006/11/17 23:55:09 cheshire
132 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
134 Revision 1.52 2006/11/17 04:27:51 cheshire
135 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
137 Revision 1.51 2006/11/17 03:50:18 cheshire
138 Add debugging loggin in SendPacket and UDPServerTransaction
140 Revision 1.50 2006/11/17 03:48:57 cheshire
141 <rdar://problem/4842493> dnsextd replying on wrong port
143 Revision 1.49 2006/11/03 06:12:44 herscher
144 Make sure all buffers passed to GetRRDisplayString_rdb are of length MaxMsg
146 Revision 1.48 2006/10/20 19:18:35 cheshire
147 <rdar://problem/4669228> dnsextd generates bogus SRV record with null target
149 Revision 1.47 2006/10/20 05:43:51 herscher
150 LookupLLQ() needs to match on the port number when looking up the LLQ
152 Revision 1.46 2006/10/11 22:56:07 herscher
153 Tidy up the implementation of ZoneHandlesName
155 Revision 1.45 2006/08/22 03:28:57 herscher
156 <rdar://problem/4678717> Long-lived queries aren't working well in TOT.
158 Revision 1.44 2006/08/14 23:24:56 cheshire
159 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
161 Revision 1.43 2006/07/20 19:53:33 mkrochma
162 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
163 More fixes for private DNS
165 Revision 1.42 2006/07/05 22:48:19 cheshire
166 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
171 #include "../mDNSShared/uds_daemon.h"
172 #include "../mDNSShared/dnssd_ipc.h"
173 #include "../mDNSCore/uDNS.h"
174 #include "../mDNSShared/DebugServices.h"
179 #include <sys/types.h>
180 #include <sys/socket.h>
181 #include <netinet/in.h>
182 #include <arpa/inet.h>
186 #include <sys/time.h>
187 #include <sys/resource.h>
191 // Compatibility workaround
193 #define AF_LOCAL AF_UNIX
199 mDNSexport
const char ProgramName
[] = "dnsextd";
201 #define LOOPBACK "127.0.0.1"
202 #if !defined(LISTENQ)
203 # define LISTENQ 128 // tcp connection backlog
205 #define RECV_BUFLEN 9000
206 #define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
207 #define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
208 #define SRV_TTL 7200 // TTL For _dns-update SRV records
209 #define CONFIG_FILE "/etc/dnsextd.conf"
210 #define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
212 // LLQ Lease bounds (seconds)
213 #define LLQ_MIN_LEASE (15 * 60)
214 #define LLQ_MAX_LEASE (120 * 60)
215 #define LLQ_LEASE_FUDGE 60
217 // LLQ SOA poll interval (microseconds)
218 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
219 #define LLQ_MONITOR_INTERVAL 250000
221 #define INFO_SIGNAL SIGINFO
223 #define INFO_SIGNAL SIGUSR1
226 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
230 // Structs/fields that must be locked for thread safety are explicitly commented
233 // args passed to UDP request handler thread as void*
238 struct sockaddr_in cliaddr
;
243 // args passed to TCP request handler thread as void*
247 struct sockaddr_in cliaddr
;
248 TCPSocket
*sock
; // socket connected to client
252 // args passed to UpdateAnswerList thread as void*
257 } UpdateAnswerListArgs
;
263 // booleans to determine runtime output
264 // read-only after initialization (no mutex protection)
265 static mDNSBool foreground
= 0;
266 static mDNSBool verbose
= 0;
268 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
269 static mDNSBool terminate
= 0;
270 static mDNSBool dumptable
= 0;
271 static mDNSBool hangup
= 0;
273 // global for config file location
274 static char * cfgfile
= NULL
;
278 // Log messages are delivered to syslog unless -f option specified
281 // common message logging subroutine
282 mDNSlocal
void PrintLog(const char *buffer
)
286 fprintf(stderr
,"%s\n", buffer
);
291 openlog("dnsextd", LOG_CONS
, LOG_DAEMON
);
292 syslog(LOG_ERR
, "%s", buffer
);
297 // Verbose Logging (conditional on -v option)
298 mDNSlocal
void VLog(const char *format
, ...)
303 if (!verbose
) return;
304 va_start(ptr
,format
);
305 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
310 // Unconditional Logging
311 mDNSlocal
void Log(const char *format
, ...)
316 va_start(ptr
,format
);
317 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
323 // prints message "dnsextd <function>: <operation> - <error message>"
324 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
325 mDNSlocal
void LogErr(const char *fn
, const char *operation
)
327 char buf
[512], errbuf
[256];
328 strerror_r(errno
, errbuf
, sizeof(errbuf
));
329 snprintf(buf
, sizeof(buf
), "%s: %s - %s", fn
, operation
, errbuf
);
334 // Networking Utility Routines
337 // Convert DNS Message Header from Network to Host byte order
338 mDNSlocal
void HdrNToH(PktMsg
*pkt
)
340 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
341 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
342 pkt
->msg
.h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
343 pkt
->msg
.h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
344 pkt
->msg
.h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
345 pkt
->msg
.h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
348 // Convert DNS Message Header from Host to Network byte order
349 mDNSlocal
void HdrHToN(PktMsg
*pkt
)
351 mDNSu16 numQuestions
= pkt
->msg
.h
.numQuestions
;
352 mDNSu16 numAnswers
= pkt
->msg
.h
.numAnswers
;
353 mDNSu16 numAuthorities
= pkt
->msg
.h
.numAuthorities
;
354 mDNSu16 numAdditionals
= pkt
->msg
.h
.numAdditionals
;
355 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
357 // Put all the integer values in IETF byte-order (MSB first, LSB second)
358 *ptr
++ = (mDNSu8
)(numQuestions
>> 8);
359 *ptr
++ = (mDNSu8
)(numQuestions
& 0xFF);
360 *ptr
++ = (mDNSu8
)(numAnswers
>> 8);
361 *ptr
++ = (mDNSu8
)(numAnswers
& 0xFF);
362 *ptr
++ = (mDNSu8
)(numAuthorities
>> 8);
363 *ptr
++ = (mDNSu8
)(numAuthorities
& 0xFF);
364 *ptr
++ = (mDNSu8
)(numAdditionals
>> 8);
365 *ptr
++ = (mDNSu8
)(numAdditionals
& 0xFF);
369 // Add socket to event loop
371 mDNSlocal mStatus
AddSourceToEventLoop( DaemonInfo
* self
, TCPSocket
*sock
, EventCallback callback
, void *context
)
373 EventSource
* newSource
;
374 mStatus err
= mStatus_NoError
;
376 if ( self
->eventSources
.LinkOffset
== 0 )
378 InitLinkedList( &self
->eventSources
, offsetof( EventSource
, next
));
381 newSource
= ( EventSource
*) malloc( sizeof *newSource
);
382 if ( newSource
== NULL
)
384 err
= mStatus_NoMemoryErr
;
388 newSource
->callback
= callback
;
389 newSource
->context
= context
;
390 newSource
->sock
= sock
;
391 newSource
->fd
= mDNSPlatformTCPGetFD( sock
);
393 AddToTail( &self
->eventSources
, newSource
);
401 // Remove socket from event loop
403 mDNSlocal mStatus
RemoveSourceFromEventLoop( DaemonInfo
* self
, TCPSocket
*sock
)
405 EventSource
* source
;
408 for ( source
= ( EventSource
* ) self
->eventSources
.Head
; source
; source
= source
->next
)
410 if ( source
->sock
== sock
)
412 RemoveFromList( &self
->eventSources
, source
);
415 err
= mStatus_NoError
;
420 err
= mStatus_NoSuchNameErr
;
427 // create a socket connected to nameserver
428 // caller terminates connection via close()
429 mDNSlocal TCPSocket
*ConnectToServer(DaemonInfo
*d
)
431 int ntries
= 0, retry
= 0;
435 mDNSIPPort port
= zeroIPPort
;
438 TCPSocket
*sock
= mDNSPlatformTCPSocket( NULL
, 0, &port
);
439 if ( !sock
) { LogErr("ConnectToServer", "socket"); return NULL
; }
440 fd
= mDNSPlatformTCPGetFD( sock
);
441 if (!connect( fd
, (struct sockaddr
*)&d
->ns_addr
, sizeof(d
->ns_addr
))) return sock
;
442 mDNSPlatformTCPCloseConnection( sock
);
445 LogErr("ConnectToServer", "connect");
446 Log("ConnectToServer - retrying connection");
447 if (!retry
) retry
= 500000 + random() % 500000;
451 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries
); return NULL
; }
455 // send an entire block of data over a connected socket
456 mDNSlocal
int MySend(TCPSocket
*sock
, const void *msg
, int len
)
458 int selectval
, n
, nsent
= 0;
460 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
468 fd
= mDNSPlatformTCPGetFD( sock
);
471 selectval
= select( fd
+1, NULL
, &wset
, NULL
, &timeout
);
472 if (selectval
< 0) { LogErr("MySend", "select"); return -1; }
473 if (!selectval
|| !FD_ISSET(fd
, &wset
)) { Log("MySend - timeout"); return -1; }
475 n
= mDNSPlatformWriteTCP( sock
, ( char* ) msg
+ nsent
, len
- nsent
);
477 if (n
< 0) { LogErr("MySend", "send"); return -1; }
483 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
484 mDNSlocal
int SendPacket(TCPSocket
*sock
, PktMsg
*pkt
)
486 // send the lenth, in network byte order
487 mDNSu16 len
= htons((mDNSu16
)pkt
->len
);
488 if (MySend(sock
, &len
, sizeof(len
)) < 0) return -1;
491 VLog("SendPacket Q:%d A:%d A:%d A:%d ",
492 ntohs(pkt
->msg
.h
.numQuestions
),
493 ntohs(pkt
->msg
.h
.numAnswers
),
494 ntohs(pkt
->msg
.h
.numAuthorities
),
495 ntohs(pkt
->msg
.h
.numAdditionals
));
496 return MySend(sock
, &pkt
->msg
, pkt
->len
);
499 // Receive len bytes, waiting until we have all of them.
500 // Returns number of bytes read (which should always be the number asked for).
501 static int my_recv(TCPSocket
*sock
, void *const buf
, const int len
, mDNSBool
* closed
)
503 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
504 // use an explicit while() loop instead.
505 // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
506 // arithmetic on "void *" pointers is compiler-dependent.
509 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
510 int selectval
, remaining
= len
;
511 char *ptr
= (char *)buf
;
518 fd
= mDNSPlatformTCPGetFD( sock
);
522 selectval
= select(fd
+1, &rset
, NULL
, NULL
, &timeout
);
523 if (selectval
< 0) { LogErr("my_recv", "select"); return -1; }
524 if (!selectval
|| !FD_ISSET(fd
, &rset
))
526 Log("my_recv - timeout");
530 num_read
= mDNSPlatformReadTCP( sock
, ptr
, remaining
, closed
);
532 if (((num_read
== 0) && *closed
) || (num_read
< 0) || (num_read
> remaining
)) return -1;
533 if (num_read
== 0) return 0;
535 remaining
-= num_read
;
540 // Return a DNS Message read off of a TCP socket, or NULL on failure
541 // If storage is non-null, result is placed in that buffer. Otherwise,
542 // returned value is allocated with Malloc, and contains sufficient extra
543 // storage for a Lease OPT RR
561 fd
= mDNSPlatformTCPGetFD( sock
);
563 nread
= my_recv( sock
, &msglen
, sizeof( msglen
), closed
);
565 require_action_quiet( nread
!= -1, exit
, err
= mStatus_UnknownErr
);
566 require_action_quiet( nread
> 0, exit
, err
= mStatus_NoError
);
568 msglen
= ntohs( msglen
);
569 require_action_quiet( nread
== sizeof( msglen
), exit
, err
= mStatus_UnknownErr
; Log( "Could not read length field of message") );
573 require_action_quiet( msglen
<= sizeof( storage
->msg
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: provided buffer too small." ) );
578 // buffer extra space to add an OPT RR
580 if ( msglen
> sizeof(DNSMessage
))
582 allocsize
= sizeof(PktMsg
) - sizeof(DNSMessage
) + msglen
;
586 allocsize
= sizeof(PktMsg
);
589 pkt
= malloc(allocsize
);
590 require_action_quiet( pkt
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvPacket", "malloc" ) );
591 bzero( pkt
, sizeof( *pkt
) );
595 srclen
= sizeof(pkt
->src
);
597 if ( getpeername( fd
, ( struct sockaddr
* ) &pkt
->src
, &srclen
) || ( srclen
!= sizeof( pkt
->src
) ) )
599 LogErr("RecvPacket", "getpeername");
600 bzero(&pkt
->src
, sizeof(pkt
->src
));
603 nread
= my_recv(sock
, &pkt
->msg
, msglen
, closed
);
604 require_action_quiet( nread
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvPacket", "recv" ) );
605 require_action_quiet( nread
== msglen
, exit
, err
= mStatus_UnknownErr
; Log( "Could not read entire message" ) );
606 require_action_quiet( pkt
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: Message too short (%d bytes)", pkt
->len
) );
612 if ( pkt
!= storage
)
633 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
635 if ( SameDomainName( &zone
->name
, name
) )
648 const domainname
* zname
,
649 const domainname
* dname
652 mDNSu16 i
= DomainNameLength( zname
);
653 mDNSu16 j
= DomainNameLength( dname
);
655 if ( ( i
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( j
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( i
> j
) || ( memcmp( zname
->c
, dname
->c
+ ( j
- i
), i
) != 0 ) )
664 mDNSlocal mDNSBool
IsQuery( PktMsg
* pkt
)
666 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
);
670 mDNSlocal mDNSBool
IsUpdate( PktMsg
* pkt
)
672 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_OP_Update
);
676 mDNSlocal mDNSBool
IsNotify(PktMsg
*pkt
)
678 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( mDNSu8
) ( kDNSFlag0_OP_Notify
);
682 mDNSlocal mDNSBool
IsLLQRequest(PktMsg
*pkt
)
684 const mDNSu8
*ptr
= NULL
, *end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
685 LargeCacheRecord lcr
;
687 mDNSBool result
= mDNSfalse
;
690 if ((mDNSu8
)(pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (mDNSu8
)(kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
)) goto end
;
692 if (!pkt
->msg
.h
.numAdditionals
) goto end
;
693 ptr
= LocateAdditionals(&pkt
->msg
, end
);
696 // find last Additional info.
697 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
699 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
700 if (!ptr
) { Log("Unable to read additional record"); goto end
; }
703 if ( lcr
.r
.resrec
.rrtype
== kDNSType_OPT
&& lcr
.r
.resrec
.rdlength
>= LLQ_OPT_RDLEN
&& lcr
.r
.resrec
.rdata
->u
.opt
.opt
== kDNSOpt_LLQ
)
713 // !!!KRS implement properly
714 mDNSlocal mDNSBool
IsLLQAck(PktMsg
*pkt
)
716 if ((pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
) &&
717 pkt
->msg
.h
.numQuestions
&& !pkt
->msg
.h
.numAnswers
&& !pkt
->msg
.h
.numAuthorities
) return mDNStrue
;
729 DNameListElem
* elem
;
730 mDNSBool ret
= mDNSfalse
;
731 int i
= ( int ) DomainNameLength( &q
->qname
) - 1;
733 for ( elem
= self
->public_names
; elem
; elem
= elem
->next
)
735 int j
= ( int ) DomainNameLength( &elem
->name
) - 1;
739 for ( ; i
>= 0; i
--, j
-- )
741 if ( q
->qname
.c
[ i
] != elem
->name
.c
[ j
] )
765 const mDNSu8
* ptr
= pkt
->msg
.data
;
766 mDNSBool exception
= mDNSfalse
;
771 pkt
->isZonePublic
= mDNStrue
;
774 // Figure out what type of packet this is
776 QR_OP
= ( mDNSu8
) ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
778 if ( IsQuery( pkt
) )
780 DNSQuestion question
;
784 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
786 AppendDomainName( &zname
, &question
.qname
);
788 exception
= ( ( question
.qtype
== kDNSType_SOA
) || ( question
.qtype
== kDNSType_NS
) || ( ( question
.qtype
== kDNSType_SRV
) && IsPublicSRV( self
, &question
) ) );
790 else if ( IsUpdate( pkt
) )
792 DNSQuestion question
;
794 // It's an update. The format of the zone section is the same as the format for the question section
795 // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
797 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
799 AppendDomainName( &zname
, &question
.qname
);
801 exception
= mDNSfalse
;
804 if ( zname
.c
[0] != '\0' )
806 // Find the right zone
808 for ( pkt
->zone
= self
->zones
; pkt
->zone
; pkt
->zone
= pkt
->zone
->next
)
810 if ( ZoneHandlesName( &pkt
->zone
->name
, &zname
) )
812 VLog( "found correct zone %##s for query", pkt
->zone
->name
.c
);
814 pkt
->isZonePublic
= ( ( pkt
->zone
->type
== kDNSZonePublic
) || exception
);
816 VLog( "zone %##s is %s", pkt
->zone
->name
.c
, ( pkt
->isZonePublic
) ? "public" : "private" );
826 UDPServerTransaction(const DaemonInfo
*d
, const PktMsg
*request
, PktMsg
*reply
, mDNSBool
*trunc
)
829 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
832 mStatus err
= mStatus_NoError
;
840 sd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
841 require_action( sd
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "socket" ) );
843 // Send the packet to the nameserver
845 VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
846 ntohs(request
->msg
.h
.numQuestions
),
847 ntohs(request
->msg
.h
.numAnswers
),
848 ntohs(request
->msg
.h
.numAuthorities
),
849 ntohs(request
->msg
.h
.numAdditionals
));
850 res
= sendto( sd
, (char *)&request
->msg
, request
->len
, 0, ( struct sockaddr
* ) &d
->ns_addr
, sizeof( d
->ns_addr
) );
851 require_action( res
== (int) request
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "sendto" ) );
857 res
= select( sd
+ 1, &rset
, NULL
, NULL
, &timeout
);
858 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "select" ) );
859 require_action( ( res
> 0 ) && FD_ISSET( sd
, &rset
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - timeout" ) );
863 reply
->len
= recvfrom( sd
, &reply
->msg
, sizeof(reply
->msg
), 0, NULL
, NULL
);
864 require_action( ( ( int ) reply
->len
) >= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "recvfrom" ) );
865 require_action( reply
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - Message too short (%d bytes)", reply
->len
) );
867 // Check for truncation bit
869 if ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_TC
)
885 // Dynamic Update Utility Routines
888 // check if a request and server response complete a successful dynamic update
889 mDNSlocal mDNSBool
SuccessfulUpdateTransaction(PktMsg
*request
, PktMsg
*reply
)
892 char *vlogmsg
= NULL
;
895 if (!request
|| !reply
) { vlogmsg
= "NULL message"; goto failure
; }
896 if (request
->len
< sizeof(DNSMessageHeader
) || reply
->len
< sizeof(DNSMessageHeader
)) { vlogmsg
= "Malformatted message"; goto failure
; }
898 // check request operation
899 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
))
900 { vlogmsg
= "Request opcode not an update"; goto failure
; }
903 if ((reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)) { vlogmsg
= "Reply contains non-zero rcode"; goto failure
; }
904 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
))
905 { vlogmsg
= "Reply opcode not an update response"; goto failure
; }
907 VLog("Successful update from %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32));
911 VLog("Request %s: %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32), vlogmsg
);
915 // Allocate an appropriately sized CacheRecord and copy data from original.
916 // Name pointer in CacheRecord object is set to point to the name specified
918 mDNSlocal CacheRecord
*CopyCacheRecord(const CacheRecord
*orig
, domainname
*name
)
921 size_t size
= sizeof(*cr
);
922 if (orig
->resrec
.rdlength
> InlineCacheRDSize
) size
+= orig
->resrec
.rdlength
- InlineCacheRDSize
;
924 if (!cr
) { LogErr("CopyCacheRecord", "malloc"); return NULL
; }
925 memcpy(cr
, orig
, size
);
926 cr
->resrec
.rdata
= (RData
*)&cr
->rdatastorage
;
927 cr
->resrec
.name
= name
;
934 // Lease Hashtable Utility Routines
937 // double hash table size
938 // caller must lock table prior to invocation
939 mDNSlocal
void RehashTable(DaemonInfo
*d
)
941 RRTableElem
*ptr
, *tmp
, **new;
942 int i
, bucket
, newnbuckets
= d
->nbuckets
* 2;
944 VLog("Rehashing lease table (new size %d buckets)", newnbuckets
);
945 new = malloc(sizeof(RRTableElem
*) * newnbuckets
);
946 if (!new) { LogErr("RehashTable", "malloc"); return; }
947 bzero(new, newnbuckets
* sizeof(RRTableElem
*));
949 for (i
= 0; i
< d
->nbuckets
; i
++)
954 bucket
= ptr
->rr
.resrec
.namehash
% newnbuckets
;
957 tmp
->next
= new[bucket
];
961 d
->nbuckets
= newnbuckets
;
966 // print entire contents of hashtable, invoked via SIGINFO
967 mDNSlocal
void PrintLeaseTable(DaemonInfo
*d
)
971 char rrbuf
[MaxMsg
], addrbuf
[16];
975 if (gettimeofday(&now
, NULL
)) { LogErr("PrintTable", "gettimeofday"); return; }
976 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
978 Log("Dumping Lease Table Contents (table contains %d resource records)", d
->nelems
);
979 for (i
= 0; i
< d
->nbuckets
; i
++)
981 for (ptr
= d
->table
[i
]; ptr
; ptr
= ptr
->next
)
983 hr
= ((ptr
->expire
- now
.tv_sec
) / 60) / 60;
984 min
= ((ptr
->expire
- now
.tv_sec
) / 60) % 60;
985 sec
= (ptr
->expire
- now
.tv_sec
) % 60;
986 Log("Update from %s, Expires in %d:%d:%d\n\t%s", inet_ntop(AF_INET
, &ptr
->cli
.sin_addr
, addrbuf
, 16), hr
, min
, sec
,
987 GetRRDisplayString_rdb(&ptr
->rr
.resrec
, &ptr
->rr
.resrec
.rdata
->u
, rrbuf
));
990 pthread_mutex_unlock(&d
->tablelock
);
994 // Startup SRV Registration Routines
995 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
996 // the daemon accepts requests
999 // delete all RRS of a given name/type
1000 mDNSlocal mDNSu8
*putRRSetDeletion(DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
, ResourceRecord
*rr
)
1002 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
1003 if (!ptr
|| ptr
+ 10 >= limit
) return NULL
; // out of space
1004 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
1005 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
1006 ptr
[2] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
>> 8);
1007 ptr
[3] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
& 0xFF);
1008 bzero(ptr
+4, sizeof(rr
->rroriginalttl
) + sizeof(rr
->rdlength
)); // zero ttl/rdata
1009 msg
->h
.mDNS_numUpdates
++;
1013 mDNSlocal mDNSu8
*PutUpdateSRV(DaemonInfo
*d
, DNSZone
* zone
, PktMsg
*pkt
, mDNSu8
*ptr
, char *regtype
, mDNSIPPort port
, mDNSBool registration
)
1016 char hostname
[1024], buf
[MaxMsg
];
1017 mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ sizeof(DNSMessage
);
1021 mDNS_SetupResourceRecord(&rr
, NULL
, 0, kDNSType_SRV
, SRV_TTL
, kDNSRecordTypeUnique
, NULL
, NULL
);
1022 rr
.resrec
.rrclass
= kDNSClass_IN
;
1023 rr
.resrec
.rdata
->u
.srv
.priority
= 0;
1024 rr
.resrec
.rdata
->u
.srv
.weight
= 0;
1025 rr
.resrec
.rdata
->u
.srv
.port
= port
;
1026 if (gethostname(hostname
, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr
.resrec
.rdata
->u
.srv
.target
, hostname
))
1027 rr
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0';
1029 MakeDomainNameFromDNSNameString(&rr
.namestorage
, regtype
);
1030 AppendDomainName(&rr
.namestorage
, &zone
->name
);
1031 VLog("%s %s", registration
? "Registering SRV record" : "Deleting existing RRSet",
1032 GetRRDisplayString_rdb(&rr
.resrec
, &rr
.resrec
.rdata
->u
, buf
));
1033 if (registration
) ptr
= PutResourceRecord(&pkt
->msg
, ptr
, &pkt
->msg
.h
.mDNS_numUpdates
, &rr
.resrec
);
1034 else ptr
= putRRSetDeletion(&pkt
->msg
, ptr
, end
, &rr
.resrec
);
1039 // perform dynamic update.
1040 // specify deletion by passing false for the register parameter, otherwise register the records.
1041 mDNSlocal
int UpdateSRV(DaemonInfo
*d
, mDNSBool registration
)
1043 TCPSocket
*sock
= NULL
;
1045 int err
= mStatus_NoError
;
1047 sock
= ConnectToServer( d
);
1048 require_action( sock
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: ConnectToServer failed" ) );
1050 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1053 mDNSu8
*ptr
= pkt
.msg
.data
;
1054 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1055 PktMsg
*reply
= NULL
;
1059 // Initialize message
1060 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1061 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1062 pkt
.src
.sin_family
= AF_INET
;
1064 // format message body
1065 ptr
= putZone(&pkt
.msg
, ptr
, end
, &zone
->name
, mDNSOpaque16fromIntVal(kDNSClass_IN
));
1066 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1068 if ( zone
->type
== kDNSZonePrivate
)
1070 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls._tcp.", d
->private_port
, registration
);
1071 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1072 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls._tcp.", d
->private_port
, registration
);
1073 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1074 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls._tcp.", d
->private_port
, registration
);
1075 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1077 if ( !registration
)
1079 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
1080 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1081 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
1082 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1087 if ( !registration
)
1089 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls.", d
->private_port
, registration
);
1090 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1091 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls.", d
->private_port
, registration
);
1092 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1093 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls.", d
->private_port
, registration
);
1094 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1097 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
1098 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1099 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
1100 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1105 if ( zone
->updateKeys
)
1107 DNSDigest_SignMessage( &pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1108 require_action( ptr
, exit
, Log("UpdateSRV: Error constructing lease expiration update" ) );
1111 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1113 // send message, receive reply
1115 err
= SendPacket( sock
, &pkt
);
1116 require_action( !err
, exit
, Log( "UpdateSRV: SendPacket failed" ) );
1118 reply
= RecvPacket( sock
, NULL
, &closed
);
1119 require_action( reply
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: RecvPacket returned NULL" ) );
1121 ok
= SuccessfulUpdateTransaction( &pkt
, reply
);
1125 Log("SRV record registration failed with rcode %d", reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1135 mDNSPlatformTCPCloseConnection( sock
);
1141 // wrapper routines/macros
1142 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1144 // clear any existing records prior to registration
1145 mDNSlocal
int SetUpdateSRV(DaemonInfo
*d
)
1149 err
= ClearUpdateSRV(d
); // clear any existing record
1150 if (!err
) err
= UpdateSRV(d
, 1);
1155 // Argument Parsing and Configuration
1158 mDNSlocal
void PrintUsage(void)
1160 fprintf(stderr
, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1161 "Use \"dnsextd -h\" for help\n");
1164 mDNSlocal
void PrintHelp(void)
1166 fprintf(stderr
, "\n\n");
1170 "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
1171 "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
1172 "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
1173 "Discovery, Update Leases, and Long Lived Queries.)\n\n"
1175 "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
1176 "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
1177 "primary master server for this zone.\n\n"
1179 "The options are as follows:\n\n"
1181 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1183 "-d Run daemon in foreground.\n\n"
1185 "-h Print help.\n\n"
1187 "-v Verbose output.\n\n"
1192 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
1193 // returns 0 (success) if program is to continue execution
1194 // output control arguments (-f, -v) do not affect this routine
1195 mDNSlocal
int ProcessArgs(int argc
, char *argv
[], DaemonInfo
*d
)
1201 cfgfile
= strdup( CONFIG_FILE
);
1202 require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
);
1204 // defaults, may be overriden by command option
1206 // setup our sockaddr
1208 bzero( &d
->addr
, sizeof( d
->addr
) );
1209 d
->addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1210 d
->addr
.sin_port
= UnicastDNSPort
.NotAnInteger
;
1211 d
->addr
.sin_family
= AF_INET
;
1212 #ifndef NOT_HAVE_SA_LEN
1213 d
->addr
.sin_len
= sizeof( d
->addr
);
1216 // setup nameserver's sockaddr
1218 bzero(&d
->ns_addr
, sizeof(d
->ns_addr
));
1219 d
->ns_addr
.sin_family
= AF_INET
;
1220 inet_pton( AF_INET
, LOOPBACK
, &d
->ns_addr
.sin_addr
);
1221 d
->ns_addr
.sin_port
= NSIPCPort
.NotAnInteger
;
1222 #ifndef NOT_HAVE_SA_LEN
1223 d
->ns_addr
.sin_len
= sizeof( d
->ns_addr
);
1228 d
->private_port
= PrivateDNSPort
;
1229 d
->llq_port
= DNSEXTPort
;
1231 while ((opt
= getopt(argc
, argv
, "f:hdv")) != -1)
1235 case 'f': free( cfgfile
); cfgfile
= strdup( optarg
); require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
); break;
1236 case 'h': PrintHelp(); return -1;
1237 case 'd': foreground
= 1; break; // Also used when launched via OS X's launchd mechanism
1238 case 'v': verbose
= 1; break;
1239 default: goto arg_error
;
1243 err
= ParseConfig( d
, cfgfile
);
1244 require_noerr( err
, arg_error
);
1246 // Make sure we've specified some zones
1248 require_action( d
->zones
, arg_error
, err
= mStatus_UnknownErr
);
1250 // if we have a shared secret, use it for the entire zone
1252 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1254 if ( zone
->updateKeys
)
1256 AssignDomainName( &zone
->updateKeys
->domain
, &zone
->name
);
1270 // Initialization Routines
1273 // Allocate memory, initialize locks and bookkeeping variables
1274 mDNSlocal
int InitLeaseTable(DaemonInfo
*d
)
1276 if (pthread_mutex_init(&d
->tablelock
, NULL
)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1277 d
->nbuckets
= LEASETABLE_INIT_NBUCKETS
;
1279 d
->table
= malloc(sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1280 if (!d
->table
) { LogErr("InitLeaseTable", "malloc"); return -1; }
1281 bzero(d
->table
, sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1292 static const int kOn
= 1;
1294 mDNSBool
private = mDNSfalse
;
1295 struct sockaddr_in daddr
;
1299 // set up sockets on which we all ns requests
1301 self
->tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1302 require_action( dnssd_SocketValid(self
->tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1304 #if defined(SO_REUSEADDR)
1305 err
= setsockopt(self
->tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1306 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
1309 err
= bind( self
->tcpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1310 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1312 err
= listen( self
->tcpsd
, LISTENQ
);
1313 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1315 self
->udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1316 require_action( dnssd_SocketValid(self
->udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1318 #if defined(SO_REUSEADDR)
1319 err
= setsockopt(self
->udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1320 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
1323 err
= bind( self
->udpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1324 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->udpsd" ) );
1326 // set up sockets on which we receive llq requests
1328 bzero(&self
->llq_addr
, sizeof(self
->llq_addr
));
1329 self
->llq_addr
.sin_family
= AF_INET
;
1330 self
->llq_addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1331 self
->llq_addr
.sin_port
= ( self
->llq_port
.NotAnInteger
) ? self
->llq_port
.NotAnInteger
: DNSEXTPort
.NotAnInteger
;
1333 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1334 require_action( dnssd_SocketValid(self
->llq_tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1336 #if defined(SO_REUSEADDR)
1337 err
= setsockopt(self
->llq_tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1338 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
1341 err
= bind( self
->llq_tcpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1342 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
1344 err
= listen( self
->llq_tcpsd
, LISTENQ
);
1345 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1347 self
->llq_udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1348 require_action( dnssd_SocketValid(self
->llq_udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1350 #if defined(SO_REUSEADDR)
1351 err
= setsockopt(self
->llq_udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1352 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
1355 err
= bind(self
->llq_udpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1356 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
1358 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1360 err
= socketpair( AF_LOCAL
, SOCK_STREAM
, 0, sockpair
);
1361 require_action( !err
, exit
, LogErr( "SetupSockets", "socketpair" ) );
1363 self
->LLQEventListenSock
= sockpair
[0];
1364 self
->LLQEventNotifySock
= sockpair
[1];
1366 // set up socket on which we receive private requests
1368 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1369 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1370 bzero(&daddr
, sizeof(daddr
));
1371 daddr
.sin_family
= AF_INET
;
1372 daddr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1373 daddr
.sin_port
= ( self
->private_port
.NotAnInteger
) ? self
->private_port
.NotAnInteger
: PrivateDNSPort
.NotAnInteger
;
1375 self
->tlssd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1376 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1378 #if defined(SO_REUSEADDR)
1379 err
= setsockopt(self
->tlssd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1380 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
1383 err
= bind( self
->tlssd
, ( struct sockaddr
* ) &daddr
, sizeof( daddr
) );
1384 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tlssd" ) );
1386 err
= listen( self
->tlssd
, LISTENQ
);
1387 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1389 // Do we have any private zones?
1391 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
1393 if ( zone
->type
== kDNSZonePrivate
)
1402 err
= mDNSPlatformTLSSetupCerts();
1403 require_action( !err
, exit
, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1412 // periodic table updates
1415 // Delete a resource record from the nameserver via a dynamic update
1416 // sd is a socket already connected to the server
1417 mDNSlocal
void DeleteOneRecord(DaemonInfo
*d
, CacheRecord
*rr
, domainname
*zname
, TCPSocket
*sock
)
1421 mDNSu8
*ptr
= pkt
.msg
.data
;
1422 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1425 PktMsg
*reply
= NULL
;
1427 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, buf
));
1429 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1431 ptr
= putZone(&pkt
.msg
, ptr
, end
, zname
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
1433 ptr
= putDeletionRecord(&pkt
.msg
, ptr
, &rr
->resrec
);
1438 zone
= FindZone( d
, zname
);
1440 if ( zone
&& zone
->updateKeys
)
1442 DNSDigest_SignMessage(&pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1446 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1447 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1448 pkt
.src
.sin_family
= AF_INET
;
1449 if (SendPacket( sock
, &pkt
)) { Log("DeleteOneRecord: SendPacket failed"); }
1450 reply
= RecvPacket( sock
, NULL
, &closed
);
1451 if (reply
) HdrNToH(reply
);
1452 require_action( reply
, end
, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
1454 if (!SuccessfulUpdateTransaction(&pkt
, reply
))
1455 Log("Expiration update failed with rcode %d", reply
? reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
: -1);
1458 if (!ptr
) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1459 if (reply
) free(reply
);
1462 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1463 mDNSlocal
void DeleteRecords(DaemonInfo
*d
, mDNSBool DeleteAll
)
1467 TCPSocket
*sock
= ConnectToServer(d
);
1468 if (!sock
) { Log("DeleteRecords: ConnectToServer failed"); return; }
1469 if (gettimeofday(&now
, NULL
)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
1470 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
1472 for (i
= 0; i
< d
->nbuckets
; i
++)
1474 RRTableElem
**ptr
= &d
->table
[i
];
1477 if (DeleteAll
|| (*ptr
)->expire
- now
.tv_sec
< 0)
1480 // delete record from server
1481 DeleteOneRecord(d
, &(*ptr
)->rr
, &(*ptr
)->zone
, sock
);
1483 *ptr
= (*ptr
)->next
;
1487 else ptr
= &(*ptr
)->next
;
1490 pthread_mutex_unlock(&d
->tablelock
);
1491 mDNSPlatformTCPCloseConnection( sock
);
1495 // main update request handling
1498 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
1499 mDNSlocal
void UpdateLeaseTable(PktMsg
*pkt
, DaemonInfo
*d
, mDNSs32 lease
)
1501 RRTableElem
**rptr
, *tmp
;
1502 int i
, allocsize
, bucket
;
1503 LargeCacheRecord lcr
;
1504 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1505 const mDNSu8
*ptr
, *end
;
1510 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
1512 ptr
= pkt
->msg
.data
;
1513 end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
1514 ptr
= getQuestion(&pkt
->msg
, ptr
, end
, 0, &zone
);
1515 if (!ptr
) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup
; }
1516 ptr
= LocateAuthorities(&pkt
->msg
, end
);
1517 if (!ptr
) { Log("UpdateLeaseTable: Format error"); goto cleanup
; }
1519 for (i
= 0; i
< pkt
->msg
.h
.mDNS_numUpdates
; i
++)
1521 mDNSBool DeleteAllRRSets
= mDNSfalse
, DeleteOneRRSet
= mDNSfalse
, DeleteOneRR
= mDNSfalse
;
1523 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1524 if (!ptr
) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup
; }
1525 bucket
= rr
->namehash
% d
->nbuckets
;
1526 rptr
= &d
->table
[bucket
];
1529 if (rr
->rrtype
== kDNSQType_ANY
&& !rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1530 DeleteAllRRSets
= mDNStrue
; // delete all rrsets for a name
1531 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1532 DeleteOneRRSet
= mDNStrue
;
1533 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSClass_NONE
)
1534 DeleteOneRR
= mDNStrue
;
1536 if (DeleteAllRRSets
|| DeleteOneRRSet
|| DeleteOneRR
)
1540 if (SameDomainName((*rptr
)->rr
.resrec
.name
, rr
->name
) &&
1542 (DeleteOneRRSet
&& (*rptr
)->rr
.resrec
.rrtype
== rr
->rrtype
) ||
1543 (DeleteOneRR
&& IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
))))
1546 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp
->rr
.resrec
, &tmp
->rr
.resrec
.rdata
->u
, buf
));
1547 *rptr
= (*rptr
)->next
;
1551 else rptr
= &(*rptr
)->next
;
1556 // see if add or refresh
1557 while (*rptr
&& !IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
)) rptr
= &(*rptr
)->next
;
1561 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1562 (*rptr
)->expire
= tv
.tv_sec
+ (unsigned)lease
;
1563 VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1567 // New record - add to table
1568 if (d
->nelems
> d
->nbuckets
)
1571 bucket
= rr
->namehash
% d
->nbuckets
;
1572 rptr
= &d
->table
[bucket
];
1574 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1575 allocsize
= sizeof(RRTableElem
);
1576 if (rr
->rdlength
> InlineCacheRDSize
) allocsize
+= (rr
->rdlength
- InlineCacheRDSize
);
1577 tmp
= malloc(allocsize
);
1578 if (!tmp
) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup
; }
1579 memcpy(&tmp
->rr
, &lcr
.r
, sizeof(CacheRecord
) + rr
->rdlength
- InlineCacheRDSize
);
1580 tmp
->rr
.resrec
.rdata
= (RData
*)&tmp
->rr
.rdatastorage
;
1581 AssignDomainName(&tmp
->name
, rr
->name
);
1582 tmp
->rr
.resrec
.name
= &tmp
->name
;
1583 tmp
->expire
= tv
.tv_sec
+ (unsigned)lease
;
1584 tmp
->cli
.sin_addr
= pkt
->src
.sin_addr
;
1585 AssignDomainName(&tmp
->zone
, &zone
.qname
);
1586 tmp
->next
= d
->table
[bucket
];
1587 d
->table
[bucket
] = tmp
;
1589 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1595 pthread_mutex_unlock(&d
->tablelock
);
1599 // Given a successful reply from a server, create a new reply that contains lease information
1600 // Replies are currently not signed !!!KRS change this
1601 mDNSlocal PktMsg
*FormatLeaseReply(DaemonInfo
*d
, PktMsg
*orig
, mDNSu32 lease
)
1608 reply
= malloc(sizeof(*reply
));
1609 if (!reply
) { LogErr("FormatLeaseReply", "malloc"); return NULL
; }
1610 flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
1613 InitializeDNSMessage(&reply
->msg
.h
, orig
->msg
.h
.id
, flags
);
1614 reply
->src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // unused except for log messages
1615 reply
->src
.sin_family
= AF_INET
;
1616 ptr
= reply
->msg
.data
;
1617 end
= (mDNSu8
*)&reply
->msg
+ sizeof(DNSMessage
);
1618 ptr
= putUpdateLease(&reply
->msg
, ptr
, lease
);
1619 if (!ptr
) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply
); return NULL
; }
1620 reply
->len
= ptr
- (mDNSu8
*)&reply
->msg
;
1626 // pkt is thread-local, not requiring locking
1635 PktMsg
* reply
= NULL
;
1636 PktMsg
* leaseReply
;
1639 TCPSocket
* sock
= NULL
;
1642 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == kDNSFlag0_OP_Update
)
1644 int i
, adds
= 0, dels
= 0;
1645 const mDNSu8
*ptr
, *end
= (mDNSu8
*)&request
->msg
+ request
->len
;
1647 lease
= GetPktLease(&mDNSStorage
, &request
->msg
, end
);
1648 ptr
= LocateAuthorities(&request
->msg
, end
);
1649 for (i
= 0; i
< request
->msg
.h
.mDNS_numUpdates
; i
++)
1651 LargeCacheRecord lcr
;
1652 ptr
= GetLargeResourceRecord(NULL
, &request
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1653 if (lcr
.r
.resrec
.rroriginalttl
) adds
++; else dels
++;
1658 static const mDNSOpaque16 UpdateRefused
= { { kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
, kDNSFlag1_RC_Refused
} };
1659 Log("Rejecting Update Request with %d additions but no lease", adds
);
1660 reply
= malloc(sizeof(*reply
));
1661 bzero(&reply
->src
, sizeof(reply
->src
));
1662 reply
->len
= sizeof(DNSMessageHeader
);
1664 reply
->isZonePublic
= 0;
1665 InitializeDNSMessage(&reply
->msg
.h
, request
->msg
.h
.id
, UpdateRefused
);
1668 if (lease
> 1200) // Don't allow lease greater than 20 minutes
1671 // Send msg to server, read reply
1673 if ( request
->len
<= 512 )
1677 if ( UDPServerTransaction( self
, request
, &buf
, &trunc
) < 0 )
1679 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1683 VLog("HandleRequest - answer truncated. Using TCP");
1687 reply
= &buf
; // success
1696 sock
= ConnectToServer( self
);
1697 require_action_quiet( sock
, exit
, err
= mStatus_UnknownErr
; Log( "Discarding request from %s due to connection errors", inet_ntop( AF_INET
, &request
->src
.sin_addr
, addrbuf
, 32 ) ) );
1699 res
= SendPacket( sock
, request
);
1700 require_action_quiet( res
>= 0, exit
, err
= mStatus_UnknownErr
; Log( "Couldn't relay message from %s to server. Discarding.", inet_ntop(AF_INET
, &request
->src
.sin_addr
, addrbuf
, 32 ) ) );
1702 reply
= RecvPacket( sock
, &buf
, &closed
);
1705 // IMPORTANT: reply is in network byte order at this point in the code
1706 // We keep it this way because we send it back to the client in the same form
1710 if ( reply
&& ( ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
) ) )
1713 mDNSBool ok
= SuccessfulUpdateTransaction( request
, reply
);
1714 require_action( ok
, exit
, err
= mStatus_UnknownErr
; VLog( "Message from %s not a successful update.", inet_ntop(AF_INET
, &request
->src
.sin_addr
, addrbuf
, 32 ) ) );
1716 UpdateLeaseTable( request
, self
, lease
);
1720 leaseReply
= FormatLeaseReply( self
, reply
, lease
);
1724 Log("HandleRequest - unable to format lease reply");
1727 // %%% Looks like a potential memory leak -- who frees the original reply?
1731 // tell the main thread there was an update so it can send LLQs
1733 if ( send( self
->LLQEventNotifySock
, pingmsg
, sizeof( pingmsg
), 0 ) != sizeof( pingmsg
) )
1735 LogErr("HandleRequest", "send");
1743 mDNSPlatformTCPCloseConnection( sock
);
1746 if ( reply
== &buf
)
1748 reply
= malloc( sizeof( *reply
) );
1752 reply
->len
= buf
.len
;
1753 memcpy(&reply
->msg
, &buf
.msg
, buf
.len
);
1757 LogErr("HandleRequest", "malloc");
1766 // LLQ Support Routines
1769 // Set fields of an LLQ OPT Resource Record
1770 mDNSlocal
void FormatLLQOpt(AuthRecord
*opt
, int opcode
, const mDNSOpaque64
*const id
, mDNSs32 lease
)
1772 bzero(opt
, sizeof(*opt
));
1773 mDNS_SetupResourceRecord(opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
1774 opt
->resrec
.rrclass
= NormalMaxDNSMessageData
;
1775 opt
->resrec
.rdlength
= LLQ_OPT_RDLEN
;
1776 opt
->resrec
.rdestimate
= LLQ_OPT_RDLEN
;
1777 opt
->resrec
.rdata
->u
.opt
.opt
= kDNSOpt_LLQ
;
1778 opt
->resrec
.rdata
->u
.opt
.optlen
= sizeof(LLQOptData
);
1779 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.vers
= kLLQ_Vers
;
1780 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.llqOp
= opcode
;
1781 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.err
= LLQErr_NoError
;
1782 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.id
= *id
;
1783 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.llqlease
= lease
;
1786 // Calculate effective remaining lease of an LLQ
1787 mDNSlocal mDNSu32
LLQLease(LLQEntry
*e
)
1791 gettimeofday(&t
, NULL
);
1792 if (e
->expire
< t
.tv_sec
) return 0;
1793 else return e
->expire
- t
.tv_sec
;
1796 mDNSlocal
void DeleteLLQ(DaemonInfo
*d
, LLQEntry
*e
)
1798 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
1799 LLQEntry
**ptr
= &d
->LLQTable
[bucket
];
1800 AnswerListElem
*a
= e
->AnswerList
;
1803 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1804 VLog("Deleting LLQ table entry for %##s client %s", e
->qname
.c
, addr
);
1806 if (a
&& !(--a
->refcount
) && d
->AnswerTableCount
>= LLQ_TABLESIZE
)
1808 // currently, generating initial answers blocks the main thread, so we keep the answer list
1809 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1810 // if the ref count drops to zero AND there are more table elements than buckets
1811 // !!!KRS update this when we make the table dynamically growable
1813 CacheRecord
*cr
= a
->KnownAnswers
, *tmp
;
1814 AnswerListElem
**tbl
= &d
->AnswerTable
[bucket
];
1823 while (*tbl
&& *tbl
!= a
) tbl
= &(*tbl
)->next
;
1824 if (*tbl
) { *tbl
= (*tbl
)->next
; free(a
); d
->AnswerTableCount
--; }
1825 else Log("Error: DeleteLLQ - AnswerList not found in table");
1828 // remove LLQ from table, free memory
1829 while(*ptr
&& *ptr
!= e
) ptr
= &(*ptr
)->next
;
1830 if (!*ptr
) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1831 *ptr
= (*ptr
)->next
;
1835 mDNSlocal
int SendLLQ(DaemonInfo
*d
, PktMsg
*pkt
, struct sockaddr_in dst
, TCPSocket
*sock
)
1844 if ( SendPacket( sock
, pkt
) != 0 )
1846 LogErr("DaemonInfo", "MySend");
1847 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1852 if (sendto(d
->llq_udpsd
, &pkt
->msg
, pkt
->len
, 0, (struct sockaddr
*)&dst
, sizeof(dst
)) != (int)pkt
->len
)
1854 LogErr("DaemonInfo", "sendto");
1855 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1864 mDNSlocal CacheRecord
*AnswerQuestion(DaemonInfo
*d
, AnswerListElem
*e
)
1868 TCPSocket
*sock
= NULL
;
1869 const mDNSu8
*ansptr
;
1870 mDNSu8
*end
= q
.msg
.data
;
1871 PktMsg buf
, *reply
= NULL
;
1872 LargeCacheRecord lcr
;
1873 CacheRecord
*AnswerList
= NULL
;
1876 VLog("Querying server for %##s type %d", e
->name
.c
, e
->type
);
1878 InitializeDNSMessage(&q
.msg
.h
, zeroID
, uQueryFlags
);
1880 end
= putQuestion(&q
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->name
, e
->type
, kDNSClass_IN
);
1881 if (!end
) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end
; }
1882 q
.len
= (int)(end
- (mDNSu8
*)&q
.msg
);
1890 if (UDPServerTransaction(d
, &q
, &buf
, &trunc
) < 0)
1891 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e
->name
.c
);
1893 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e
->name
.c
); e
->UseTCP
= mDNStrue
; }
1894 else reply
= &buf
; // success
1901 sock
= ConnectToServer(d
);
1902 if (!sock
) { Log("AnswerQuestion: ConnectToServer failed"); goto end
; }
1903 if (SendPacket( sock
, &q
)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock
); goto end
; }
1904 reply
= RecvPacket( sock
, NULL
, &closed
);
1905 mDNSPlatformTCPCloseConnection( sock
);
1906 require_action( reply
, end
, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1910 if (reply
) HdrNToH(reply
);
1912 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
))
1913 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end
; }
1914 rcode
= (mDNSu8
)(reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1915 if (rcode
&& rcode
!= kDNSFlag1_RC_NXDomain
) { Log("AnswerQuestion: %##s type %d - non-zero rcode %d from server", e
->name
.c
, e
->type
, rcode
); goto end
; }
1917 end
= (mDNSu8
*)&reply
->msg
+ reply
->len
;
1918 ansptr
= LocateAnswers(&reply
->msg
, end
);
1919 if (!ansptr
) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end
; }
1921 for (i
= 0; i
< reply
->msg
.h
.numAnswers
; i
++)
1923 ansptr
= GetLargeResourceRecord(NULL
, &reply
->msg
, ansptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1924 if (!ansptr
) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end
; }
1925 if (lcr
.r
.resrec
.rrtype
!= e
->type
|| lcr
.r
.resrec
.rrclass
!= kDNSClass_IN
|| !SameDomainName(lcr
.r
.resrec
.name
, &e
->name
))
1927 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1928 lcr
.r
.resrec
.name
->c
, lcr
.r
.resrec
.rrtype
, e
->name
.c
, e
->type
);
1932 CacheRecord
*cr
= CopyCacheRecord(&lcr
.r
, &e
->name
);
1933 if (!cr
) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end
; }
1934 cr
->next
= AnswerList
;
1940 if (reply
&& reply
!= &buf
) free(reply
);
1944 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1945 mDNSlocal
void *UpdateAnswerList(void *args
)
1947 CacheRecord
*cr
, *NewAnswers
, **na
, **ka
; // "new answer", "known answer"
1948 DaemonInfo
*d
= ((UpdateAnswerListArgs
*)args
)->d
;
1949 AnswerListElem
*a
= ((UpdateAnswerListArgs
*)args
)->a
;
1954 // get up to date answers
1955 NewAnswers
= AnswerQuestion(d
, a
);
1957 // first pass - mark all answers for deletion
1958 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1959 (*ka
)->resrec
.rroriginalttl
= (unsigned)-1; // -1 means delete
1961 // second pass - mark answers pre-existent
1962 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1964 for (na
= &NewAnswers
; *na
; na
= &(*na
)->next
)
1966 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
))
1967 { (*ka
)->resrec
.rroriginalttl
= 0; break; } // 0 means no change
1971 // third pass - add new records to Event list
1975 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1976 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
)) break;
1979 // answer is not in list - splice from NewAnswers list, add to Event list
1981 *na
= (*na
)->next
; // splice from list
1982 cr
->next
= a
->EventList
; // add spliced record to event list
1984 cr
->resrec
.rroriginalttl
= 1; // 1 means add
1986 else na
= &(*na
)->next
;
1989 // move all the removes from the answer list to the event list
1990 ka
= &a
->KnownAnswers
;
1993 if ((*ka
)->resrec
.rroriginalttl
== (unsigned)-1)
1997 cr
->next
= a
->EventList
;
2000 else ka
= &(*ka
)->next
;
2003 // lastly, free the remaining records (known answers) in NewAnswers list
2007 NewAnswers
= NewAnswers
->next
;
2014 mDNSlocal
void SendEvents(DaemonInfo
*d
, LLQEntry
*e
)
2018 mDNSu8
*end
= (mDNSu8
*)&response
.msg
.data
;
2020 char rrbuf
[MaxMsg
], addrbuf
[32];
2023 // Should this really be random? Do we use the msgID on the receiving end?
2024 msgID
.NotAnInteger
= random();
2025 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2026 InitializeDNSMessage(&response
.msg
.h
, msgID
, ResponseFlags
);
2027 end
= putQuestion(&response
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2028 if (!end
) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
2030 // put adds/removes in packet
2031 for (cr
= e
->AnswerList
->EventList
; cr
; cr
= cr
->next
)
2033 if (verbose
) GetRRDisplayString_rdb(&cr
->resrec
, &cr
->resrec
.rdata
->u
, rrbuf
);
2034 VLog("%s (%s): %s", addrbuf
, (mDNSs32
)cr
->resrec
.rroriginalttl
< 0 ? "Remove": "Add", rrbuf
);
2035 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAnswers
, &cr
->resrec
, cr
->resrec
.rroriginalttl
);
2036 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
2039 FormatLLQOpt(&opt
, kLLQOp_Event
, &e
->id
, LLQLease(e
));
2040 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2041 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
2043 response
.len
= (int)(end
- (mDNSu8
*)&response
.msg
);
2044 if (SendLLQ(d
, &response
, e
->cli
, NULL
) < 0) LogMsg("Error: SendEvents - SendLLQ");
2047 mDNSlocal
void PrintLLQAnswers(DaemonInfo
*d
)
2052 Log("Printing LLQ Answer Table contents");
2054 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2056 AnswerListElem
*a
= d
->AnswerTable
[i
];
2060 const CacheRecord
*rr
= a
->KnownAnswers
;
2061 while (rr
) { ancount
++; rr
= rr
->next
; }
2062 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a
, a
->name
.c
, a
->type
, a
->refcount
, ancount
);
2063 for (rr
= a
->KnownAnswers
; rr
; rr
= rr
->next
) Log("\t%s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, rrbuf
));
2069 mDNSlocal
void PrintLLQTable(DaemonInfo
*d
)
2075 Log("Printing LLQ table contents");
2077 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2086 case RequestReceived
: state
= "RequestReceived"; break;
2087 case ChallengeSent
: state
= "ChallengeSent"; break;
2088 case Established
: state
= "Established"; break;
2089 default: state
= "unknown";
2091 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2093 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
2094 addr
, state
, e
->qname
.c
, e
->qtype
, e
->lease
, LLQLease(e
), e
->AnswerList
);
2100 // Send events to clients as a result of a change in the zone
2101 mDNSlocal
void GenLLQEvents(DaemonInfo
*d
)
2106 UpdateAnswerListArgs
*args
;
2108 VLog("Generating LLQ Events");
2110 gettimeofday(&t
, NULL
);
2112 // get all answers up to date
2113 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2115 AnswerListElem
*a
= d
->AnswerTable
[i
];
2118 args
= malloc(sizeof(*args
));
2119 if (!args
) { LogErr("GenLLQEvents", "malloc"); return; }
2122 if (pthread_create(&a
->tid
, NULL
, UpdateAnswerList
, args
) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
2128 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2130 AnswerListElem
*a
= d
->AnswerTable
[i
];
2133 if (pthread_join(a
->tid
, NULL
)) LogErr("GenLLQEvents", "pthread_join");
2138 // for each established LLQ, send events
2139 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2141 e
= &d
->LLQTable
[i
];
2144 if ((*e
)->expire
< t
.tv_sec
) DeleteLLQ(d
, *e
);
2147 if ((*e
)->state
== Established
&& (*e
)->AnswerList
->EventList
) SendEvents(d
, *e
);
2153 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2154 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2156 AnswerListElem
*a
= d
->AnswerTable
[i
];
2161 CacheRecord
*cr
= a
->EventList
, *tmp
;
2166 if ((signed)tmp
->resrec
.rroriginalttl
< 0) free(tmp
);
2169 tmp
->next
= a
->KnownAnswers
;
2170 a
->KnownAnswers
= tmp
;
2171 tmp
->resrec
.rroriginalttl
= 0;
2174 a
->EventList
= NULL
;
2181 mDNSlocal
void SetAnswerList(DaemonInfo
*d
, LLQEntry
*e
)
2183 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
2184 AnswerListElem
*a
= d
->AnswerTable
[bucket
];
2185 while (a
&& (a
->type
!= e
->qtype
||!SameDomainName(&a
->name
, &e
->qname
))) a
= a
->next
;
2188 a
= malloc(sizeof(*a
));
2189 if (!a
) { LogErr("SetAnswerList", "malloc"); return; }
2190 AssignDomainName(&a
->name
, &e
->qname
);
2193 a
->EventList
= NULL
;
2194 a
->UseTCP
= mDNSfalse
;
2195 a
->next
= d
->AnswerTable
[bucket
];
2196 d
->AnswerTable
[bucket
] = a
;
2197 d
->AnswerTableCount
++;
2198 a
->KnownAnswers
= AnswerQuestion(d
, a
);
2205 // Allocate LLQ entry, insert into table
2206 mDNSlocal LLQEntry
*NewLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, mDNSu32 lease
)
2210 int bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2213 e
= malloc(sizeof(*e
));
2214 if (!e
) { LogErr("NewLLQ", "malloc"); return NULL
; }
2216 inet_ntop(AF_INET
, &cli
.sin_addr
, addr
, 32);
2217 VLog("Allocating LLQ entry for client %s question %##s type %d", addr
, qname
->c
, qtype
);
2219 // initialize structure
2221 AssignDomainName(&e
->qname
, qname
);
2223 e
->id
= zeroOpaque64
;
2224 e
->state
= RequestReceived
;
2225 e
->AnswerList
= NULL
;
2227 if (lease
< LLQ_MIN_LEASE
) lease
= LLQ_MIN_LEASE
;
2228 else if (lease
> LLQ_MAX_LEASE
) lease
= LLQ_MAX_LEASE
;
2230 gettimeofday(&t
, NULL
);
2231 e
->expire
= t
.tv_sec
+ (int)lease
;
2235 e
->next
= d
->LLQTable
[bucket
];
2236 d
->LLQTable
[bucket
] = e
;
2241 // Handle a refresh request from client
2242 mDNSlocal
void LLQRefresh(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2246 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2249 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2250 VLog("%s LLQ for %##s from %s", llq
->llqlease
? "Refreshing" : "Deleting", e
->qname
.c
, addr
);
2255 if (llq
->llqlease
< LLQ_MIN_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2256 else if (llq
->llqlease
> LLQ_MAX_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2257 gettimeofday(&t
, NULL
);
2258 e
->expire
= t
.tv_sec
+ llq
->llqlease
;
2261 ack
.src
.sin_addr
.s_addr
= 0; // unused
2262 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2263 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2264 if (!end
) { Log("Error: putQuestion"); return; }
2266 FormatLLQOpt(&opt
, kLLQOp_Refresh
, &e
->id
, llq
->llqlease
? LLQLease(e
) : 0);
2267 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2268 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2270 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2271 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQRefresh");
2273 if (llq
->llqlease
) e
->state
= Established
;
2274 else DeleteLLQ(d
, e
);
2277 // Complete handshake with Ack an initial answers
2278 mDNSlocal
void LLQCompleteHandshake(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2284 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2285 char rrbuf
[MaxMsg
], addrbuf
[32];
2287 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2289 if (!mDNSSameOpaque64(&llq
->id
, &e
->id
) ||
2290 llq
->vers
!= kLLQ_Vers
||
2291 llq
->llqOp
!= kLLQOp_Setup
||
2292 llq
->err
!= LLQErr_NoError
||
2293 llq
->llqlease
> e
->lease
+ LLQ_LEASE_FUDGE
||
2294 llq
->llqlease
< e
->lease
- LLQ_LEASE_FUDGE
)
2296 Log("Incorrect challenge response from %s", addr
);
2300 if (e
->state
== Established
) VLog("Retransmitting LLQ ack + answers for %##s", e
->qname
.c
);
2301 else VLog("Delivering LLQ ack + answers for %##s", e
->qname
.c
);
2303 // format ack + answers
2304 ack
.src
.sin_addr
.s_addr
= 0; // unused
2305 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2306 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2307 if (!end
) { Log("Error: putQuestion"); return; }
2309 if (e
->state
!= Established
) { SetAnswerList(d
, e
); e
->state
= Established
; }
2311 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2312 for (ptr
= e
->AnswerList
->KnownAnswers
; ptr
; ptr
= ptr
->next
)
2314 if (verbose
) GetRRDisplayString_rdb(&ptr
->resrec
, &ptr
->resrec
.rdata
->u
, rrbuf
);
2315 VLog("%s Intitial Answer - %s", addr
, rrbuf
);
2316 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAnswers
, &ptr
->resrec
, 1);
2317 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2320 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2321 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2322 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2324 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2325 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQCompleteHandshake");
2328 mDNSlocal
void LLQSetupChallenge(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
)
2332 mDNSu8
*end
= challenge
.msg
.data
;
2335 if (e
->state
== ChallengeSent
) VLog("Retransmitting LLQ setup challenge for %##s", e
->qname
.c
);
2336 else VLog("Sending LLQ setup challenge for %##s", e
->qname
.c
);
2338 if (!mDNSOpaque64IsZero(&llq
->id
)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2339 if (llq
->llqOp
!= kLLQOp_Setup
) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2341 if (mDNSOpaque64IsZero(&e
->id
)) // don't regenerate random ID for retransmissions
2343 // construct ID <time><random>
2344 gettimeofday(&t
, NULL
);
2345 e
->id
.l
[0] = t
.tv_sec
;
2346 e
->id
.l
[1] = random();
2349 // format response (query + LLQ opt rr)
2350 challenge
.src
.sin_addr
.s_addr
= 0; // unused
2351 InitializeDNSMessage(&challenge
.msg
.h
, msgID
, ResponseFlags
);
2352 end
= putQuestion(&challenge
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2353 if (!end
) { Log("Error: putQuestion"); return; }
2354 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2355 end
= PutResourceRecordTTLJumbo(&challenge
.msg
, end
, &challenge
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2356 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2357 challenge
.len
= (int)(end
- (mDNSu8
*)&challenge
.msg
);
2358 if (SendLLQ(d
, &challenge
, e
->cli
, NULL
)) { Log("Error: LLQSetupChallenge"); return; }
2359 e
->state
= ChallengeSent
;
2362 // Take action on an LLQ message from client. Entry must be initialized and in table
2363 mDNSlocal
void UpdateLLQ(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2367 case RequestReceived
:
2371 gettimeofday(&t
, NULL
);
2372 e
->id
.l
[0] = t
.tv_sec
; // construct ID <time><random>
2373 e
->id
.l
[1] = random();
2375 LLQCompleteHandshake( d
, e
, llq
, msgID
, sock
);
2377 // Set the state to established because we've just set the LLQ up using TCP
2378 e
->state
= Established
;
2382 LLQSetupChallenge(d
, e
, llq
, msgID
);
2386 if (mDNSOpaque64IsZero(&llq
->id
)) LLQSetupChallenge(d
, e
, llq
, msgID
); // challenge sent and lost
2387 else LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
);
2390 if (mDNSOpaque64IsZero(&llq
->id
))
2392 // client started over. reset state.
2393 LLQEntry
*newe
= NewLLQ(d
, e
->cli
, &e
->qname
, e
->qtype
, llq
->llqlease
);
2396 LLQSetupChallenge(d
, newe
, llq
, msgID
);
2399 else if (llq
->llqOp
== kLLQOp_Setup
)
2400 { LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
); return; } // Ack lost
2401 else if (llq
->llqOp
== kLLQOp_Refresh
)
2402 { LLQRefresh(d
, e
, llq
, msgID
, sock
); return; }
2403 else { Log("Unhandled message for established LLQ"); return; }
2407 mDNSlocal LLQEntry
*LookupLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, const mDNSOpaque64
*const id
)
2409 int bucket
= bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2410 LLQEntry
*ptr
= d
->LLQTable
[bucket
];
2414 if (((ptr
->state
== ChallengeSent
&& mDNSOpaque64IsZero(id
) && (cli
.sin_port
== ptr
->cli
.sin_port
)) || // zero-id due to packet loss OK in state ChallengeSent
2415 mDNSSameOpaque64(id
, &ptr
->id
)) && // id match
2416 (cli
.sin_addr
.s_addr
== ptr
->cli
.sin_addr
.s_addr
) && (qtype
== ptr
->qtype
) && SameDomainName(&ptr
->qname
, qname
)) // same source, type, qname
2433 pkt
->msg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
2435 res
= sendto( d
->udpsd
, &pkt
->msg
, pkt
->len
, 0, ( struct sockaddr
* ) &pkt
->src
, sizeof( pkt
->src
) );
2436 require_action( res
== ( int ) pkt
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvNotify", "sendto" ) );
2444 mDNSlocal
int RecvLLQ( DaemonInfo
*d
, PktMsg
*pkt
, TCPSocket
*sock
)
2447 LargeCacheRecord opt
;
2450 const mDNSu8
*qptr
= pkt
->msg
.data
;
2451 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2453 LLQOptData
*llq
= NULL
;
2457 aptr
= LocateAdditionals(&pkt
->msg
, end
); // Can't do this until after HdrNToH(pkt);
2458 inet_ntop(AF_INET
, &pkt
->src
.sin_addr
, addr
, 32);
2460 VLog("Received LLQ msg from %s", addr
);
2461 // sanity-check packet
2462 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2464 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
2468 // Locate the OPT record.
2469 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2470 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2471 // but not necessarily the *last* entry in the Additional Section.
2472 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2474 aptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, aptr
, end
, 0, kDNSRecordTypePacketAdd
, &opt
);
2475 if (!aptr
) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr
, i
); goto end
; }
2476 if (opt
.r
.resrec
.rrtype
== kDNSType_OPT
) break;
2480 if (opt
.r
.resrec
.rrtype
!= kDNSType_OPT
) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr
); goto end
; }
2481 if (opt
.r
.resrec
.rdlength
< pkt
->msg
.h
.numQuestions
* LLQ_OPT_RDLEN
) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr
, opt
.r
.resrec
.rdlength
, pkt
->msg
.h
.numQuestions
); }
2483 // dispatch each question
2484 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
2486 qptr
= getQuestion(&pkt
->msg
, qptr
, end
, 0, &q
);
2487 if (!qptr
) { Log("Malformatted LLQ from %s: cannot read question %d", addr
, i
); goto end
; }
2488 llq
= (LLQOptData
*)&opt
.r
.resrec
.rdata
->u
.opt
.OptData
.llq
+ i
; // point into OptData at index i
2489 if (llq
->vers
!= kLLQ_Vers
) { Log("LLQ from %s contains bad version %d (expected %d)", addr
, llq
->vers
, kLLQ_Vers
); goto end
; }
2491 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2494 // no entry - if zero ID, create new
2495 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2498 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2508 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
2510 const mDNSu8
* lastPtr
= NULL
;
2511 const mDNSu8
* ptr
= NULL
;
2512 DomainAuthInfo
* keys
;
2513 mDNSu8
* end
= ( mDNSu8
* ) &pkt
->msg
+ pkt
->len
;
2514 LargeCacheRecord lcr
;
2515 mDNSBool hasTSIG
= mDNSfalse
;
2516 mDNSBool strip
= mDNSfalse
;
2517 mDNSBool ok
= mDNSfalse
;
2520 // Unused parameters
2528 if ( pkt
->msg
.h
.numAdditionals
)
2530 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2533 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2536 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2539 Log("Unable to read additional record");
2545 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2549 LogMsg( "IsAuthorized: unable to find Additional section" );
2553 // If we don't know what zone this is, then it's authorized.
2562 if ( IsQuery( pkt
) )
2564 keys
= pkt
->zone
->queryKeys
;
2567 else if ( IsUpdate( pkt
) )
2569 keys
= pkt
->zone
->updateKeys
;
2579 if ( pkt
->isZonePublic
)
2585 // If there are no keys, then we're authorized
2587 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
2589 Log( "Invalid TSIG spec %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2590 *rcode
= kDNSFlag1_RC_NotAuth
;
2591 *tcode
= TSIG_ErrBadKey
;
2597 // Find the right key
2599 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2601 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
2609 Log( "Invalid TSIG name %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2610 *rcode
= kDNSFlag1_RC_NotAuth
;
2611 *tcode
= TSIG_ErrBadKey
;
2617 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2618 // lifting of message verification
2620 pkt
->msg
.h
.numAdditionals
--;
2624 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2628 pkt
->msg
.h
.numAdditionals
++;
2632 if ( hasTSIG
&& strip
)
2634 // Strip the TSIG from the message
2636 pkt
->msg
.h
.numAdditionals
--;
2637 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2645 // request handler wrappers for TCP and UDP requests
2646 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2654 UDPContext
* context
= ( UDPContext
* ) vptr
;
2655 PktMsg
* reply
= NULL
;
2659 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2660 // may give us a long answer that would require truncation for UDP delivery to client
2662 reply
= HandleRequest( context
->d
, &context
->pkt
);
2663 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
2665 res
= sendto( context
->sd
, &reply
->msg
, reply
->len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2666 require_action_quiet( res
== ( int ) reply
->len
, exit
, LogErr( "UDPMessageHandler", "sendto" ) );
2677 pthread_exit( NULL
);
2690 UDPContext
* context
= NULL
;
2694 DomainAuthInfo
* key
;
2695 unsigned int clisize
= sizeof( context
->cliaddr
);
2697 mStatus err
= mStatus_NoError
;
2699 context
= malloc( sizeof( UDPContext
) );
2700 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2702 bzero( context
, sizeof( *context
) );
2706 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
2708 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvUDPMessage", "recvfrom" ) );
2709 context
->pkt
.len
= res
;
2710 require_action( clisize
== sizeof( context
->cliaddr
), exit
, err
= mStatus_UnknownErr
; Log( "Client address of unknown size %d", clisize
) );
2711 context
->pkt
.src
= context
->cliaddr
;
2713 // Set the zone in the packet
2715 SetZone( context
->d
, &context
->pkt
);
2717 // Notify messages handled by main thread
2719 if ( IsNotify( &context
->pkt
) )
2721 int e
= RecvNotify( self
, &context
->pkt
);
2725 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2727 if ( IsLLQRequest( &context
->pkt
) )
2729 // LLQ messages handled by main thread
2730 int e
= RecvLLQ( self
, &context
->pkt
, NULL
);
2735 if ( IsLLQAck(&context
->pkt
) )
2737 // !!!KRS need to do acks + retrans
2743 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2744 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2746 pthread_detach(tid
);
2753 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2755 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2756 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_NXDomain
;
2758 e
= sendto( sd
, &reply
.msg
, reply
.len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2759 require_action_quiet( e
== ( int ) reply
.len
, exit
, LogErr( "RecvUDPMessage", "sendto" ) );
2761 err
= mStatus_NoAuth
;
2766 if ( err
&& context
)
2778 TCPContext
* context
2783 if ( context
->sock
)
2785 mDNSPlatformTCPCloseConnection( context
->sock
);
2799 TCPContext
* context
= ( TCPContext
* ) vptr
;
2800 PktMsg
* reply
= NULL
;
2804 //!!!KRS if this read blocks indefinitely, we can run out of threads
2807 reply
= HandleRequest( context
->d
, &context
->pkt
);
2808 require_action_quiet( reply
, exit
, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2810 // deliver reply to client
2812 res
= SendPacket( context
->sock
, reply
);
2813 require_action( res
>= 0, exit
, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2817 FreeTCPContext( context
);
2834 TCPContext
* context
= ( TCPContext
* ) param
;
2838 DomainAuthInfo
* key
;
2841 mDNSBool freeContext
= mDNStrue
;
2842 mStatus err
= mStatus_NoError
;
2844 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2845 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2846 // wire. We'll let it do that, and wait for the next packet which will be ours.
2848 pkt
= RecvPacket( context
->sock
, &context
->pkt
, &closed
);
2849 if (pkt
) HdrNToH(pkt
);
2850 require_action( pkt
|| !closed
, exit
, err
= mStatus_UnknownErr
; LogMsg( "client disconnected" ) );
2854 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2855 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2856 // are sent over UDP
2858 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2860 // Set's the DNS Zone that is associated with this message
2862 SetZone( context
->d
, &context
->pkt
);
2864 // IsAuthorized will make sure the message is authorized for the designated zone.
2865 // After verifying the signature, it will strip the TSIG from the message
2867 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2869 if ( IsLLQRequest( &context
->pkt
) )
2871 // LLQ messages handled by main thread
2872 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2876 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2880 LogErr( "RecvTCPMessage", "pthread_create" );
2881 err
= mStatus_NoError
;
2885 // Let the thread free the context
2887 freeContext
= mDNSfalse
;
2889 pthread_detach(tid
);
2896 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2898 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2900 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2901 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_Refused
;
2903 SendPacket( context
->sock
, &reply
);
2908 freeContext
= mDNSfalse
;
2915 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2920 FreeTCPContext( context
);
2930 TCPSocketFlags flags
2933 TCPContext
* context
= NULL
;
2934 unsigned int clilen
= sizeof( context
->cliaddr
);
2936 mStatus err
= mStatus_NoError
;
2938 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2939 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2940 bzero( context
, sizeof( sizeof( TCPContext
) ) );
2942 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2943 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2945 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2946 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2948 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2949 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2953 if ( err
&& context
)
2964 // listen for incoming requests, periodically check table for expired records, respond to signals
2965 mDNSlocal
int Run(DaemonInfo
*d
)
2967 int staticMaxFD
, nfds
;
2969 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
2970 mDNSBool EventsPending
= mDNSfalse
;
2972 VLog("Listening for requests...");
2976 if ( d
->tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tcpsd
+ 1;
2977 if ( d
->udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->udpsd
+ 1;
2978 if ( d
->tlssd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tlssd
+ 1;
2979 if ( d
->llq_tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_tcpsd
+ 1;
2980 if ( d
->llq_udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_udpsd
+ 1;
2981 if ( d
->LLQEventListenSock
+ 1 > staticMaxFD
) staticMaxFD
= d
->LLQEventListenSock
+ 1;
2985 EventSource
* source
;
2989 timeout
.tv_sec
= timeout
.tv_usec
= 0;
2990 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2994 if (timenow
.tv_sec
- EventTS
.tv_sec
>= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2995 { GenLLQEvents(d
); EventsPending
= mDNSfalse
; } // events, we go ahead and do it now
2996 else timeout
.tv_usec
= 500000; // else do events after 1/2 second with no new events or LLQs
3000 // if no pending events, timeout when we need to check for expired records
3001 if (tablecheck
.tv_sec
&& timenow
.tv_sec
- tablecheck
.tv_sec
>= 0)
3002 { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; } // table check overdue
3003 if (!tablecheck
.tv_sec
) tablecheck
.tv_sec
= timenow
.tv_sec
+ EXPIRATION_INTERVAL
;
3004 timeout
.tv_sec
= tablecheck
.tv_sec
- timenow
.tv_sec
;
3008 FD_SET( d
->tcpsd
, &rset
);
3009 FD_SET( d
->udpsd
, &rset
);
3010 FD_SET( d
->tlssd
, &rset
);
3011 FD_SET( d
->llq_tcpsd
, &rset
);
3012 FD_SET( d
->llq_udpsd
, &rset
);
3013 FD_SET( d
->LLQEventListenSock
, &rset
);
3015 maxFD
= staticMaxFD
;
3017 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3019 FD_SET( source
->fd
, &rset
);
3021 if ( source
->fd
> maxFD
)
3027 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
3034 // close sockets to prevent clients from making new requests during shutdown
3038 close( d
->llq_tcpsd
);
3039 close( d
->llq_udpsd
);
3040 d
->tcpsd
= d
->udpsd
= d
->tlssd
= d
->llq_tcpsd
= d
->llq_udpsd
= -1;
3041 DeleteRecords(d
, mDNStrue
);
3046 Log( "Received SIGINFO" );
3057 Log( "Received SIGHUP" );
3059 err
= ParseConfig( d
, cfgfile
);
3063 LogErr( "Run", "ParseConfig" );
3071 Log("Received unhandled signal - continuing");
3076 LogErr("Run", "select"); return -1;
3081 if (FD_ISSET(d
->udpsd
, &rset
)) RecvUDPMessage( d
, d
->udpsd
);
3082 if (FD_ISSET(d
->llq_udpsd
, &rset
)) RecvUDPMessage( d
, d
->llq_udpsd
);
3083 if (FD_ISSET(d
->tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->tcpsd
, 0 );
3084 if (FD_ISSET(d
->llq_tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->llq_tcpsd
, 0 );
3085 if (FD_ISSET(d
->tlssd
, &rset
)) AcceptTCPConnection( d
, d
->tlssd
, TCP_SOCKET_FLAGS
);
3086 if (FD_ISSET(d
->LLQEventListenSock
, &rset
))
3088 // clear signalling data off socket
3090 recv(d
->LLQEventListenSock
, buf
, 256, 0);
3093 EventsPending
= mDNStrue
;
3094 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
3098 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3100 if ( FD_ISSET( source
->fd
, &rset
) )
3102 source
->callback( source
->context
);
3103 break; // in case we removed this guy from the event loop
3110 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
3111 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
3117 // signal handler sets global variables, which are inspected by main event loop
3118 // (select automatically returns due to the handled signal)
3119 mDNSlocal
void HndlSignal(int sig
)
3121 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
3122 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
3123 if (sig
== SIGHUP
) { hangup
= 1; return; }
3133 DNameListElem
* elem
;
3134 mStatus err
= mStatus_NoError
;
3136 elem
= ( DNameListElem
* ) malloc( sizeof( DNameListElem
) );
3137 require_action( elem
, exit
, err
= mStatus_NoMemoryErr
);
3138 MakeDomainNameFromDNSNameString( &elem
->name
, name
);
3139 elem
->next
= d
->public_names
;
3140 d
->public_names
= elem
;
3148 int main(int argc
, char *argv
[])
3150 int started_via_launchd
= 0;
3154 Log("dnsextd starting");
3156 d
= malloc(sizeof(*d
));
3157 if (!d
) { LogErr("main", "malloc"); exit(1); }
3158 bzero(d
, sizeof(DaemonInfo
));
3160 // Setup the public SRV record names
3162 SetPublicSRV(d
, "_dns-update._udp.");
3163 SetPublicSRV(d
, "_dns-llq._udp.");
3164 SetPublicSRV(d
, "_dns-update-tls._tcp.");
3165 SetPublicSRV(d
, "_dns-query-tls._tcp.");
3166 SetPublicSRV(d
, "_dns-llq-tls._tcp.");
3168 // Setup signal handling
3170 if (signal(SIGHUP
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGHUP");
3171 if (signal(SIGTERM
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGTERM");
3172 if (signal(INFO_SIGNAL
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINFO");
3173 if (signal(SIGINT
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINT");
3174 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) perror("Can't ignore SIGPIPE");
3176 // remove open file limit
3177 rlim
.rlim_max
= RLIM_INFINITY
;
3178 rlim
.rlim_cur
= RLIM_INFINITY
;
3179 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3181 LogErr("main", "setrlimit");
3182 Log("Using default file descriptor resource limit");
3185 if (!strcasecmp(argv
[1], "-launchd"))
3187 Log("started_via_launchd");
3188 started_via_launchd
= 1;
3192 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3194 if (!foreground
&& !started_via_launchd
)
3198 LogErr("main", "daemon");
3203 if (InitLeaseTable(d
) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3204 if (SetupSockets(d
) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3205 if (SetUpdateSRV(d
) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3209 Log("dnsextd stopping");
3211 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3217 // These are stubbed out implementations of up-call routines that the various platform support layers
3218 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3219 // link this code in.
3221 // It's an error for these routines to actually be called, so perhaps we should log any call
3223 void mDNSCoreInitComplete( mDNS
* const m
, mStatus result
) { ( void ) m
; ( void ) result
; }
3224 void mDNSCoreMachineSleep(mDNS
* const m
, mDNSBool wake
) { ( void ) m
; ( void ) wake
; }
3225 void mDNSCoreReceive(mDNS
*const m
, void *const msg
, const mDNSu8
*const end
,
3226 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
,
3227 const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID iid
)
3228 { ( void ) m
; ( void ) msg
; ( void ) end
; ( void ) srcaddr
; ( void ) srcport
; ( void ) dstaddr
; ( void ) dstport
; ( void ) iid
; }
3229 DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
)
3230 { ( void ) m
; ( void ) d
; ( void ) interface
; ( void ) addr
; ( void ) port
; return(NULL
); }
3231 void mDNS_AddSearchDomain(const domainname
*const domain
) { (void)domain
; }
3232 void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3233 { ( void ) m
; ( void ) fqdn
; ( void ) StatusCallback
; ( void ) StatusContext
; }
3234 mDNSs32
mDNS_Execute (mDNS
*const m
) { ( void ) m
; return 0; }
3235 mDNSs32
mDNS_TimeNow(const mDNS
*const m
) { ( void ) m
; return 0; }
3236 mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3237 void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3238 { ( void ) m
; ( void ) set
; ( void ) flapping
; }
3239 const char * const mDNS_DomainTypeNames
[1] = {};
3240 mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
3241 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
3242 { ( void ) m
; ( void ) question
; ( void ) DomainType
; ( void ) dom
; ( void ) InterfaceID
; ( void ) Callback
; ( void ) Context
; return 0; }
3243 mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3244 mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3245 { ( void ) m
; ( void ) set
; ( void ) flapping
; return 0; }
3246 void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
) { ( void ) m
; ( void ) fqdn
; }
3247 void mDNS_SetFQDN(mDNS
* const m
) { ( void ) m
; }
3248 void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3249 { ( void ) m
; ( void ) v4addr
; ( void ) v6addr
; ( void ) router
; }
3250 mStatus
uDNS_SetupDNSConfig( mDNS
*const m
) { ( void ) m
; return 0; }
3251 mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
3252 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, mDNSBool AutoTunnel
)
3253 { ( void ) m
; ( void ) info
; ( void ) domain
; ( void ) keyname
; ( void ) b64keydata
; ( void ) AutoTunnel
; return 0; }
3254 mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
) { ( void ) m
; ( void ) question
; return 0; }
3258 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
3259 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
3260 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
3261 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
3262 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
3264 // For convenience when using the "strings" command, this is the last thing in the file
3265 // The "@(#) " pattern is a special prefix the "what" command looks for
3266 const char mDNSResponderVersionString_SCCS
[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
3268 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3269 const char *__crashreporter_info__
= mDNSResponderVersionString_SCCS
+ 5;
3270 asm(".desc ___crashreporter_info__, 0x10");