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.84 2007/10/24 18:19:37 cheshire
21 Fixed header byte order bug sending update responses
23 Revision 1.83 2007/10/17 22:52:26 cheshire
24 Get rid of unused mDNS_UpdateLLQs()
26 Revision 1.82 2007/09/27 17:42:49 cheshire
27 Fix naming: for consistency, "kDNSFlag1_RC" should be "kDNSFlag1_RC_Mask"
29 Revision 1.81 2007/09/21 21:12:37 cheshire
30 DNSDigest_SignMessage does not need separate "mDNSu16 *numAdditionals" parameter
32 Revision 1.80 2007/09/18 19:09:02 cheshire
33 <rdar://problem/5489549> mDNSResponderHelper (and other binaries) missing SCCS version strings
35 Revision 1.79 2007/07/11 02:59:58 cheshire
36 <rdar://problem/5303807> Register IPv6-only hostname and don't create port mappings for AutoTunnel services
37 Add AutoTunnel parameter to mDNS_SetSecretForDomain
39 Revision 1.78 2007/06/20 01:10:13 cheshire
40 <rdar://problem/5280520> Sync iPhone changes into main mDNSResponder code
42 Revision 1.77 2007/05/15 21:57:17 cheshire
43 <rdar://problem/4608220> Use dnssd_SocketValid(x) macro instead of just
44 assuming that all negative values (or zero!) are invalid socket numbers
46 Revision 1.76 2007/05/01 23:53:26 cheshire
47 <rdar://problem/5175318> dnsextd should refuse updates without attached lease
49 Revision 1.75 2007/05/01 00:18:12 cheshire
50 Use "-launchd" instead of "-d" when starting via launchd
51 (-d sets foreground mode, which writes errors to stderr, which is ignored when starting via launchd)
53 Revision 1.74 2007/04/26 00:35:16 cheshire
54 <rdar://problem/5140339> uDNS: Domain discovery not working over VPN
55 Fixes to make sure results update correctly when connectivity changes (e.g. a DNS server
56 inside the firewall may give answers where a public one gives none, and vice versa.)
58 Revision 1.73 2007/04/22 06:02:03 cheshire
59 <rdar://problem/4615977> Query should immediately return failure when no server
61 Revision 1.72 2007/04/05 22:55:37 cheshire
62 <rdar://problem/5077076> Records are ending up in Lighthouse without expiry information
64 Revision 1.71 2007/04/05 19:43:56 cheshire
65 Added ProgramName and comment about '-d' option
67 Revision 1.70 2007/04/05 18:34:40 cheshire
68 <rdar://problem/4838930> dnsextd gives "bind - Address already in use" error
70 Revision 1.69 2007/03/28 21:14:08 cheshire
71 The rrclass field of an OPT pseudo-RR holds the sender's UDP payload size
73 Revision 1.68 2007/03/28 18:20:50 cheshire
76 Revision 1.67 2007/03/21 00:30:07 cheshire
77 <rdar://problem/4789455> Multiple errors in DNameList-related code
79 Revision 1.66 2007/03/20 17:07:16 cheshire
80 Rename "struct uDNS_TCPSocket_struct" to "TCPSocket", "struct uDNS_UDPSocket_struct" to "UDPSocket"
82 Revision 1.65 2007/02/07 19:32:00 cheshire
83 <rdar://problem/4980353> All mDNSResponder components should contain version strings in SCCS-compatible format
85 Revision 1.64 2007/01/20 01:43:26 cheshire
86 <rdar://problem/4058383> Should not write log messages to /dev/console
88 Revision 1.63 2007/01/20 01:31:56 cheshire
91 Revision 1.62 2007/01/17 22:06:03 cheshire
92 Replace duplicated literal constant "{ { 0 } }" with symbol "zeroIPPort"
94 Revision 1.61 2007/01/05 08:30:54 cheshire
95 Trim excessive "$Log" checkin history from before 2006
96 (checkin history still available via "cvs log ..." of course)
98 Revision 1.60 2007/01/05 08:07:29 cheshire
99 Remove unnecessary dummy udsserver_default_reg_domain_changed() routine
101 Revision 1.59 2007/01/05 05:46:47 cheshire
102 Remove unnecessary dummy udsserver_automatic_browse_domain_changed() routine
104 Revision 1.58 2007/01/04 23:11:54 cheshire
105 udsserver_default_browse_domain_changed renamed to udsserver_automatic_browse_domain_changed
107 Revision 1.57 2007/01/04 01:41:48 cheshire
108 Use _dns-update-tls/_dns-query-tls/_dns-llq-tls instead of creating a new "_tls" subdomain
110 Revision 1.56 2006/12/22 20:59:51 cheshire
111 <rdar://problem/4742742> Read *all* DNS keys from keychain,
112 not just key for the system-wide default registration domain
114 Revision 1.55 2006/11/30 23:08:39 herscher
115 <rdar://problem/4765644> uDNS: Sync up with Lighthouse changes for Private DNS
117 Revision 1.54 2006/11/18 05:01:33 cheshire
118 Preliminary support for unifying the uDNS and mDNS code,
119 including caching of uDNS answers
121 Revision 1.53 2006/11/17 23:55:09 cheshire
122 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
124 Revision 1.52 2006/11/17 04:27:51 cheshire
125 <rdar://problem/4842494> dnsextd byte-order bugs on Intel
127 Revision 1.51 2006/11/17 03:50:18 cheshire
128 Add debugging loggin in SendPacket and UDPServerTransaction
130 Revision 1.50 2006/11/17 03:48:57 cheshire
131 <rdar://problem/4842493> dnsextd replying on wrong port
133 Revision 1.49 2006/11/03 06:12:44 herscher
134 Make sure all buffers passed to GetRRDisplayString_rdb are of length MaxMsg
136 Revision 1.48 2006/10/20 19:18:35 cheshire
137 <rdar://problem/4669228> dnsextd generates bogus SRV record with null target
139 Revision 1.47 2006/10/20 05:43:51 herscher
140 LookupLLQ() needs to match on the port number when looking up the LLQ
142 Revision 1.46 2006/10/11 22:56:07 herscher
143 Tidy up the implementation of ZoneHandlesName
145 Revision 1.45 2006/08/22 03:28:57 herscher
146 <rdar://problem/4678717> Long-lived queries aren't working well in TOT.
148 Revision 1.44 2006/08/14 23:24:56 cheshire
149 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
151 Revision 1.43 2006/07/20 19:53:33 mkrochma
152 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
153 More fixes for private DNS
155 Revision 1.42 2006/07/05 22:48:19 cheshire
156 <rdar://problem/4472013> Add Private DNS server functionality to dnsextd
161 #include "../mDNSShared/uds_daemon.h"
162 #include "../mDNSShared/dnssd_ipc.h"
163 #include "../mDNSCore/uDNS.h"
164 #include "../mDNSShared/DebugServices.h"
169 #include <sys/types.h>
170 #include <sys/socket.h>
171 #include <netinet/in.h>
172 #include <arpa/inet.h>
176 #include <sys/time.h>
177 #include <sys/resource.h>
181 // Compatibility workaround
183 #define AF_LOCAL AF_UNIX
189 mDNSexport
const char ProgramName
[] = "dnsextd";
191 #define LOOPBACK "127.0.0.1"
192 #if !defined(LISTENQ)
193 # define LISTENQ 128 // tcp connection backlog
195 #define RECV_BUFLEN 9000
196 #define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
197 #define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
198 #define SRV_TTL 7200 // TTL For _dns-update SRV records
199 #define CONFIG_FILE "/etc/dnsextd.conf"
200 #define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
202 // LLQ Lease bounds (seconds)
203 #define LLQ_MIN_LEASE (15 * 60)
204 #define LLQ_MAX_LEASE (120 * 60)
205 #define LLQ_LEASE_FUDGE 60
207 // LLQ SOA poll interval (microseconds)
208 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
209 #define LLQ_MONITOR_INTERVAL 250000
211 #define INFO_SIGNAL SIGINFO
213 #define INFO_SIGNAL SIGUSR1
216 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
220 // Structs/fields that must be locked for thread safety are explicitly commented
223 // args passed to UDP request handler thread as void*
228 struct sockaddr_in cliaddr
;
233 // args passed to TCP request handler thread as void*
237 struct sockaddr_in cliaddr
;
238 TCPSocket
*sock
; // socket connected to client
242 // args passed to UpdateAnswerList thread as void*
247 } UpdateAnswerListArgs
;
253 // booleans to determine runtime output
254 // read-only after initialization (no mutex protection)
255 static mDNSBool foreground
= 0;
256 static mDNSBool verbose
= 0;
258 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
259 static mDNSBool terminate
= 0;
260 static mDNSBool dumptable
= 0;
261 static mDNSBool hangup
= 0;
263 // global for config file location
264 static char * cfgfile
= NULL
;
268 // Log messages are delivered to syslog unless -f option specified
271 // common message logging subroutine
272 mDNSlocal
void PrintLog(const char *buffer
)
276 fprintf(stderr
,"%s\n", buffer
);
281 openlog("dnsextd", LOG_CONS
, LOG_DAEMON
);
282 syslog(LOG_ERR
, "%s", buffer
);
287 // Verbose Logging (conditional on -v option)
288 mDNSlocal
void VLog(const char *format
, ...)
293 if (!verbose
) return;
294 va_start(ptr
,format
);
295 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
300 // Unconditional Logging
301 mDNSlocal
void Log(const char *format
, ...)
306 va_start(ptr
,format
);
307 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
313 // prints message "dnsextd <function>: <operation> - <error message>"
314 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
315 mDNSlocal
void LogErr(const char *fn
, const char *operation
)
317 char buf
[512], errbuf
[256];
318 strerror_r(errno
, errbuf
, sizeof(errbuf
));
319 snprintf(buf
, sizeof(buf
), "%s: %s - %s", fn
, operation
, errbuf
);
324 // Networking Utility Routines
327 // Convert DNS Message Header from Network to Host byte order
328 mDNSlocal
void HdrNToH(PktMsg
*pkt
)
330 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
331 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
332 pkt
->msg
.h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
333 pkt
->msg
.h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
334 pkt
->msg
.h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
335 pkt
->msg
.h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
338 // Convert DNS Message Header from Host to Network byte order
339 mDNSlocal
void HdrHToN(PktMsg
*pkt
)
341 mDNSu16 numQuestions
= pkt
->msg
.h
.numQuestions
;
342 mDNSu16 numAnswers
= pkt
->msg
.h
.numAnswers
;
343 mDNSu16 numAuthorities
= pkt
->msg
.h
.numAuthorities
;
344 mDNSu16 numAdditionals
= pkt
->msg
.h
.numAdditionals
;
345 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
347 // Put all the integer values in IETF byte-order (MSB first, LSB second)
348 *ptr
++ = (mDNSu8
)(numQuestions
>> 8);
349 *ptr
++ = (mDNSu8
)(numQuestions
& 0xFF);
350 *ptr
++ = (mDNSu8
)(numAnswers
>> 8);
351 *ptr
++ = (mDNSu8
)(numAnswers
& 0xFF);
352 *ptr
++ = (mDNSu8
)(numAuthorities
>> 8);
353 *ptr
++ = (mDNSu8
)(numAuthorities
& 0xFF);
354 *ptr
++ = (mDNSu8
)(numAdditionals
>> 8);
355 *ptr
++ = (mDNSu8
)(numAdditionals
& 0xFF);
359 // Add socket to event loop
361 mDNSlocal mStatus
AddSourceToEventLoop( DaemonInfo
* self
, TCPSocket
*sock
, EventCallback callback
, void *context
)
363 EventSource
* newSource
;
364 mStatus err
= mStatus_NoError
;
366 if ( self
->eventSources
.LinkOffset
== 0 )
368 InitLinkedList( &self
->eventSources
, offsetof( EventSource
, next
));
371 newSource
= ( EventSource
*) malloc( sizeof *newSource
);
372 if ( newSource
== NULL
)
374 err
= mStatus_NoMemoryErr
;
378 newSource
->callback
= callback
;
379 newSource
->context
= context
;
380 newSource
->sock
= sock
;
381 newSource
->fd
= mDNSPlatformTCPGetFD( sock
);
383 AddToTail( &self
->eventSources
, newSource
);
391 // Remove socket from event loop
393 mDNSlocal mStatus
RemoveSourceFromEventLoop( DaemonInfo
* self
, TCPSocket
*sock
)
395 EventSource
* source
;
398 for ( source
= ( EventSource
* ) self
->eventSources
.Head
; source
; source
= source
->next
)
400 if ( source
->sock
== sock
)
402 RemoveFromList( &self
->eventSources
, source
);
405 err
= mStatus_NoError
;
410 err
= mStatus_NoSuchNameErr
;
417 // create a socket connected to nameserver
418 // caller terminates connection via close()
419 mDNSlocal TCPSocket
*ConnectToServer(DaemonInfo
*d
)
421 int ntries
= 0, retry
= 0;
425 mDNSIPPort port
= zeroIPPort
;
428 TCPSocket
*sock
= mDNSPlatformTCPSocket( NULL
, 0, &port
);
429 if ( !sock
) { LogErr("ConnectToServer", "socket"); return NULL
; }
430 fd
= mDNSPlatformTCPGetFD( sock
);
431 if (!connect( fd
, (struct sockaddr
*)&d
->ns_addr
, sizeof(d
->ns_addr
))) return sock
;
432 mDNSPlatformTCPCloseConnection( sock
);
435 LogErr("ConnectToServer", "connect");
436 Log("ConnectToServer - retrying connection");
437 if (!retry
) retry
= 500000 + random() % 500000;
441 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries
); return NULL
; }
445 // send an entire block of data over a connected socket
446 mDNSlocal
int MySend(TCPSocket
*sock
, const void *msg
, int len
)
448 int selectval
, n
, nsent
= 0;
450 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
458 fd
= mDNSPlatformTCPGetFD( sock
);
461 selectval
= select( fd
+1, NULL
, &wset
, NULL
, &timeout
);
462 if (selectval
< 0) { LogErr("MySend", "select"); return -1; }
463 if (!selectval
|| !FD_ISSET(fd
, &wset
)) { Log("MySend - timeout"); return -1; }
465 n
= mDNSPlatformWriteTCP( sock
, ( char* ) msg
+ nsent
, len
- nsent
);
467 if (n
< 0) { LogErr("MySend", "send"); return -1; }
473 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
474 mDNSlocal
int SendPacket(TCPSocket
*sock
, PktMsg
*pkt
)
476 // send the lenth, in network byte order
477 mDNSu16 len
= htons((mDNSu16
)pkt
->len
);
478 if (MySend(sock
, &len
, sizeof(len
)) < 0) return -1;
481 VLog("SendPacket Q:%d A:%d A:%d A:%d ",
482 ntohs(pkt
->msg
.h
.numQuestions
),
483 ntohs(pkt
->msg
.h
.numAnswers
),
484 ntohs(pkt
->msg
.h
.numAuthorities
),
485 ntohs(pkt
->msg
.h
.numAdditionals
));
486 return MySend(sock
, &pkt
->msg
, pkt
->len
);
489 // Receive len bytes, waiting until we have all of them.
490 // Returns number of bytes read (which should always be the number asked for).
491 static int my_recv(TCPSocket
*sock
, void *const buf
, const int len
, mDNSBool
* closed
)
493 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
494 // use an explicit while() loop instead.
495 // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
496 // arithmetic on "void *" pointers is compiler-dependent.
499 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
500 int selectval
, remaining
= len
;
501 char *ptr
= (char *)buf
;
508 fd
= mDNSPlatformTCPGetFD( sock
);
512 selectval
= select(fd
+1, &rset
, NULL
, NULL
, &timeout
);
513 if (selectval
< 0) { LogErr("my_recv", "select"); return -1; }
514 if (!selectval
|| !FD_ISSET(fd
, &rset
))
516 Log("my_recv - timeout");
520 num_read
= mDNSPlatformReadTCP( sock
, ptr
, remaining
, closed
);
522 if (((num_read
== 0) && *closed
) || (num_read
< 0) || (num_read
> remaining
)) return -1;
523 if (num_read
== 0) return 0;
525 remaining
-= num_read
;
530 // Return a DNS Message read off of a TCP socket, or NULL on failure
531 // If storage is non-null, result is placed in that buffer. Otherwise,
532 // returned value is allocated with Malloc, and contains sufficient extra
533 // storage for a Lease OPT RR
551 fd
= mDNSPlatformTCPGetFD( sock
);
553 nread
= my_recv( sock
, &msglen
, sizeof( msglen
), closed
);
555 require_action_quiet( nread
!= -1, exit
, err
= mStatus_UnknownErr
);
556 require_action_quiet( nread
> 0, exit
, err
= mStatus_NoError
);
558 msglen
= ntohs( msglen
);
559 require_action_quiet( nread
== sizeof( msglen
), exit
, err
= mStatus_UnknownErr
; Log( "Could not read length field of message") );
563 require_action_quiet( msglen
<= sizeof( storage
->msg
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: provided buffer too small." ) );
568 // buffer extra space to add an OPT RR
570 if ( msglen
> sizeof(DNSMessage
))
572 allocsize
= sizeof(PktMsg
) - sizeof(DNSMessage
) + msglen
;
576 allocsize
= sizeof(PktMsg
);
579 pkt
= malloc(allocsize
);
580 require_action_quiet( pkt
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvPacket", "malloc" ) );
581 bzero( pkt
, sizeof( *pkt
) );
585 srclen
= sizeof(pkt
->src
);
587 if ( getpeername( fd
, ( struct sockaddr
* ) &pkt
->src
, &srclen
) || ( srclen
!= sizeof( pkt
->src
) ) )
589 LogErr("RecvPacket", "getpeername");
590 bzero(&pkt
->src
, sizeof(pkt
->src
));
593 nread
= my_recv(sock
, &pkt
->msg
, msglen
, closed
);
594 require_action_quiet( nread
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvPacket", "recv" ) );
595 require_action_quiet( nread
== msglen
, exit
, err
= mStatus_UnknownErr
; Log( "Could not read entire message" ) );
596 require_action_quiet( pkt
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: Message too short (%d bytes)", pkt
->len
) );
602 if ( pkt
!= storage
)
623 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
625 if ( SameDomainName( &zone
->name
, name
) )
638 const domainname
* zname
,
639 const domainname
* dname
642 mDNSu16 i
= DomainNameLength( zname
);
643 mDNSu16 j
= DomainNameLength( dname
);
645 if ( ( i
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( j
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( i
> j
) || ( memcmp( zname
->c
, dname
->c
+ ( j
- i
), i
) != 0 ) )
654 mDNSlocal mDNSBool
IsQuery( PktMsg
* pkt
)
656 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
);
660 mDNSlocal mDNSBool
IsUpdate( PktMsg
* pkt
)
662 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_OP_Update
);
666 mDNSlocal mDNSBool
IsNotify(PktMsg
*pkt
)
668 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( mDNSu8
) ( kDNSFlag0_OP_Notify
);
672 mDNSlocal mDNSBool
IsLLQRequest(PktMsg
*pkt
)
674 const mDNSu8
*ptr
= NULL
, *end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
675 LargeCacheRecord lcr
;
677 mDNSBool result
= mDNSfalse
;
680 if ((mDNSu8
)(pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (mDNSu8
)(kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
)) goto end
;
682 if (!pkt
->msg
.h
.numAdditionals
) goto end
;
683 ptr
= LocateAdditionals(&pkt
->msg
, end
);
686 // find last Additional info.
687 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
689 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
690 if (!ptr
) { Log("Unable to read additional record"); goto end
; }
693 if ( lcr
.r
.resrec
.rrtype
== kDNSType_OPT
&& lcr
.r
.resrec
.rdlength
>= LLQ_OPT_RDLEN
&& lcr
.r
.resrec
.rdata
->u
.opt
.opt
== kDNSOpt_LLQ
)
703 // !!!KRS implement properly
704 mDNSlocal mDNSBool
IsLLQAck(PktMsg
*pkt
)
706 if ((pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
) &&
707 pkt
->msg
.h
.numQuestions
&& !pkt
->msg
.h
.numAnswers
&& !pkt
->msg
.h
.numAuthorities
) return mDNStrue
;
719 DNameListElem
* elem
;
720 mDNSBool ret
= mDNSfalse
;
721 int i
= ( int ) DomainNameLength( &q
->qname
) - 1;
723 for ( elem
= self
->public_names
; elem
; elem
= elem
->next
)
725 int j
= ( int ) DomainNameLength( &elem
->name
) - 1;
729 for ( ; i
>= 0; i
--, j
-- )
731 if ( q
->qname
.c
[ i
] != elem
->name
.c
[ j
] )
755 const mDNSu8
* ptr
= pkt
->msg
.data
;
756 mDNSBool exception
= mDNSfalse
;
761 pkt
->isZonePublic
= mDNStrue
;
764 // Figure out what type of packet this is
766 QR_OP
= ( mDNSu8
) ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
768 if ( IsQuery( pkt
) )
770 DNSQuestion question
;
774 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
776 AppendDomainName( &zname
, &question
.qname
);
778 exception
= ( ( question
.qtype
== kDNSType_SOA
) || ( question
.qtype
== kDNSType_NS
) || ( ( question
.qtype
== kDNSType_SRV
) && IsPublicSRV( self
, &question
) ) );
780 else if ( IsUpdate( pkt
) )
782 DNSQuestion question
;
784 // It's an update. The format of the zone section is the same as the format for the question section
785 // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
787 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
789 AppendDomainName( &zname
, &question
.qname
);
791 exception
= mDNSfalse
;
794 if ( zname
.c
[0] != '\0' )
796 // Find the right zone
798 for ( pkt
->zone
= self
->zones
; pkt
->zone
; pkt
->zone
= pkt
->zone
->next
)
800 if ( ZoneHandlesName( &pkt
->zone
->name
, &zname
) )
802 VLog( "found correct zone %##s for query", pkt
->zone
->name
.c
);
804 pkt
->isZonePublic
= ( ( pkt
->zone
->type
== kDNSZonePublic
) || exception
);
806 VLog( "zone %##s is %s", pkt
->zone
->name
.c
, ( pkt
->isZonePublic
) ? "public" : "private" );
816 UDPServerTransaction(const DaemonInfo
*d
, const PktMsg
*request
, PktMsg
*reply
, mDNSBool
*trunc
)
819 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
822 mStatus err
= mStatus_NoError
;
830 sd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
831 require_action( sd
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "socket" ) );
833 // Send the packet to the nameserver
835 VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
836 ntohs(request
->msg
.h
.numQuestions
),
837 ntohs(request
->msg
.h
.numAnswers
),
838 ntohs(request
->msg
.h
.numAuthorities
),
839 ntohs(request
->msg
.h
.numAdditionals
));
840 res
= sendto( sd
, (char *)&request
->msg
, request
->len
, 0, ( struct sockaddr
* ) &d
->ns_addr
, sizeof( d
->ns_addr
) );
841 require_action( res
== (int) request
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "sendto" ) );
847 res
= select( sd
+ 1, &rset
, NULL
, NULL
, &timeout
);
848 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "select" ) );
849 require_action( ( res
> 0 ) && FD_ISSET( sd
, &rset
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - timeout" ) );
853 reply
->len
= recvfrom( sd
, &reply
->msg
, sizeof(reply
->msg
), 0, NULL
, NULL
);
854 require_action( ( ( int ) reply
->len
) >= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "recvfrom" ) );
855 require_action( reply
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - Message too short (%d bytes)", reply
->len
) );
857 // Check for truncation bit
859 if ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_TC
)
875 // Dynamic Update Utility Routines
878 // check if a request and server response complete a successful dynamic update
879 mDNSlocal mDNSBool
SuccessfulUpdateTransaction(PktMsg
*request
, PktMsg
*reply
)
882 char *vlogmsg
= NULL
;
885 if (!request
|| !reply
) { vlogmsg
= "NULL message"; goto failure
; }
886 if (request
->len
< sizeof(DNSMessageHeader
) || reply
->len
< sizeof(DNSMessageHeader
)) { vlogmsg
= "Malformatted message"; goto failure
; }
888 // check request operation
889 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
))
890 { vlogmsg
= "Request opcode not an update"; goto failure
; }
893 if ((reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)) { vlogmsg
= "Reply contains non-zero rcode"; goto failure
; }
894 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
))
895 { vlogmsg
= "Reply opcode not an update response"; goto failure
; }
897 VLog("Successful update from %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32));
901 VLog("Request %s: %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32), vlogmsg
);
905 // Allocate an appropriately sized CacheRecord and copy data from original.
906 // Name pointer in CacheRecord object is set to point to the name specified
908 mDNSlocal CacheRecord
*CopyCacheRecord(const CacheRecord
*orig
, domainname
*name
)
911 size_t size
= sizeof(*cr
);
912 if (orig
->resrec
.rdlength
> InlineCacheRDSize
) size
+= orig
->resrec
.rdlength
- InlineCacheRDSize
;
914 if (!cr
) { LogErr("CopyCacheRecord", "malloc"); return NULL
; }
915 memcpy(cr
, orig
, size
);
916 cr
->resrec
.rdata
= (RData
*)&cr
->rdatastorage
;
917 cr
->resrec
.name
= name
;
924 // Lease Hashtable Utility Routines
927 // double hash table size
928 // caller must lock table prior to invocation
929 mDNSlocal
void RehashTable(DaemonInfo
*d
)
931 RRTableElem
*ptr
, *tmp
, **new;
932 int i
, bucket
, newnbuckets
= d
->nbuckets
* 2;
934 VLog("Rehashing lease table (new size %d buckets)", newnbuckets
);
935 new = malloc(sizeof(RRTableElem
*) * newnbuckets
);
936 if (!new) { LogErr("RehashTable", "malloc"); return; }
937 bzero(new, newnbuckets
* sizeof(RRTableElem
*));
939 for (i
= 0; i
< d
->nbuckets
; i
++)
944 bucket
= ptr
->rr
.resrec
.namehash
% newnbuckets
;
947 tmp
->next
= new[bucket
];
951 d
->nbuckets
= newnbuckets
;
956 // print entire contents of hashtable, invoked via SIGINFO
957 mDNSlocal
void PrintLeaseTable(DaemonInfo
*d
)
961 char rrbuf
[MaxMsg
], addrbuf
[16];
965 if (gettimeofday(&now
, NULL
)) { LogErr("PrintTable", "gettimeofday"); return; }
966 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
968 Log("Dumping Lease Table Contents (table contains %d resource records)", d
->nelems
);
969 for (i
= 0; i
< d
->nbuckets
; i
++)
971 for (ptr
= d
->table
[i
]; ptr
; ptr
= ptr
->next
)
973 hr
= ((ptr
->expire
- now
.tv_sec
) / 60) / 60;
974 min
= ((ptr
->expire
- now
.tv_sec
) / 60) % 60;
975 sec
= (ptr
->expire
- now
.tv_sec
) % 60;
976 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
,
977 GetRRDisplayString_rdb(&ptr
->rr
.resrec
, &ptr
->rr
.resrec
.rdata
->u
, rrbuf
));
980 pthread_mutex_unlock(&d
->tablelock
);
984 // Startup SRV Registration Routines
985 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
986 // the daemon accepts requests
989 // delete all RRS of a given name/type
990 mDNSlocal mDNSu8
*putRRSetDeletion(DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
, ResourceRecord
*rr
)
992 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
993 if (!ptr
|| ptr
+ 10 >= limit
) return NULL
; // out of space
994 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
995 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
996 ptr
[2] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
>> 8);
997 ptr
[3] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
& 0xFF);
998 bzero(ptr
+4, sizeof(rr
->rroriginalttl
) + sizeof(rr
->rdlength
)); // zero ttl/rdata
999 msg
->h
.mDNS_numUpdates
++;
1003 mDNSlocal mDNSu8
*PutUpdateSRV(DaemonInfo
*d
, DNSZone
* zone
, PktMsg
*pkt
, mDNSu8
*ptr
, char *regtype
, mDNSIPPort port
, mDNSBool registration
)
1006 char hostname
[1024], buf
[MaxMsg
];
1007 mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ sizeof(DNSMessage
);
1011 mDNS_SetupResourceRecord(&rr
, NULL
, 0, kDNSType_SRV
, SRV_TTL
, kDNSRecordTypeUnique
, NULL
, NULL
);
1012 rr
.resrec
.rrclass
= kDNSClass_IN
;
1013 rr
.resrec
.rdata
->u
.srv
.priority
= 0;
1014 rr
.resrec
.rdata
->u
.srv
.weight
= 0;
1015 rr
.resrec
.rdata
->u
.srv
.port
= port
;
1016 if (gethostname(hostname
, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr
.resrec
.rdata
->u
.srv
.target
, hostname
))
1017 rr
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0';
1019 MakeDomainNameFromDNSNameString(&rr
.namestorage
, regtype
);
1020 AppendDomainName(&rr
.namestorage
, &zone
->name
);
1021 VLog("%s %s", registration
? "Registering SRV record" : "Deleting existing RRSet",
1022 GetRRDisplayString_rdb(&rr
.resrec
, &rr
.resrec
.rdata
->u
, buf
));
1023 if (registration
) ptr
= PutResourceRecord(&pkt
->msg
, ptr
, &pkt
->msg
.h
.mDNS_numUpdates
, &rr
.resrec
);
1024 else ptr
= putRRSetDeletion(&pkt
->msg
, ptr
, end
, &rr
.resrec
);
1029 // perform dynamic update.
1030 // specify deletion by passing false for the register parameter, otherwise register the records.
1031 mDNSlocal
int UpdateSRV(DaemonInfo
*d
, mDNSBool registration
)
1033 TCPSocket
*sock
= NULL
;
1035 int err
= mStatus_NoError
;
1037 sock
= ConnectToServer( d
);
1038 require_action( sock
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: ConnectToServer failed" ) );
1040 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1043 mDNSu8
*ptr
= pkt
.msg
.data
;
1044 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1045 PktMsg
*reply
= NULL
;
1049 // Initialize message
1050 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1051 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1052 pkt
.src
.sin_family
= AF_INET
;
1054 // format message body
1055 ptr
= putZone(&pkt
.msg
, ptr
, end
, &zone
->name
, mDNSOpaque16fromIntVal(kDNSClass_IN
));
1056 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1058 if ( zone
->type
== kDNSZonePrivate
)
1060 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls._tcp.", d
->private_port
, registration
);
1061 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1062 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls._tcp.", d
->private_port
, registration
);
1063 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1064 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls._tcp.", d
->private_port
, registration
);
1065 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1067 if ( !registration
)
1069 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
1070 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1071 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
1072 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-tls.", d
->private_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-query-tls.", d
->private_port
, registration
);
1082 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1083 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls.", d
->private_port
, registration
);
1084 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1087 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
1088 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1089 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
1090 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
1095 if ( zone
->updateKeys
)
1097 ptr
= DNSDigest_SignMessage( &pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1098 require_action( ptr
, exit
, Log("UpdateSRV: Error constructing lease expiration update" ) );
1101 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1103 // send message, receive reply
1105 err
= SendPacket( sock
, &pkt
);
1106 require_action( !err
, exit
, Log( "UpdateSRV: SendPacket failed" ) );
1108 reply
= RecvPacket( sock
, NULL
, &closed
);
1109 require_action( reply
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: RecvPacket returned NULL" ) );
1111 ok
= SuccessfulUpdateTransaction( &pkt
, reply
);
1115 Log("SRV record registration failed with rcode %d", reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1125 mDNSPlatformTCPCloseConnection( sock
);
1131 // wrapper routines/macros
1132 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1134 // clear any existing records prior to registration
1135 mDNSlocal
int SetUpdateSRV(DaemonInfo
*d
)
1139 err
= ClearUpdateSRV(d
); // clear any existing record
1140 if (!err
) err
= UpdateSRV(d
, 1);
1145 // Argument Parsing and Configuration
1148 mDNSlocal
void PrintUsage(void)
1150 fprintf(stderr
, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1151 "Use \"dnsextd -h\" for help\n");
1154 mDNSlocal
void PrintHelp(void)
1156 fprintf(stderr
, "\n\n");
1160 "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
1161 "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
1162 "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
1163 "Discovery, Update Leases, and Long Lived Queries.)\n\n"
1165 "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
1166 "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
1167 "primary master server for this zone.\n\n"
1169 "The options are as follows:\n\n"
1171 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1173 "-d Run daemon in foreground.\n\n"
1175 "-h Print help.\n\n"
1177 "-v Verbose output.\n\n"
1182 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
1183 // returns 0 (success) if program is to continue execution
1184 // output control arguments (-f, -v) do not affect this routine
1185 mDNSlocal
int ProcessArgs(int argc
, char *argv
[], DaemonInfo
*d
)
1191 cfgfile
= strdup( CONFIG_FILE
);
1192 require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
);
1194 // defaults, may be overriden by command option
1196 // setup our sockaddr
1198 bzero( &d
->addr
, sizeof( d
->addr
) );
1199 d
->addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1200 d
->addr
.sin_port
= UnicastDNSPort
.NotAnInteger
;
1201 d
->addr
.sin_family
= AF_INET
;
1202 #ifndef NOT_HAVE_SA_LEN
1203 d
->addr
.sin_len
= sizeof( d
->addr
);
1206 // setup nameserver's sockaddr
1208 bzero(&d
->ns_addr
, sizeof(d
->ns_addr
));
1209 d
->ns_addr
.sin_family
= AF_INET
;
1210 inet_pton( AF_INET
, LOOPBACK
, &d
->ns_addr
.sin_addr
);
1211 d
->ns_addr
.sin_port
= NSIPCPort
.NotAnInteger
;
1212 #ifndef NOT_HAVE_SA_LEN
1213 d
->ns_addr
.sin_len
= sizeof( d
->ns_addr
);
1218 d
->private_port
= PrivateDNSPort
;
1219 d
->llq_port
= DNSEXTPort
;
1221 while ((opt
= getopt(argc
, argv
, "f:hdv")) != -1)
1225 case 'f': free( cfgfile
); cfgfile
= strdup( optarg
); require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
); break;
1226 case 'h': PrintHelp(); return -1;
1227 case 'd': foreground
= 1; break; // Also used when launched via OS X's launchd mechanism
1228 case 'v': verbose
= 1; break;
1229 default: goto arg_error
;
1233 err
= ParseConfig( d
, cfgfile
);
1234 require_noerr( err
, arg_error
);
1236 // Make sure we've specified some zones
1238 require_action( d
->zones
, arg_error
, err
= mStatus_UnknownErr
);
1240 // if we have a shared secret, use it for the entire zone
1242 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1244 if ( zone
->updateKeys
)
1246 AssignDomainName( &zone
->updateKeys
->domain
, &zone
->name
);
1260 // Initialization Routines
1263 // Allocate memory, initialize locks and bookkeeping variables
1264 mDNSlocal
int InitLeaseTable(DaemonInfo
*d
)
1266 if (pthread_mutex_init(&d
->tablelock
, NULL
)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1267 d
->nbuckets
= LEASETABLE_INIT_NBUCKETS
;
1269 d
->table
= malloc(sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1270 if (!d
->table
) { LogErr("InitLeaseTable", "malloc"); return -1; }
1271 bzero(d
->table
, sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1282 static const int kOn
= 1;
1284 mDNSBool
private = mDNSfalse
;
1285 struct sockaddr_in daddr
;
1289 // set up sockets on which we all ns requests
1291 self
->tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1292 require_action( dnssd_SocketValid(self
->tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1294 #if defined(SO_REUSEADDR)
1295 err
= setsockopt(self
->tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1296 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
1299 err
= bind( self
->tcpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1300 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1302 err
= listen( self
->tcpsd
, LISTENQ
);
1303 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1305 self
->udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1306 require_action( dnssd_SocketValid(self
->udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1308 #if defined(SO_REUSEADDR)
1309 err
= setsockopt(self
->udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1310 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
1313 err
= bind( self
->udpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1314 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->udpsd" ) );
1316 // set up sockets on which we receive llq requests
1318 bzero(&self
->llq_addr
, sizeof(self
->llq_addr
));
1319 self
->llq_addr
.sin_family
= AF_INET
;
1320 self
->llq_addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1321 self
->llq_addr
.sin_port
= ( self
->llq_port
.NotAnInteger
) ? self
->llq_port
.NotAnInteger
: DNSEXTPort
.NotAnInteger
;
1323 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1324 require_action( dnssd_SocketValid(self
->llq_tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1326 #if defined(SO_REUSEADDR)
1327 err
= setsockopt(self
->llq_tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1328 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
1331 err
= bind( self
->llq_tcpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1332 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
1334 err
= listen( self
->llq_tcpsd
, LISTENQ
);
1335 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1337 self
->llq_udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1338 require_action( dnssd_SocketValid(self
->llq_udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1340 #if defined(SO_REUSEADDR)
1341 err
= setsockopt(self
->llq_udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1342 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
1345 err
= bind(self
->llq_udpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1346 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
1348 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1350 err
= socketpair( AF_LOCAL
, SOCK_STREAM
, 0, sockpair
);
1351 require_action( !err
, exit
, LogErr( "SetupSockets", "socketpair" ) );
1353 self
->LLQEventListenSock
= sockpair
[0];
1354 self
->LLQEventNotifySock
= sockpair
[1];
1356 // set up socket on which we receive private requests
1358 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1359 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1360 bzero(&daddr
, sizeof(daddr
));
1361 daddr
.sin_family
= AF_INET
;
1362 daddr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1363 daddr
.sin_port
= ( self
->private_port
.NotAnInteger
) ? self
->private_port
.NotAnInteger
: PrivateDNSPort
.NotAnInteger
;
1365 self
->tlssd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1366 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1368 #if defined(SO_REUSEADDR)
1369 err
= setsockopt(self
->tlssd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1370 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
1373 err
= bind( self
->tlssd
, ( struct sockaddr
* ) &daddr
, sizeof( daddr
) );
1374 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tlssd" ) );
1376 err
= listen( self
->tlssd
, LISTENQ
);
1377 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1379 // Do we have any private zones?
1381 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
1383 if ( zone
->type
== kDNSZonePrivate
)
1392 err
= mDNSPlatformTLSSetupCerts();
1393 require_action( !err
, exit
, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1402 // periodic table updates
1405 // Delete a resource record from the nameserver via a dynamic update
1406 // sd is a socket already connected to the server
1407 mDNSlocal
void DeleteOneRecord(DaemonInfo
*d
, CacheRecord
*rr
, domainname
*zname
, TCPSocket
*sock
)
1411 mDNSu8
*ptr
= pkt
.msg
.data
;
1412 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1415 PktMsg
*reply
= NULL
;
1417 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, buf
));
1419 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1421 ptr
= putZone(&pkt
.msg
, ptr
, end
, zname
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
1423 ptr
= putDeletionRecord(&pkt
.msg
, ptr
, &rr
->resrec
);
1428 zone
= FindZone( d
, zname
);
1430 if ( zone
&& zone
->updateKeys
)
1432 ptr
= DNSDigest_SignMessage(&pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1436 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1437 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1438 pkt
.src
.sin_family
= AF_INET
;
1439 if (SendPacket( sock
, &pkt
)) { Log("DeleteOneRecord: SendPacket failed"); }
1440 reply
= RecvPacket( sock
, NULL
, &closed
);
1441 if (reply
) HdrNToH(reply
);
1442 require_action( reply
, end
, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
1444 if (!SuccessfulUpdateTransaction(&pkt
, reply
))
1445 Log("Expiration update failed with rcode %d", reply
? reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
: -1);
1448 if (!ptr
) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1449 if (reply
) free(reply
);
1452 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1453 mDNSlocal
void DeleteRecords(DaemonInfo
*d
, mDNSBool DeleteAll
)
1457 TCPSocket
*sock
= ConnectToServer(d
);
1458 if (!sock
) { Log("DeleteRecords: ConnectToServer failed"); return; }
1459 if (gettimeofday(&now
, NULL
)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
1460 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
1462 for (i
= 0; i
< d
->nbuckets
; i
++)
1464 RRTableElem
**ptr
= &d
->table
[i
];
1467 if (DeleteAll
|| (*ptr
)->expire
- now
.tv_sec
< 0)
1470 // delete record from server
1471 DeleteOneRecord(d
, &(*ptr
)->rr
, &(*ptr
)->zone
, sock
);
1473 *ptr
= (*ptr
)->next
;
1477 else ptr
= &(*ptr
)->next
;
1480 pthread_mutex_unlock(&d
->tablelock
);
1481 mDNSPlatformTCPCloseConnection( sock
);
1485 // main update request handling
1488 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
1489 mDNSlocal
void UpdateLeaseTable(PktMsg
*pkt
, DaemonInfo
*d
, mDNSs32 lease
)
1491 RRTableElem
**rptr
, *tmp
;
1492 int i
, allocsize
, bucket
;
1493 LargeCacheRecord lcr
;
1494 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1495 const mDNSu8
*ptr
, *end
;
1496 struct timeval time
;
1500 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
1502 ptr
= pkt
->msg
.data
;
1503 end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
1504 ptr
= getQuestion(&pkt
->msg
, ptr
, end
, 0, &zone
);
1505 if (!ptr
) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup
; }
1506 ptr
= LocateAuthorities(&pkt
->msg
, end
);
1507 if (!ptr
) { Log("UpdateLeaseTable: Format error"); goto cleanup
; }
1509 for (i
= 0; i
< pkt
->msg
.h
.mDNS_numUpdates
; i
++)
1511 mDNSBool DeleteAllRRSets
= mDNSfalse
, DeleteOneRRSet
= mDNSfalse
, DeleteOneRR
= mDNSfalse
;
1513 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1514 if (!ptr
) { Log("UpdateLeaseTable: GetLargeResourceRecord returned NULL"); goto cleanup
; }
1515 bucket
= rr
->namehash
% d
->nbuckets
;
1516 rptr
= &d
->table
[bucket
];
1519 if (rr
->rrtype
== kDNSQType_ANY
&& !rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1520 DeleteAllRRSets
= mDNStrue
; // delete all rrsets for a name
1521 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1522 DeleteOneRRSet
= mDNStrue
;
1523 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSClass_NONE
)
1524 DeleteOneRR
= mDNStrue
;
1526 if (DeleteAllRRSets
|| DeleteOneRRSet
|| DeleteOneRR
)
1530 if (SameDomainName((*rptr
)->rr
.resrec
.name
, rr
->name
) &&
1532 (DeleteOneRRSet
&& (*rptr
)->rr
.resrec
.rrtype
== rr
->rrtype
) ||
1533 (DeleteOneRR
&& SameResourceRecord(&(*rptr
)->rr
.resrec
, rr
))))
1536 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp
->rr
.resrec
, &tmp
->rr
.resrec
.rdata
->u
, buf
));
1537 *rptr
= (*rptr
)->next
;
1541 else rptr
= &(*rptr
)->next
;
1546 // see if add or refresh
1547 while (*rptr
&& !SameResourceRecord(&(*rptr
)->rr
.resrec
, rr
)) rptr
= &(*rptr
)->next
;
1551 if (gettimeofday(&time
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1552 (*rptr
)->expire
= time
.tv_sec
+ (unsigned)lease
;
1553 VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1557 // New record - add to table
1558 if (d
->nelems
> d
->nbuckets
)
1561 bucket
= rr
->namehash
% d
->nbuckets
;
1562 rptr
= &d
->table
[bucket
];
1564 if (gettimeofday(&time
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1565 allocsize
= sizeof(RRTableElem
);
1566 if (rr
->rdlength
> InlineCacheRDSize
) allocsize
+= (rr
->rdlength
- InlineCacheRDSize
);
1567 tmp
= malloc(allocsize
);
1568 if (!tmp
) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup
; }
1569 memcpy(&tmp
->rr
, &lcr
.r
, sizeof(CacheRecord
) + rr
->rdlength
- InlineCacheRDSize
);
1570 tmp
->rr
.resrec
.rdata
= (RData
*)&tmp
->rr
.rdatastorage
;
1571 AssignDomainName(&tmp
->name
, rr
->name
);
1572 tmp
->rr
.resrec
.name
= &tmp
->name
;
1573 tmp
->expire
= time
.tv_sec
+ (unsigned)lease
;
1574 tmp
->cli
.sin_addr
= pkt
->src
.sin_addr
;
1575 AssignDomainName(&tmp
->zone
, &zone
.qname
);
1576 tmp
->next
= d
->table
[bucket
];
1577 d
->table
[bucket
] = tmp
;
1579 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1585 pthread_mutex_unlock(&d
->tablelock
);
1589 // Given a successful reply from a server, create a new reply that contains lease information
1590 // Replies are currently not signed !!!KRS change this
1591 mDNSlocal PktMsg
*FormatLeaseReply(DaemonInfo
*d
, PktMsg
*orig
, mDNSu32 lease
)
1598 reply
= malloc(sizeof(*reply
));
1599 if (!reply
) { LogErr("FormatLeaseReply", "malloc"); return NULL
; }
1600 flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
1603 InitializeDNSMessage(&reply
->msg
.h
, orig
->msg
.h
.id
, flags
);
1604 reply
->src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // unused except for log messages
1605 reply
->src
.sin_family
= AF_INET
;
1606 ptr
= reply
->msg
.data
;
1607 end
= (mDNSu8
*)&reply
->msg
+ sizeof(DNSMessage
);
1608 ptr
= putUpdateLease(&reply
->msg
, ptr
, lease
);
1609 if (!ptr
) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply
); return NULL
; }
1610 reply
->len
= ptr
- (mDNSu8
*)&reply
->msg
;
1616 // pkt is thread-local, not requiring locking
1625 PktMsg
* reply
= NULL
;
1626 PktMsg
* leaseReply
;
1629 TCPSocket
* sock
= NULL
;
1632 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == kDNSFlag0_OP_Update
)
1634 int i
, adds
= 0, dels
= 0;
1635 const mDNSu8
*ptr
, *end
= (mDNSu8
*)&request
->msg
+ request
->len
;
1637 lease
= GetPktLease(&mDNSStorage
, &request
->msg
, end
);
1638 ptr
= LocateAuthorities(&request
->msg
, end
);
1639 for (i
= 0; i
< request
->msg
.h
.mDNS_numUpdates
; i
++)
1641 LargeCacheRecord lcr
;
1642 ptr
= GetLargeResourceRecord(NULL
, &request
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1643 if (lcr
.r
.resrec
.rroriginalttl
) adds
++; else dels
++;
1648 static const mDNSOpaque16 UpdateRefused
= { { kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
, kDNSFlag1_RC_Refused
} };
1649 Log("Rejecting Update Request with %d additions but no lease", adds
);
1650 reply
= malloc(sizeof(*reply
));
1651 bzero(&reply
->src
, sizeof(reply
->src
));
1652 reply
->len
= sizeof(DNSMessageHeader
);
1654 reply
->isZonePublic
= 0;
1655 InitializeDNSMessage(&reply
->msg
.h
, request
->msg
.h
.id
, UpdateRefused
);
1658 if (lease
> 1200) // Don't allow lease greater than 20 minutes
1661 // Send msg to server, read reply
1663 if ( request
->len
<= 512 )
1667 if ( UDPServerTransaction( self
, request
, &buf
, &trunc
) < 0 )
1669 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1673 VLog("HandleRequest - answer truncated. Using TCP");
1677 reply
= &buf
; // success
1686 sock
= ConnectToServer( self
);
1687 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 ) ) );
1689 res
= SendPacket( sock
, request
);
1690 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 ) ) );
1692 reply
= RecvPacket( sock
, &buf
, &closed
);
1695 // IMPORTANT: reply is in network byte order at this point in the code
1696 // We keep it this way because we send it back to the client in the same form
1700 if ( reply
&& ( ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
) ) )
1703 mDNSBool ok
= SuccessfulUpdateTransaction( request
, reply
);
1704 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 ) ) );
1706 UpdateLeaseTable( request
, self
, lease
);
1710 leaseReply
= FormatLeaseReply( self
, reply
, lease
);
1714 Log("HandleRequest - unable to format lease reply");
1717 // %%% Looks like a potential memory leak -- who frees the original reply?
1721 // tell the main thread there was an update so it can send LLQs
1723 if ( send( self
->LLQEventNotifySock
, pingmsg
, sizeof( pingmsg
), 0 ) != sizeof( pingmsg
) )
1725 LogErr("HandleRequest", "send");
1733 mDNSPlatformTCPCloseConnection( sock
);
1736 if ( reply
== &buf
)
1738 reply
= malloc( sizeof( *reply
) );
1742 reply
->len
= buf
.len
;
1743 memcpy(&reply
->msg
, &buf
.msg
, buf
.len
);
1747 LogErr("HandleRequest", "malloc");
1756 // LLQ Support Routines
1759 // Set fields of an LLQ OPT Resource Record
1760 mDNSlocal
void FormatLLQOpt(AuthRecord
*opt
, int opcode
, const mDNSOpaque64
*const id
, mDNSs32 lease
)
1762 bzero(opt
, sizeof(*opt
));
1763 mDNS_SetupResourceRecord(opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, mDNSNULL
, mDNSNULL
);
1764 opt
->resrec
.rrclass
= NormalMaxDNSMessageData
;
1765 opt
->resrec
.rdlength
= LLQ_OPT_RDLEN
;
1766 opt
->resrec
.rdestimate
= LLQ_OPT_RDLEN
;
1767 opt
->resrec
.rdata
->u
.opt
.opt
= kDNSOpt_LLQ
;
1768 opt
->resrec
.rdata
->u
.opt
.optlen
= sizeof(LLQOptData
);
1769 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.vers
= kLLQ_Vers
;
1770 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.llqOp
= opcode
;
1771 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.err
= LLQErr_NoError
;
1772 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.id
= *id
;
1773 opt
->resrec
.rdata
->u
.opt
.OptData
.llq
.llqlease
= lease
;
1776 // Calculate effective remaining lease of an LLQ
1777 mDNSlocal mDNSu32
LLQLease(LLQEntry
*e
)
1781 gettimeofday(&t
, NULL
);
1782 if (e
->expire
< t
.tv_sec
) return 0;
1783 else return e
->expire
- t
.tv_sec
;
1786 mDNSlocal
void DeleteLLQ(DaemonInfo
*d
, LLQEntry
*e
)
1788 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
1789 LLQEntry
**ptr
= &d
->LLQTable
[bucket
];
1790 AnswerListElem
*a
= e
->AnswerList
;
1793 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1794 VLog("Deleting LLQ table entry for %##s client %s", e
->qname
.c
, addr
);
1796 if (a
&& !(--a
->refcount
) && d
->AnswerTableCount
>= LLQ_TABLESIZE
)
1798 // currently, generating initial answers blocks the main thread, so we keep the answer list
1799 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1800 // if the ref count drops to zero AND there are more table elements than buckets
1801 // !!!KRS update this when we make the table dynamically growable
1803 CacheRecord
*cr
= a
->KnownAnswers
, *tmp
;
1804 AnswerListElem
**tbl
= &d
->AnswerTable
[bucket
];
1813 while (*tbl
&& *tbl
!= a
) tbl
= &(*tbl
)->next
;
1814 if (*tbl
) { *tbl
= (*tbl
)->next
; free(a
); d
->AnswerTableCount
--; }
1815 else Log("Error: DeleteLLQ - AnswerList not found in table");
1818 // remove LLQ from table, free memory
1819 while(*ptr
&& *ptr
!= e
) ptr
= &(*ptr
)->next
;
1820 if (!*ptr
) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1821 *ptr
= (*ptr
)->next
;
1825 mDNSlocal
int SendLLQ(DaemonInfo
*d
, PktMsg
*pkt
, struct sockaddr_in dst
, TCPSocket
*sock
)
1834 if ( SendPacket( sock
, pkt
) != 0 )
1836 LogErr("DaemonInfo", "MySend");
1837 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1842 if (sendto(d
->llq_udpsd
, &pkt
->msg
, pkt
->len
, 0, (struct sockaddr
*)&dst
, sizeof(dst
)) != (int)pkt
->len
)
1844 LogErr("DaemonInfo", "sendto");
1845 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1854 mDNSlocal CacheRecord
*AnswerQuestion(DaemonInfo
*d
, AnswerListElem
*e
)
1858 TCPSocket
*sock
= NULL
;
1859 const mDNSu8
*ansptr
;
1860 mDNSu8
*end
= q
.msg
.data
;
1861 PktMsg buf
, *reply
= NULL
;
1862 LargeCacheRecord lcr
;
1863 CacheRecord
*AnswerList
= NULL
;
1866 VLog("Querying server for %##s type %d", e
->name
.c
, e
->type
);
1868 InitializeDNSMessage(&q
.msg
.h
, zeroID
, uQueryFlags
);
1870 end
= putQuestion(&q
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->name
, e
->type
, kDNSClass_IN
);
1871 if (!end
) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end
; }
1872 q
.len
= (int)(end
- (mDNSu8
*)&q
.msg
);
1880 if (UDPServerTransaction(d
, &q
, &buf
, &trunc
) < 0)
1881 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e
->name
.c
);
1883 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e
->name
.c
); e
->UseTCP
= mDNStrue
; }
1884 else reply
= &buf
; // success
1891 sock
= ConnectToServer(d
);
1892 if (!sock
) { Log("AnswerQuestion: ConnectToServer failed"); goto end
; }
1893 if (SendPacket( sock
, &q
)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock
); goto end
; }
1894 reply
= RecvPacket( sock
, NULL
, &closed
);
1895 mDNSPlatformTCPCloseConnection( sock
);
1896 require_action( reply
, end
, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1900 if (reply
) HdrNToH(reply
);
1902 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
))
1903 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end
; }
1904 rcode
= (mDNSu8
)(reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1905 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
; }
1907 end
= (mDNSu8
*)&reply
->msg
+ reply
->len
;
1908 ansptr
= LocateAnswers(&reply
->msg
, end
);
1909 if (!ansptr
) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end
; }
1911 for (i
= 0; i
< reply
->msg
.h
.numAnswers
; i
++)
1913 ansptr
= GetLargeResourceRecord(NULL
, &reply
->msg
, ansptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1914 if (!ansptr
) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end
; }
1915 if (lcr
.r
.resrec
.rrtype
!= e
->type
|| lcr
.r
.resrec
.rrclass
!= kDNSClass_IN
|| !SameDomainName(lcr
.r
.resrec
.name
, &e
->name
))
1917 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1918 lcr
.r
.resrec
.name
->c
, lcr
.r
.resrec
.rrtype
, e
->name
.c
, e
->type
);
1922 CacheRecord
*cr
= CopyCacheRecord(&lcr
.r
, &e
->name
);
1923 if (!cr
) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end
; }
1924 cr
->next
= AnswerList
;
1930 if (reply
&& reply
!= &buf
) free(reply
);
1934 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1935 mDNSlocal
void *UpdateAnswerList(void *args
)
1937 CacheRecord
*cr
, *NewAnswers
, **na
, **ka
; // "new answer", "known answer"
1938 DaemonInfo
*d
= ((UpdateAnswerListArgs
*)args
)->d
;
1939 AnswerListElem
*a
= ((UpdateAnswerListArgs
*)args
)->a
;
1944 // get up to date answers
1945 NewAnswers
= AnswerQuestion(d
, a
);
1947 // first pass - mark all answers for deletion
1948 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1949 (*ka
)->resrec
.rroriginalttl
= (unsigned)-1; // -1 means delete
1951 // second pass - mark answers pre-existent
1952 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1954 for (na
= &NewAnswers
; *na
; na
= &(*na
)->next
)
1956 if (SameResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
))
1957 { (*ka
)->resrec
.rroriginalttl
= 0; break; } // 0 means no change
1961 // third pass - add new records to Event list
1965 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1966 if (SameResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
)) break;
1969 // answer is not in list - splice from NewAnswers list, add to Event list
1971 *na
= (*na
)->next
; // splice from list
1972 cr
->next
= a
->EventList
; // add spliced record to event list
1974 cr
->resrec
.rroriginalttl
= 1; // 1 means add
1976 else na
= &(*na
)->next
;
1979 // move all the removes from the answer list to the event list
1980 ka
= &a
->KnownAnswers
;
1983 if ((*ka
)->resrec
.rroriginalttl
== (unsigned)-1)
1987 cr
->next
= a
->EventList
;
1990 else ka
= &(*ka
)->next
;
1993 // lastly, free the remaining records (known answers) in NewAnswers list
1997 NewAnswers
= NewAnswers
->next
;
2004 mDNSlocal
void SendEvents(DaemonInfo
*d
, LLQEntry
*e
)
2008 mDNSu8
*end
= (mDNSu8
*)&response
.msg
.data
;
2010 char rrbuf
[MaxMsg
], addrbuf
[32];
2013 // Should this really be random? Do we use the msgID on the receiving end?
2014 msgID
.NotAnInteger
= random();
2015 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2016 InitializeDNSMessage(&response
.msg
.h
, msgID
, ResponseFlags
);
2017 end
= putQuestion(&response
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2018 if (!end
) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
2020 // put adds/removes in packet
2021 for (cr
= e
->AnswerList
->EventList
; cr
; cr
= cr
->next
)
2023 if (verbose
) GetRRDisplayString_rdb(&cr
->resrec
, &cr
->resrec
.rdata
->u
, rrbuf
);
2024 VLog("%s (%s): %s", addrbuf
, (mDNSs32
)cr
->resrec
.rroriginalttl
< 0 ? "Remove": "Add", rrbuf
);
2025 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAnswers
, &cr
->resrec
, cr
->resrec
.rroriginalttl
);
2026 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
2029 FormatLLQOpt(&opt
, kLLQOp_Event
, &e
->id
, LLQLease(e
));
2030 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2031 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
2033 response
.len
= (int)(end
- (mDNSu8
*)&response
.msg
);
2034 if (SendLLQ(d
, &response
, e
->cli
, NULL
) < 0) LogMsg("Error: SendEvents - SendLLQ");
2037 mDNSlocal
void PrintLLQAnswers(DaemonInfo
*d
)
2042 Log("Printing LLQ Answer Table contents");
2044 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2046 AnswerListElem
*a
= d
->AnswerTable
[i
];
2050 const CacheRecord
*rr
= a
->KnownAnswers
;
2051 while (rr
) { ancount
++; rr
= rr
->next
; }
2052 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a
, a
->name
.c
, a
->type
, a
->refcount
, ancount
);
2053 for (rr
= a
->KnownAnswers
; rr
; rr
= rr
->next
) Log("\t%s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, rrbuf
));
2059 mDNSlocal
void PrintLLQTable(DaemonInfo
*d
)
2065 Log("Printing LLQ table contents");
2067 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2076 case RequestReceived
: state
= "RequestReceived"; break;
2077 case ChallengeSent
: state
= "ChallengeSent"; break;
2078 case Established
: state
= "Established"; break;
2079 default: state
= "unknown";
2081 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2083 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
2084 addr
, state
, e
->qname
.c
, e
->qtype
, e
->lease
, LLQLease(e
), e
->AnswerList
);
2090 // Send events to clients as a result of a change in the zone
2091 mDNSlocal
void GenLLQEvents(DaemonInfo
*d
)
2096 UpdateAnswerListArgs
*args
;
2098 VLog("Generating LLQ Events");
2100 gettimeofday(&t
, NULL
);
2102 // get all answers up to date
2103 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2105 AnswerListElem
*a
= d
->AnswerTable
[i
];
2108 args
= malloc(sizeof(*args
));
2109 if (!args
) { LogErr("GenLLQEvents", "malloc"); return; }
2112 if (pthread_create(&a
->tid
, NULL
, UpdateAnswerList
, args
) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
2118 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2120 AnswerListElem
*a
= d
->AnswerTable
[i
];
2123 if (pthread_join(a
->tid
, NULL
)) LogErr("GenLLQEvents", "pthread_join");
2128 // for each established LLQ, send events
2129 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2131 e
= &d
->LLQTable
[i
];
2134 if ((*e
)->expire
< t
.tv_sec
) DeleteLLQ(d
, *e
);
2137 if ((*e
)->state
== Established
&& (*e
)->AnswerList
->EventList
) SendEvents(d
, *e
);
2143 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2144 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2146 AnswerListElem
*a
= d
->AnswerTable
[i
];
2151 CacheRecord
*cr
= a
->EventList
, *tmp
;
2156 if ((signed)tmp
->resrec
.rroriginalttl
< 0) free(tmp
);
2159 tmp
->next
= a
->KnownAnswers
;
2160 a
->KnownAnswers
= tmp
;
2161 tmp
->resrec
.rroriginalttl
= 0;
2164 a
->EventList
= NULL
;
2171 mDNSlocal
void SetAnswerList(DaemonInfo
*d
, LLQEntry
*e
)
2173 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
2174 AnswerListElem
*a
= d
->AnswerTable
[bucket
];
2175 while (a
&& (a
->type
!= e
->qtype
||!SameDomainName(&a
->name
, &e
->qname
))) a
= a
->next
;
2178 a
= malloc(sizeof(*a
));
2179 if (!a
) { LogErr("SetAnswerList", "malloc"); return; }
2180 AssignDomainName(&a
->name
, &e
->qname
);
2183 a
->EventList
= NULL
;
2184 a
->UseTCP
= mDNSfalse
;
2185 a
->next
= d
->AnswerTable
[bucket
];
2186 d
->AnswerTable
[bucket
] = a
;
2187 d
->AnswerTableCount
++;
2188 a
->KnownAnswers
= AnswerQuestion(d
, a
);
2195 // Allocate LLQ entry, insert into table
2196 mDNSlocal LLQEntry
*NewLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, mDNSu32 lease
)
2200 int bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2203 e
= malloc(sizeof(*e
));
2204 if (!e
) { LogErr("NewLLQ", "malloc"); return NULL
; }
2206 inet_ntop(AF_INET
, &cli
.sin_addr
, addr
, 32);
2207 VLog("Allocating LLQ entry for client %s question %##s type %d", addr
, qname
->c
, qtype
);
2209 // initialize structure
2211 AssignDomainName(&e
->qname
, qname
);
2213 e
->id
= zeroOpaque64
;
2214 e
->state
= RequestReceived
;
2215 e
->AnswerList
= NULL
;
2217 if (lease
< LLQ_MIN_LEASE
) lease
= LLQ_MIN_LEASE
;
2218 else if (lease
> LLQ_MAX_LEASE
) lease
= LLQ_MAX_LEASE
;
2220 gettimeofday(&t
, NULL
);
2221 e
->expire
= t
.tv_sec
+ (int)lease
;
2225 e
->next
= d
->LLQTable
[bucket
];
2226 d
->LLQTable
[bucket
] = e
;
2231 // Handle a refresh request from client
2232 mDNSlocal
void LLQRefresh(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2236 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2239 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2240 VLog("%s LLQ for %##s from %s", llq
->llqlease
? "Refreshing" : "Deleting", e
->qname
.c
, addr
);
2245 if (llq
->llqlease
< LLQ_MIN_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2246 else if (llq
->llqlease
> LLQ_MAX_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2247 gettimeofday(&t
, NULL
);
2248 e
->expire
= t
.tv_sec
+ llq
->llqlease
;
2251 ack
.src
.sin_addr
.s_addr
= 0; // unused
2252 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2253 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2254 if (!end
) { Log("Error: putQuestion"); return; }
2256 FormatLLQOpt(&opt
, kLLQOp_Refresh
, &e
->id
, llq
->llqlease
? LLQLease(e
) : 0);
2257 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2258 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2260 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2261 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQRefresh");
2263 if (llq
->llqlease
) e
->state
= Established
;
2264 else DeleteLLQ(d
, e
);
2267 // Complete handshake with Ack an initial answers
2268 mDNSlocal
void LLQCompleteHandshake(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2274 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2275 char rrbuf
[MaxMsg
], addrbuf
[32];
2277 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2279 if (!mDNSSameOpaque64(&llq
->id
, &e
->id
) ||
2280 llq
->vers
!= kLLQ_Vers
||
2281 llq
->llqOp
!= kLLQOp_Setup
||
2282 llq
->err
!= LLQErr_NoError
||
2283 llq
->llqlease
> e
->lease
+ LLQ_LEASE_FUDGE
||
2284 llq
->llqlease
< e
->lease
- LLQ_LEASE_FUDGE
)
2286 Log("Incorrect challenge response from %s", addr
);
2290 if (e
->state
== Established
) VLog("Retransmitting LLQ ack + answers for %##s", e
->qname
.c
);
2291 else VLog("Delivering LLQ ack + answers for %##s", e
->qname
.c
);
2293 // format ack + answers
2294 ack
.src
.sin_addr
.s_addr
= 0; // unused
2295 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2296 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2297 if (!end
) { Log("Error: putQuestion"); return; }
2299 if (e
->state
!= Established
) { SetAnswerList(d
, e
); e
->state
= Established
; }
2301 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2302 for (ptr
= e
->AnswerList
->KnownAnswers
; ptr
; ptr
= ptr
->next
)
2304 if (verbose
) GetRRDisplayString_rdb(&ptr
->resrec
, &ptr
->resrec
.rdata
->u
, rrbuf
);
2305 VLog("%s Intitial Answer - %s", addr
, rrbuf
);
2306 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAnswers
, &ptr
->resrec
, 1);
2307 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2310 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2311 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2312 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2314 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2315 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQCompleteHandshake");
2318 mDNSlocal
void LLQSetupChallenge(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
)
2322 mDNSu8
*end
= challenge
.msg
.data
;
2325 if (e
->state
== ChallengeSent
) VLog("Retransmitting LLQ setup challenge for %##s", e
->qname
.c
);
2326 else VLog("Sending LLQ setup challenge for %##s", e
->qname
.c
);
2328 if (!mDNSOpaque64IsZero(&llq
->id
)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2329 if (llq
->llqOp
!= kLLQOp_Setup
) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2331 if (mDNSOpaque64IsZero(&e
->id
)) // don't regenerate random ID for retransmissions
2333 // construct ID <time><random>
2334 gettimeofday(&t
, NULL
);
2335 e
->id
.l
[0] = t
.tv_sec
;
2336 e
->id
.l
[1] = random();
2339 // format response (query + LLQ opt rr)
2340 challenge
.src
.sin_addr
.s_addr
= 0; // unused
2341 InitializeDNSMessage(&challenge
.msg
.h
, msgID
, ResponseFlags
);
2342 end
= putQuestion(&challenge
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2343 if (!end
) { Log("Error: putQuestion"); return; }
2344 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2345 end
= PutResourceRecordTTLJumbo(&challenge
.msg
, end
, &challenge
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2346 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2347 challenge
.len
= (int)(end
- (mDNSu8
*)&challenge
.msg
);
2348 if (SendLLQ(d
, &challenge
, e
->cli
, NULL
)) { Log("Error: LLQSetupChallenge"); return; }
2349 e
->state
= ChallengeSent
;
2352 // Take action on an LLQ message from client. Entry must be initialized and in table
2353 mDNSlocal
void UpdateLLQ(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2357 case RequestReceived
:
2361 gettimeofday(&t
, NULL
);
2362 e
->id
.l
[0] = t
.tv_sec
; // construct ID <time><random>
2363 e
->id
.l
[1] = random();
2365 LLQCompleteHandshake( d
, e
, llq
, msgID
, sock
);
2367 // Set the state to established because we've just set the LLQ up using TCP
2368 e
->state
= Established
;
2372 LLQSetupChallenge(d
, e
, llq
, msgID
);
2376 if (mDNSOpaque64IsZero(&llq
->id
)) LLQSetupChallenge(d
, e
, llq
, msgID
); // challenge sent and lost
2377 else LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
);
2380 if (mDNSOpaque64IsZero(&llq
->id
))
2382 // client started over. reset state.
2383 LLQEntry
*newe
= NewLLQ(d
, e
->cli
, &e
->qname
, e
->qtype
, llq
->llqlease
);
2386 LLQSetupChallenge(d
, newe
, llq
, msgID
);
2389 else if (llq
->llqOp
== kLLQOp_Setup
)
2390 { LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
); return; } // Ack lost
2391 else if (llq
->llqOp
== kLLQOp_Refresh
)
2392 { LLQRefresh(d
, e
, llq
, msgID
, sock
); return; }
2393 else { Log("Unhandled message for established LLQ"); return; }
2397 mDNSlocal LLQEntry
*LookupLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, const mDNSOpaque64
*const id
)
2399 int bucket
= bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2400 LLQEntry
*ptr
= d
->LLQTable
[bucket
];
2404 if (((ptr
->state
== ChallengeSent
&& mDNSOpaque64IsZero(id
) && (cli
.sin_port
== ptr
->cli
.sin_port
)) || // zero-id due to packet loss OK in state ChallengeSent
2405 mDNSSameOpaque64(id
, &ptr
->id
)) && // id match
2406 (cli
.sin_addr
.s_addr
== ptr
->cli
.sin_addr
.s_addr
) && (qtype
== ptr
->qtype
) && SameDomainName(&ptr
->qname
, qname
)) // same source, type, qname
2423 pkt
->msg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
2425 res
= sendto( d
->udpsd
, &pkt
->msg
, pkt
->len
, 0, ( struct sockaddr
* ) &pkt
->src
, sizeof( pkt
->src
) );
2426 require_action( res
== ( int ) pkt
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvNotify", "sendto" ) );
2434 mDNSlocal
int RecvLLQ( DaemonInfo
*d
, PktMsg
*pkt
, TCPSocket
*sock
)
2437 LargeCacheRecord opt
;
2440 const mDNSu8
*qptr
= pkt
->msg
.data
;
2441 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2443 LLQOptData
*llq
= NULL
;
2447 aptr
= LocateAdditionals(&pkt
->msg
, end
); // Can't do this until after HdrNToH(pkt);
2448 inet_ntop(AF_INET
, &pkt
->src
.sin_addr
, addr
, 32);
2450 VLog("Received LLQ msg from %s", addr
);
2451 // sanity-check packet
2452 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2454 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
2458 // Locate the OPT record.
2459 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2460 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2461 // but not necessarily the *last* entry in the Additional Section.
2462 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2464 aptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, aptr
, end
, 0, kDNSRecordTypePacketAdd
, &opt
);
2465 if (!aptr
) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr
, i
); goto end
; }
2466 if (opt
.r
.resrec
.rrtype
== kDNSType_OPT
) break;
2470 if (opt
.r
.resrec
.rrtype
!= kDNSType_OPT
) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr
); goto end
; }
2471 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
); }
2473 // dispatch each question
2474 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
2476 qptr
= getQuestion(&pkt
->msg
, qptr
, end
, 0, &q
);
2477 if (!qptr
) { Log("Malformatted LLQ from %s: cannot read question %d", addr
, i
); goto end
; }
2478 llq
= (LLQOptData
*)&opt
.r
.resrec
.rdata
->u
.opt
.OptData
.llq
+ i
; // point into OptData at index i
2479 if (llq
->vers
!= kLLQ_Vers
) { Log("LLQ from %s contains bad version %d (expected %d)", addr
, llq
->vers
, kLLQ_Vers
); goto end
; }
2481 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2484 // no entry - if zero ID, create new
2485 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2488 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2498 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
2500 const mDNSu8
* lastPtr
= NULL
;
2501 const mDNSu8
* ptr
= NULL
;
2502 DomainAuthInfo
* keys
;
2503 mDNSu8
* end
= ( mDNSu8
* ) &pkt
->msg
+ pkt
->len
;
2504 LargeCacheRecord lcr
;
2505 mDNSBool hasTSIG
= mDNSfalse
;
2506 mDNSBool strip
= mDNSfalse
;
2507 mDNSBool ok
= mDNSfalse
;
2510 // Unused parameters
2518 if ( pkt
->msg
.h
.numAdditionals
)
2520 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2523 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2526 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2529 Log("Unable to read additional record");
2535 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2539 LogMsg( "IsAuthorized: unable to find Additional section" );
2543 // If we don't know what zone this is, then it's authorized.
2552 if ( IsQuery( pkt
) )
2554 keys
= pkt
->zone
->queryKeys
;
2557 else if ( IsUpdate( pkt
) )
2559 keys
= pkt
->zone
->updateKeys
;
2569 if ( pkt
->isZonePublic
)
2575 // If there are no keys, then we're authorized
2577 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
2579 Log( "Invalid TSIG spec %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2580 *rcode
= kDNSFlag1_RC_NotAuth
;
2581 *tcode
= TSIG_ErrBadKey
;
2587 // Find the right key
2589 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2591 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
2599 Log( "Invalid TSIG name %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2600 *rcode
= kDNSFlag1_RC_NotAuth
;
2601 *tcode
= TSIG_ErrBadKey
;
2607 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2608 // lifting of message verification
2610 pkt
->msg
.h
.numAdditionals
--;
2614 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2618 pkt
->msg
.h
.numAdditionals
++;
2622 if ( hasTSIG
&& strip
)
2624 // Strip the TSIG from the message
2626 pkt
->msg
.h
.numAdditionals
--;
2627 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2635 // request handler wrappers for TCP and UDP requests
2636 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2644 UDPContext
* context
= ( UDPContext
* ) vptr
;
2645 PktMsg
* reply
= NULL
;
2649 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2650 // may give us a long answer that would require truncation for UDP delivery to client
2652 reply
= HandleRequest( context
->d
, &context
->pkt
);
2653 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
2655 res
= sendto( context
->sd
, &reply
->msg
, reply
->len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2656 require_action_quiet( res
== ( int ) reply
->len
, exit
, LogErr( "UDPMessageHandler", "sendto" ) );
2667 pthread_exit( NULL
);
2680 UDPContext
* context
= NULL
;
2684 DomainAuthInfo
* key
;
2685 unsigned int clisize
= sizeof( context
->cliaddr
);
2687 mStatus err
= mStatus_NoError
;
2689 context
= malloc( sizeof( UDPContext
) );
2690 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2692 bzero( context
, sizeof( *context
) );
2696 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
2698 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvUDPMessage", "recvfrom" ) );
2699 context
->pkt
.len
= res
;
2700 require_action( clisize
== sizeof( context
->cliaddr
), exit
, err
= mStatus_UnknownErr
; Log( "Client address of unknown size %d", clisize
) );
2701 context
->pkt
.src
= context
->cliaddr
;
2703 // Set the zone in the packet
2705 SetZone( context
->d
, &context
->pkt
);
2707 // Notify messages handled by main thread
2709 if ( IsNotify( &context
->pkt
) )
2711 int err
= RecvNotify( self
, &context
->pkt
);
2715 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2717 if ( IsLLQRequest( &context
->pkt
) )
2719 // LLQ messages handled by main thread
2721 int err
= RecvLLQ( self
, &context
->pkt
, NULL
);
2726 if ( IsLLQAck(&context
->pkt
) )
2728 // !!!KRS need to do acks + retrans
2734 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2735 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2737 pthread_detach(tid
);
2744 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2746 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2747 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_NXDomain
;
2749 res
= sendto( sd
, &reply
.msg
, reply
.len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2750 require_action_quiet( res
== ( int ) reply
.len
, exit
, LogErr( "RecvUDPMessage", "sendto" ) );
2752 err
= mStatus_NoAuth
;
2757 if ( err
&& context
)
2769 TCPContext
* context
2774 if ( context
->sock
)
2776 mDNSPlatformTCPCloseConnection( context
->sock
);
2790 TCPContext
* context
= ( TCPContext
* ) vptr
;
2791 PktMsg
* reply
= NULL
;
2795 //!!!KRS if this read blocks indefinitely, we can run out of threads
2798 reply
= HandleRequest( context
->d
, &context
->pkt
);
2799 require_action_quiet( reply
, exit
, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2801 // deliver reply to client
2803 res
= SendPacket( context
->sock
, reply
);
2804 require_action( res
>= 0, exit
, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2808 FreeTCPContext( context
);
2825 TCPContext
* context
= ( TCPContext
* ) param
;
2829 DomainAuthInfo
* key
;
2832 mDNSBool freeContext
= mDNStrue
;
2833 mStatus err
= mStatus_NoError
;
2835 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2836 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2837 // wire. We'll let it do that, and wait for the next packet which will be ours.
2839 pkt
= RecvPacket( context
->sock
, &context
->pkt
, &closed
);
2840 if (pkt
) HdrNToH(pkt
);
2841 require_action( pkt
|| !closed
, exit
, err
= mStatus_UnknownErr
; LogMsg( "client disconnected" ) );
2845 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2846 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2847 // are sent over UDP
2849 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2851 // Set's the DNS Zone that is associated with this message
2853 SetZone( context
->d
, &context
->pkt
);
2855 // IsAuthorized will make sure the message is authorized for the designated zone.
2856 // After verifying the signature, it will strip the TSIG from the message
2858 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2860 if ( IsLLQRequest( &context
->pkt
) )
2862 // LLQ messages handled by main thread
2863 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2867 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2871 LogErr( "RecvTCPMessage", "pthread_create" );
2872 err
= mStatus_NoError
;
2876 // Let the thread free the context
2878 freeContext
= mDNSfalse
;
2880 pthread_detach(tid
);
2887 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2889 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2891 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2892 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_Refused
;
2894 SendPacket( context
->sock
, &reply
);
2899 freeContext
= mDNSfalse
;
2906 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2911 FreeTCPContext( context
);
2921 TCPSocketFlags flags
2924 TCPContext
* context
= NULL
;
2925 unsigned int clilen
= sizeof( context
->cliaddr
);
2927 mStatus err
= mStatus_NoError
;
2929 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2930 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2931 bzero( context
, sizeof( sizeof( TCPContext
) ) );
2933 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2934 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2936 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2937 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2939 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2940 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2944 if ( err
&& context
)
2955 // listen for incoming requests, periodically check table for expired records, respond to signals
2956 mDNSlocal
int Run(DaemonInfo
*d
)
2958 int staticMaxFD
, nfds
;
2960 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
2961 mDNSBool EventsPending
= mDNSfalse
;
2963 VLog("Listening for requests...");
2967 if ( d
->tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tcpsd
+ 1;
2968 if ( d
->udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->udpsd
+ 1;
2969 if ( d
->tlssd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tlssd
+ 1;
2970 if ( d
->llq_tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_tcpsd
+ 1;
2971 if ( d
->llq_udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_udpsd
+ 1;
2972 if ( d
->LLQEventListenSock
+ 1 > staticMaxFD
) staticMaxFD
= d
->LLQEventListenSock
+ 1;
2976 EventSource
* source
;
2980 timeout
.tv_sec
= timeout
.tv_usec
= 0;
2981 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2985 if (timenow
.tv_sec
- EventTS
.tv_sec
>= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2986 { GenLLQEvents(d
); EventsPending
= mDNSfalse
; } // events, we go ahead and do it now
2987 else timeout
.tv_usec
= 500000; // else do events after 1/2 second with no new events or LLQs
2991 // if no pending events, timeout when we need to check for expired records
2992 if (tablecheck
.tv_sec
&& timenow
.tv_sec
- tablecheck
.tv_sec
>= 0)
2993 { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; } // table check overdue
2994 if (!tablecheck
.tv_sec
) tablecheck
.tv_sec
= timenow
.tv_sec
+ EXPIRATION_INTERVAL
;
2995 timeout
.tv_sec
= tablecheck
.tv_sec
- timenow
.tv_sec
;
2999 FD_SET( d
->tcpsd
, &rset
);
3000 FD_SET( d
->udpsd
, &rset
);
3001 FD_SET( d
->tlssd
, &rset
);
3002 FD_SET( d
->llq_tcpsd
, &rset
);
3003 FD_SET( d
->llq_udpsd
, &rset
);
3004 FD_SET( d
->LLQEventListenSock
, &rset
);
3006 maxFD
= staticMaxFD
;
3008 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3010 FD_SET( source
->fd
, &rset
);
3012 if ( source
->fd
> maxFD
)
3018 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
3025 // close sockets to prevent clients from making new requests during shutdown
3029 close( d
->llq_tcpsd
);
3030 close( d
->llq_udpsd
);
3031 d
->tcpsd
= d
->udpsd
= d
->tlssd
= d
->llq_tcpsd
= d
->llq_udpsd
= -1;
3032 DeleteRecords(d
, mDNStrue
);
3037 Log( "Received SIGINFO" );
3048 Log( "Received SIGHUP" );
3050 err
= ParseConfig( d
, cfgfile
);
3054 LogErr( "Run", "ParseConfig" );
3062 Log("Received unhandled signal - continuing");
3067 LogErr("Run", "select"); return -1;
3072 if (FD_ISSET(d
->udpsd
, &rset
)) RecvUDPMessage( d
, d
->udpsd
);
3073 if (FD_ISSET(d
->llq_udpsd
, &rset
)) RecvUDPMessage( d
, d
->llq_udpsd
);
3074 if (FD_ISSET(d
->tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->tcpsd
, 0 );
3075 if (FD_ISSET(d
->llq_tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->llq_tcpsd
, 0 );
3076 if (FD_ISSET(d
->tlssd
, &rset
)) AcceptTCPConnection( d
, d
->tlssd
, TCP_SOCKET_FLAGS
);
3077 if (FD_ISSET(d
->LLQEventListenSock
, &rset
))
3079 // clear signalling data off socket
3081 recv(d
->LLQEventListenSock
, buf
, 256, 0);
3084 EventsPending
= mDNStrue
;
3085 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
3089 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
3091 if ( FD_ISSET( source
->fd
, &rset
) )
3093 source
->callback( source
->context
);
3094 break; // in case we removed this guy from the event loop
3101 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
3102 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
3108 // signal handler sets global variables, which are inspected by main event loop
3109 // (select automatically returns due to the handled signal)
3110 mDNSlocal
void HndlSignal(int sig
)
3112 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
3113 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
3114 if (sig
== SIGHUP
) { hangup
= 1; return; }
3124 DNameListElem
* elem
;
3125 mStatus err
= mStatus_NoError
;
3127 elem
= ( DNameListElem
* ) malloc( sizeof( DNameListElem
) );
3128 require_action( elem
, exit
, err
= mStatus_NoMemoryErr
);
3129 MakeDomainNameFromDNSNameString( &elem
->name
, name
);
3130 elem
->next
= d
->public_names
;
3131 d
->public_names
= elem
;
3139 int main(int argc
, char *argv
[])
3141 int started_via_launchd
= 0;
3145 Log("dnsextd starting");
3147 d
= malloc(sizeof(*d
));
3148 if (!d
) { LogErr("main", "malloc"); exit(1); }
3149 bzero(d
, sizeof(DaemonInfo
));
3151 // Setup the public SRV record names
3153 SetPublicSRV(d
, "_dns-update._udp.");
3154 SetPublicSRV(d
, "_dns-llq._udp.");
3155 SetPublicSRV(d
, "_dns-update-tls._tcp.");
3156 SetPublicSRV(d
, "_dns-query-tls._tcp.");
3157 SetPublicSRV(d
, "_dns-llq-tls._tcp.");
3159 // Setup signal handling
3161 if (signal(SIGHUP
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGHUP");
3162 if (signal(SIGTERM
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGTERM");
3163 if (signal(INFO_SIGNAL
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINFO");
3164 if (signal(SIGINT
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINT");
3165 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) perror("Can't ignore SIGPIPE");
3167 // remove open file limit
3168 rlim
.rlim_max
= RLIM_INFINITY
;
3169 rlim
.rlim_cur
= RLIM_INFINITY
;
3170 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3172 LogErr("main", "setrlimit");
3173 Log("Using default file descriptor resource limit");
3176 if (!strcasecmp(argv
[1], "-launchd"))
3178 Log("started_via_launchd");
3179 started_via_launchd
= 1;
3183 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3185 if (!foreground
&& !started_via_launchd
)
3189 LogErr("main", "daemon");
3194 if (InitLeaseTable(d
) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3195 if (SetupSockets(d
) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3196 if (SetUpdateSRV(d
) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3200 Log("dnsextd stopping");
3202 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3208 // These are stubbed out implementations of up-call routines that the various platform support layers
3209 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3210 // link this code in.
3212 // It's an error for these routines to actually be called, so perhaps we should log any call
3214 void mDNSCoreInitComplete( mDNS
* const m
, mStatus result
) { ( void ) m
; ( void ) result
; }
3215 void mDNSCoreMachineSleep(mDNS
* const m
, mDNSBool wake
) { ( void ) m
; ( void ) wake
; }
3216 void mDNSCoreReceive(mDNS
*const m
, void *const msg
, const mDNSu8
*const end
,
3217 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
,
3218 const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID iid
)
3219 { ( void ) m
; ( void ) msg
; ( void ) end
; ( void ) srcaddr
; ( void ) srcport
; ( void ) dstaddr
; ( void ) dstport
; ( void ) iid
; }
3220 DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
)
3221 { ( void ) m
; ( void ) d
; ( void ) interface
; ( void ) addr
; ( void ) port
; return(NULL
); }
3222 void mDNS_AddSearchDomain(const domainname
*const domain
) { (void)domain
; }
3223 void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3224 { ( void ) m
; ( void ) fqdn
; ( void ) StatusCallback
; ( void ) StatusContext
; }
3225 mDNSs32
mDNS_Execute (mDNS
*const m
) { ( void ) m
; return 0; }
3226 mDNSs32
mDNS_TimeNow(const mDNS
*const m
) { ( void ) m
; return 0; }
3227 mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3228 void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3229 { ( void ) m
; ( void ) set
; ( void ) flapping
; }
3230 const char * const mDNS_DomainTypeNames
[1] = {};
3231 mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
3232 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
3233 { ( void ) m
; ( void ) question
; ( void ) DomainType
; ( void ) dom
; ( void ) InterfaceID
; ( void ) Callback
; ( void ) Context
; return 0; }
3234 mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3235 mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3236 { ( void ) m
; ( void ) set
; ( void ) flapping
; return 0; }
3237 void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
) { ( void ) m
; ( void ) fqdn
; }
3238 void mDNS_SetFQDN(mDNS
* const m
) { ( void ) m
; }
3239 void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3240 { ( void ) m
; ( void ) v4addr
; ( void ) v6addr
; ( void ) router
; }
3241 mStatus
uDNS_SetupDNSConfig( mDNS
*const m
) { ( void ) m
; return 0; }
3242 mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
3243 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, mDNSBool AutoTunnel
)
3244 { ( void ) m
; ( void ) info
; ( void ) domain
; ( void ) keyname
; ( void ) b64keydata
; ( void ) AutoTunnel
; return 0; }
3245 mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
) { ( void ) m
; ( void ) question
; return 0; }
3249 // Note: The C preprocessor stringify operator ('#') makes a string from its argument, without macro expansion
3250 // e.g. If "version" is #define'd to be "4", then STRINGIFY_AWE(version) will return the string "version", not "4"
3251 // To expand "version" to its value before making the string, use STRINGIFY(version) instead
3252 #define STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s) #s
3253 #define STRINGIFY(s) STRINGIFY_ARGUMENT_WITHOUT_EXPANSION(s)
3255 // For convenience when using the "strings" command, this is the last thing in the file
3256 // The "@(#) " pattern is a special prefix the "what" command looks for
3257 const char mDNSResponderVersionString_SCCS
[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
3259 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3260 const char *__crashreporter_info__
= mDNSResponderVersionString_SCCS
+ 5;
3261 asm(".desc ___crashreporter_info__, 0x10");