1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2015 Apple 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.
19 // In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
20 // error, which prevents compilation because we build with "-Werror".
21 // Since this is supposed to be portable cross-platform code, we don't care that daemon is
22 // deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
23 #define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
38 #include <sys/resource.h>
44 extern int daemon(int, int);
47 // Solaris doesn't have daemon(), so we define it here
48 #ifdef NOT_HAVE_DAEMON
49 #include "../mDNSPosix/mDNSUNP.h" // For daemon()
50 #endif // NOT_HAVE_DAEMON
53 #include "../mDNSShared/uds_daemon.h"
54 #include "../mDNSShared/dnssd_ipc.h"
55 #include "../mDNSCore/uDNS.h"
56 #include "../mDNSShared/DebugServices.h"
58 // Compatibility workaround
60 #define AF_LOCAL AF_UNIX
66 mDNSexport
const char ProgramName
[] = "dnsextd";
68 #define LOOPBACK "127.0.0.1"
70 # define LISTENQ 128 // tcp connection backlog
72 #define RECV_BUFLEN 9000
73 #define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
74 #define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
75 #define SRV_TTL 7200 // TTL For _dns-update SRV records
76 #define CONFIG_FILE "/etc/dnsextd.conf"
77 #define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
79 // LLQ Lease bounds (seconds)
80 #define LLQ_MIN_LEASE (15 * 60)
81 #define LLQ_MAX_LEASE (120 * 60)
82 #define LLQ_LEASE_FUDGE 60
84 // LLQ SOA poll interval (microseconds)
85 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
86 #define LLQ_MONITOR_INTERVAL 250000
88 #define INFO_SIGNAL SIGINFO
90 #define INFO_SIGNAL SIGUSR1
93 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
97 // Structs/fields that must be locked for thread safety are explicitly commented
100 // args passed to UDP request handler thread as void*
105 struct sockaddr_in cliaddr
;
110 // args passed to TCP request handler thread as void*
114 struct sockaddr_in cliaddr
;
115 TCPSocket
*sock
; // socket connected to client
119 // args passed to UpdateAnswerList thread as void*
124 } UpdateAnswerListArgs
;
130 // booleans to determine runtime output
131 // read-only after initialization (no mutex protection)
132 static mDNSBool foreground
= 0;
133 static mDNSBool verbose
= 0;
135 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
136 static mDNSBool terminate
= 0;
137 static mDNSBool dumptable
= 0;
138 static mDNSBool hangup
= 0;
140 // global for config file location
141 static char * cfgfile
= NULL
;
145 // Log messages are delivered to syslog unless -f option specified
148 // common message logging subroutine
149 mDNSlocal
void PrintLog(const char *buffer
)
153 fprintf(stderr
,"%s\n", buffer
);
158 openlog("dnsextd", LOG_CONS
, LOG_DAEMON
);
159 syslog(LOG_ERR
, "%s", buffer
);
164 // Verbose Logging (conditional on -v option)
165 mDNSlocal
void VLog(const char *format
, ...)
170 if (!verbose
) return;
171 va_start(ptr
,format
);
172 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
177 // Unconditional Logging
178 mDNSlocal
void Log(const char *format
, ...)
183 va_start(ptr
,format
);
184 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
190 // prints message "dnsextd <function>: <operation> - <error message>"
191 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
192 mDNSlocal
void LogErr(const char *fn
, const char *operation
)
194 char buf
[512], errbuf
[256];
195 strerror_r(errno
, errbuf
, sizeof(errbuf
));
196 snprintf(buf
, sizeof(buf
), "%s: %s - %s", fn
, operation
, errbuf
);
201 // Networking Utility Routines
204 // Convert DNS Message Header from Network to Host byte order
205 mDNSlocal
void HdrNToH(PktMsg
*pkt
)
207 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
208 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
209 pkt
->msg
.h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
210 pkt
->msg
.h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
211 pkt
->msg
.h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
212 pkt
->msg
.h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
215 // Convert DNS Message Header from Host to Network byte order
216 mDNSlocal
void HdrHToN(PktMsg
*pkt
)
218 mDNSu16 numQuestions
= pkt
->msg
.h
.numQuestions
;
219 mDNSu16 numAnswers
= pkt
->msg
.h
.numAnswers
;
220 mDNSu16 numAuthorities
= pkt
->msg
.h
.numAuthorities
;
221 mDNSu16 numAdditionals
= pkt
->msg
.h
.numAdditionals
;
222 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
224 // Put all the integer values in IETF byte-order (MSB first, LSB second)
225 *ptr
++ = (mDNSu8
)(numQuestions
>> 8);
226 *ptr
++ = (mDNSu8
)(numQuestions
& 0xFF);
227 *ptr
++ = (mDNSu8
)(numAnswers
>> 8);
228 *ptr
++ = (mDNSu8
)(numAnswers
& 0xFF);
229 *ptr
++ = (mDNSu8
)(numAuthorities
>> 8);
230 *ptr
++ = (mDNSu8
)(numAuthorities
& 0xFF);
231 *ptr
++ = (mDNSu8
)(numAdditionals
>> 8);
232 *ptr
++ = (mDNSu8
)(numAdditionals
& 0xFF);
236 // Add socket to event loop
238 mDNSlocal mStatus
AddSourceToEventLoop( DaemonInfo
* self
, TCPSocket
*sock
, EventCallback callback
, void *context
)
240 EventSource
* newSource
;
241 mStatus err
= mStatus_NoError
;
243 if ( self
->eventSources
.LinkOffset
== 0 )
245 InitLinkedList( &self
->eventSources
, offsetof( EventSource
, next
));
248 newSource
= ( EventSource
*) malloc( sizeof *newSource
);
249 if ( newSource
== NULL
)
251 err
= mStatus_NoMemoryErr
;
255 newSource
->callback
= callback
;
256 newSource
->context
= context
;
257 newSource
->sock
= sock
;
258 newSource
->fd
= mDNSPlatformTCPGetFD( sock
);
260 AddToTail( &self
->eventSources
, newSource
);
268 // Remove socket from event loop
270 mDNSlocal mStatus
RemoveSourceFromEventLoop( DaemonInfo
* self
, TCPSocket
*sock
)
272 EventSource
* source
;
275 for ( source
= ( EventSource
* ) self
->eventSources
.Head
; source
; source
= source
->next
)
277 if ( source
->sock
== sock
)
279 RemoveFromList( &self
->eventSources
, source
);
282 err
= mStatus_NoError
;
287 err
= mStatus_NoSuchNameErr
;
294 // create a socket connected to nameserver
295 // caller terminates connection via close()
296 mDNSlocal TCPSocket
*ConnectToServer(DaemonInfo
*d
)
298 int ntries
= 0, retry
= 0;
302 mDNSIPPort port
= zeroIPPort
;
305 TCPSocket
*sock
= mDNSPlatformTCPSocket(0, &port
, mDNSfalse
);
306 if ( !sock
) { LogErr("ConnectToServer", "socket"); return NULL
; }
307 fd
= mDNSPlatformTCPGetFD( sock
);
308 if (!connect( fd
, (struct sockaddr
*)&d
->ns_addr
, sizeof(d
->ns_addr
))) return sock
;
309 mDNSPlatformTCPCloseConnection( sock
);
312 LogErr("ConnectToServer", "connect");
313 Log("ConnectToServer - retrying connection");
314 if (!retry
) retry
= 500000 + random() % 500000;
318 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries
); return NULL
; }
322 // send an entire block of data over a connected socket
323 mDNSlocal
int MySend(TCPSocket
*sock
, const void *msg
, int len
)
325 int selectval
, n
, nsent
= 0;
327 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
335 fd
= mDNSPlatformTCPGetFD( sock
);
338 selectval
= select( fd
+1, NULL
, &wset
, NULL
, &timeout
);
339 if (selectval
< 0) { LogErr("MySend", "select"); return -1; }
340 if (!selectval
|| !FD_ISSET(fd
, &wset
)) { Log("MySend - timeout"); return -1; }
342 n
= mDNSPlatformWriteTCP( sock
, ( char* ) msg
+ nsent
, len
- nsent
);
344 if (n
< 0) { LogErr("MySend", "send"); return -1; }
350 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
351 mDNSlocal
int SendPacket(TCPSocket
*sock
, PktMsg
*pkt
)
353 // send the lenth, in network byte order
354 mDNSu16 len
= htons((mDNSu16
)pkt
->len
);
355 if (MySend(sock
, &len
, sizeof(len
)) < 0) return -1;
358 VLog("SendPacket Q:%d A:%d A:%d A:%d ",
359 ntohs(pkt
->msg
.h
.numQuestions
),
360 ntohs(pkt
->msg
.h
.numAnswers
),
361 ntohs(pkt
->msg
.h
.numAuthorities
),
362 ntohs(pkt
->msg
.h
.numAdditionals
));
363 return MySend(sock
, &pkt
->msg
, pkt
->len
);
366 // Receive len bytes, waiting until we have all of them.
367 // Returns number of bytes read (which should always be the number asked for).
368 static int my_recv(TCPSocket
*sock
, void *const buf
, const int len
, mDNSBool
* closed
)
370 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
371 // use an explicit while() loop instead.
372 // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
373 // arithmetic on "void *" pointers is compiler-dependent.
376 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
377 int selectval
, remaining
= len
;
378 char *ptr
= (char *)buf
;
385 fd
= mDNSPlatformTCPGetFD( sock
);
389 selectval
= select(fd
+1, &rset
, NULL
, NULL
, &timeout
);
390 if (selectval
< 0) { LogErr("my_recv", "select"); return -1; }
391 if (!selectval
|| !FD_ISSET(fd
, &rset
))
393 Log("my_recv - timeout");
397 num_read
= mDNSPlatformReadTCP( sock
, ptr
, remaining
, closed
);
399 if (((num_read
== 0) && *closed
) || (num_read
< 0) || (num_read
> remaining
)) return -1;
400 if (num_read
== 0) return 0;
402 remaining
-= num_read
;
407 // Return a DNS Message read off of a TCP socket, or NULL on failure
408 // If storage is non-null, result is placed in that buffer. Otherwise,
409 // returned value is allocated with Malloc, and contains sufficient extra
410 // storage for a Lease OPT RR
428 fd
= mDNSPlatformTCPGetFD( sock
);
430 nread
= my_recv( sock
, &msglen
, sizeof( msglen
), closed
);
432 require_action_quiet( nread
!= -1, exit
, err
= mStatus_UnknownErr
);
433 require_action_quiet( nread
> 0, exit
, err
= mStatus_NoError
);
435 msglen
= ntohs( msglen
);
436 require_action_quiet( nread
== sizeof( msglen
), exit
, err
= mStatus_UnknownErr
; Log( "Could not read length field of message") );
440 require_action_quiet( msglen
<= sizeof( storage
->msg
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: provided buffer too small." ) );
445 // buffer extra space to add an OPT RR
447 if ( msglen
> sizeof(DNSMessage
))
449 allocsize
= sizeof(PktMsg
) - sizeof(DNSMessage
) + msglen
;
453 allocsize
= sizeof(PktMsg
);
456 pkt
= malloc(allocsize
);
457 require_action_quiet( pkt
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvPacket", "malloc" ) );
458 mDNSPlatformMemZero( pkt
, sizeof( *pkt
) );
462 srclen
= sizeof(pkt
->src
);
464 if ( getpeername( fd
, ( struct sockaddr
* ) &pkt
->src
, &srclen
) || ( srclen
!= sizeof( pkt
->src
) ) )
466 LogErr("RecvPacket", "getpeername");
467 mDNSPlatformMemZero(&pkt
->src
, sizeof(pkt
->src
));
470 nread
= my_recv(sock
, &pkt
->msg
, msglen
, closed
);
471 require_action_quiet( nread
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvPacket", "recv" ) );
472 require_action_quiet( nread
== msglen
, exit
, err
= mStatus_UnknownErr
; Log( "Could not read entire message" ) );
473 require_action_quiet( pkt
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: Message too short (%d bytes)", pkt
->len
) );
479 if ( pkt
!= storage
)
500 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
502 if ( SameDomainName( &zone
->name
, name
) )
515 const domainname
* zname
,
516 const domainname
* dname
519 mDNSu16 i
= DomainNameLength( zname
);
520 mDNSu16 j
= DomainNameLength( dname
);
522 if ( ( i
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( j
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( i
> j
) || ( memcmp( zname
->c
, dname
->c
+ ( j
- i
), i
) != 0 ) )
531 mDNSlocal mDNSBool
IsQuery( PktMsg
* pkt
)
533 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
);
537 mDNSlocal mDNSBool
IsUpdate( PktMsg
* pkt
)
539 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_OP_Update
);
543 mDNSlocal mDNSBool
IsNotify(PktMsg
*pkt
)
545 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( mDNSu8
) ( kDNSFlag0_OP_Notify
);
549 mDNSlocal mDNSBool
IsLLQRequest(PktMsg
*pkt
)
551 const mDNSu8
*ptr
= NULL
, *end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
552 LargeCacheRecord lcr
;
554 mDNSBool result
= mDNSfalse
;
557 if ((mDNSu8
)(pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (mDNSu8
)(kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
)) goto end
;
559 if (!pkt
->msg
.h
.numAdditionals
) goto end
;
560 ptr
= LocateAdditionals(&pkt
->msg
, end
);
563 bzero(&lcr
, sizeof(lcr
));
564 // find last Additional info.
565 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
567 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
568 if (!ptr
) { Log("Unable to read additional record"); goto end
; }
571 if ( lcr
.r
.resrec
.rrtype
== kDNSType_OPT
&& lcr
.r
.resrec
.rdlength
>= DNSOpt_LLQData_Space
&& lcr
.r
.resrec
.rdata
->u
.opt
[0].opt
== kDNSOpt_LLQ
)
581 // !!!KRS implement properly
582 mDNSlocal mDNSBool
IsLLQAck(PktMsg
*pkt
)
584 if ((pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
) &&
585 pkt
->msg
.h
.numQuestions
&& !pkt
->msg
.h
.numAnswers
&& !pkt
->msg
.h
.numAuthorities
) return mDNStrue
;
597 DNameListElem
* elem
;
598 mDNSBool ret
= mDNSfalse
;
599 int i
= ( int ) DomainNameLength( &q
->qname
) - 1;
601 for ( elem
= self
->public_names
; elem
; elem
= elem
->next
)
603 int j
= ( int ) DomainNameLength( &elem
->name
) - 1;
607 for ( ; i
>= 0; i
--, j
-- )
609 if ( q
->qname
.c
[ i
] != elem
->name
.c
[ j
] )
632 const mDNSu8
* ptr
= pkt
->msg
.data
;
633 mDNSBool exception
= mDNSfalse
;
638 pkt
->isZonePublic
= mDNStrue
;
641 // Figure out what type of packet this is
643 if ( IsQuery( pkt
) )
645 DNSQuestion question
;
649 getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
651 AppendDomainName( &zname
, &question
.qname
);
653 exception
= ( ( question
.qtype
== kDNSType_SOA
) || ( question
.qtype
== kDNSType_NS
) || ( ( question
.qtype
== kDNSType_SRV
) && IsPublicSRV( self
, &question
) ) );
655 else if ( IsUpdate( pkt
) )
657 DNSQuestion question
;
659 // It's an update. The format of the zone section is the same as the format for the question section
660 // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
662 getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
664 AppendDomainName( &zname
, &question
.qname
);
666 exception
= mDNSfalse
;
669 if ( zname
.c
[0] != '\0' )
671 // Find the right zone
673 for ( pkt
->zone
= self
->zones
; pkt
->zone
; pkt
->zone
= pkt
->zone
->next
)
675 if ( ZoneHandlesName( &pkt
->zone
->name
, &zname
) )
677 VLog( "found correct zone %##s for query", pkt
->zone
->name
.c
);
679 pkt
->isZonePublic
= ( ( pkt
->zone
->type
== kDNSZonePublic
) || exception
);
681 VLog( "zone %##s is %s", pkt
->zone
->name
.c
, ( pkt
->isZonePublic
) ? "public" : "private" );
691 UDPServerTransaction(const DaemonInfo
*d
, const PktMsg
*request
, PktMsg
*reply
, mDNSBool
*trunc
)
694 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
697 mStatus err
= mStatus_NoError
;
705 sd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
706 require_action( sd
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "socket" ) );
708 // Send the packet to the nameserver
710 VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
711 ntohs(request
->msg
.h
.numQuestions
),
712 ntohs(request
->msg
.h
.numAnswers
),
713 ntohs(request
->msg
.h
.numAuthorities
),
714 ntohs(request
->msg
.h
.numAdditionals
));
715 res
= sendto( sd
, (char *)&request
->msg
, request
->len
, 0, ( struct sockaddr
* ) &d
->ns_addr
, sizeof( d
->ns_addr
) );
716 require_action( res
== (int) request
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "sendto" ) );
722 res
= select( sd
+ 1, &rset
, NULL
, NULL
, &timeout
);
723 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "select" ) );
724 require_action( ( res
> 0 ) && FD_ISSET( sd
, &rset
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - timeout" ) );
728 reply
->len
= recvfrom( sd
, &reply
->msg
, sizeof(reply
->msg
), 0, NULL
, NULL
);
729 require_action( ( ( int ) reply
->len
) >= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "recvfrom" ) );
730 require_action( reply
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - Message too short (%d bytes)", reply
->len
) );
732 // Check for truncation bit
734 if ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_TC
)
750 // Dynamic Update Utility Routines
753 // check if a request and server response complete a successful dynamic update
754 mDNSlocal mDNSBool
SuccessfulUpdateTransaction(PktMsg
*request
, PktMsg
*reply
)
757 char *vlogmsg
= NULL
;
760 if (!request
|| !reply
) { vlogmsg
= "NULL message"; goto failure
; }
761 if (request
->len
< sizeof(DNSMessageHeader
) || reply
->len
< sizeof(DNSMessageHeader
)) { vlogmsg
= "Malformatted message"; goto failure
; }
763 // check request operation
764 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
))
765 { vlogmsg
= "Request opcode not an update"; goto failure
; }
768 if ((reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)) { vlogmsg
= "Reply contains non-zero rcode"; goto failure
; }
769 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
))
770 { vlogmsg
= "Reply opcode not an update response"; goto failure
; }
772 VLog("Successful update from %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32));
776 VLog("Request %s: %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32), vlogmsg
);
780 // Allocate an appropriately sized CacheRecord and copy data from original.
781 // Name pointer in CacheRecord object is set to point to the name specified
783 mDNSlocal CacheRecord
*CopyCacheRecord(const CacheRecord
*orig
, domainname
*name
)
786 size_t size
= sizeof(*cr
);
787 if (orig
->resrec
.rdlength
> InlineCacheRDSize
) size
+= orig
->resrec
.rdlength
- InlineCacheRDSize
;
789 if (!cr
) { LogErr("CopyCacheRecord", "malloc"); return NULL
; }
790 memcpy(cr
, orig
, size
);
791 cr
->resrec
.rdata
= (RData
*)&cr
->smallrdatastorage
;
792 cr
->resrec
.name
= name
;
799 // Lease Hashtable Utility Routines
802 // double hash table size
803 // caller must lock table prior to invocation
804 mDNSlocal
void RehashTable(DaemonInfo
*d
)
806 RRTableElem
*ptr
, *tmp
, **new;
807 int i
, bucket
, newnbuckets
= d
->nbuckets
* 2;
809 VLog("Rehashing lease table (new size %d buckets)", newnbuckets
);
810 new = malloc(sizeof(RRTableElem
*) * newnbuckets
);
811 if (!new) { LogErr("RehashTable", "malloc"); return; }
812 mDNSPlatformMemZero(new, newnbuckets
* sizeof(RRTableElem
*));
814 for (i
= 0; i
< d
->nbuckets
; i
++)
819 bucket
= ptr
->rr
.resrec
.namehash
% newnbuckets
;
822 tmp
->next
= new[bucket
];
826 d
->nbuckets
= newnbuckets
;
831 // print entire contents of hashtable, invoked via SIGINFO
832 mDNSlocal
void PrintLeaseTable(DaemonInfo
*d
)
836 char rrbuf
[MaxMsg
], addrbuf
[16];
840 if (gettimeofday(&now
, NULL
)) { LogErr("PrintTable", "gettimeofday"); return; }
841 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
843 Log("Dumping Lease Table Contents (table contains %d resource records)", d
->nelems
);
844 for (i
= 0; i
< d
->nbuckets
; i
++)
846 for (ptr
= d
->table
[i
]; ptr
; ptr
= ptr
->next
)
848 hr
= ((ptr
->expire
- now
.tv_sec
) / 60) / 60;
849 min
= ((ptr
->expire
- now
.tv_sec
) / 60) % 60;
850 sec
= (ptr
->expire
- now
.tv_sec
) % 60;
851 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
,
852 GetRRDisplayString_rdb(&ptr
->rr
.resrec
, &ptr
->rr
.resrec
.rdata
->u
, rrbuf
));
855 pthread_mutex_unlock(&d
->tablelock
);
859 // Startup SRV Registration Routines
860 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
861 // the daemon accepts requests
864 // delete all RRS of a given name/type
865 mDNSlocal mDNSu8
*putRRSetDeletion(DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
, ResourceRecord
*rr
)
867 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
868 if (!ptr
|| ptr
+ 10 >= limit
) return NULL
; // out of space
869 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
870 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
871 ptr
[2] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
>> 8);
872 ptr
[3] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
& 0xFF);
873 mDNSPlatformMemZero(ptr
+4, sizeof(rr
->rroriginalttl
) + sizeof(rr
->rdlength
)); // zero ttl/rdata
874 msg
->h
.mDNS_numUpdates
++;
878 mDNSlocal mDNSu8
*PutUpdateSRV(DaemonInfo
*d
, DNSZone
* zone
, PktMsg
*pkt
, mDNSu8
*ptr
, char *regtype
, mDNSIPPort port
, mDNSBool registration
)
881 char hostname
[1024], buf
[MaxMsg
];
882 mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ sizeof(DNSMessage
);
886 mDNS_SetupResourceRecord(&rr
, NULL
, 0, kDNSType_SRV
, SRV_TTL
, kDNSRecordTypeUnique
, AuthRecordAny
, NULL
, NULL
);
887 rr
.resrec
.rrclass
= kDNSClass_IN
;
888 rr
.resrec
.rdata
->u
.srv
.priority
= 0;
889 rr
.resrec
.rdata
->u
.srv
.weight
= 0;
890 rr
.resrec
.rdata
->u
.srv
.port
= port
;
891 if (gethostname(hostname
, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr
.resrec
.rdata
->u
.srv
.target
, hostname
))
892 rr
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0';
894 MakeDomainNameFromDNSNameString(&rr
.namestorage
, regtype
);
895 AppendDomainName(&rr
.namestorage
, &zone
->name
);
896 VLog("%s %s", registration
? "Registering SRV record" : "Deleting existing RRSet",
897 GetRRDisplayString_rdb(&rr
.resrec
, &rr
.resrec
.rdata
->u
, buf
));
898 if (registration
) ptr
= PutResourceRecord(&pkt
->msg
, ptr
, &pkt
->msg
.h
.mDNS_numUpdates
, &rr
.resrec
);
899 else ptr
= putRRSetDeletion(&pkt
->msg
, ptr
, end
, &rr
.resrec
);
904 // perform dynamic update.
905 // specify deletion by passing false for the register parameter, otherwise register the records.
906 mDNSlocal
int UpdateSRV(DaemonInfo
*d
, mDNSBool registration
)
908 TCPSocket
*sock
= NULL
;
910 int err
= mStatus_NoError
;
912 sock
= ConnectToServer( d
);
913 require_action( sock
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: ConnectToServer failed" ) );
915 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
918 mDNSu8
*ptr
= pkt
.msg
.data
;
919 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
920 PktMsg
*reply
= NULL
;
924 // Initialize message
925 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
926 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
927 pkt
.src
.sin_family
= AF_INET
;
929 // format message body
930 ptr
= putZone(&pkt
.msg
, ptr
, end
, &zone
->name
, mDNSOpaque16fromIntVal(kDNSClass_IN
));
931 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
933 if ( zone
->type
== kDNSZonePrivate
)
935 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls._tcp.", d
->private_port
, registration
);
936 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
937 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls._tcp.", d
->private_port
, registration
);
938 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
939 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls._tcp.", d
->private_port
, registration
);
940 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
944 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
945 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
946 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
947 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
954 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls.", d
->private_port
, registration
);
955 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
956 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls.", d
->private_port
, registration
);
957 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
958 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls.", d
->private_port
, registration
);
959 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
962 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
963 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
964 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
965 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
970 if ( zone
->updateKeys
)
972 DNSDigest_SignMessage( &pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
973 require_action( ptr
, exit
, Log("UpdateSRV: Error constructing lease expiration update" ) );
976 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
978 // send message, receive reply
980 err
= SendPacket( sock
, &pkt
);
981 require_action( !err
, exit
, Log( "UpdateSRV: SendPacket failed" ) );
983 reply
= RecvPacket( sock
, NULL
, &closed
);
984 require_action( reply
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: RecvPacket returned NULL" ) );
986 ok
= SuccessfulUpdateTransaction( &pkt
, reply
);
990 Log("SRV record registration failed with rcode %d", reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1000 mDNSPlatformTCPCloseConnection( sock
);
1006 // wrapper routines/macros
1007 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1009 // clear any existing records prior to registration
1010 mDNSlocal
int SetUpdateSRV(DaemonInfo
*d
)
1014 err
= ClearUpdateSRV(d
); // clear any existing record
1015 if (!err
) err
= UpdateSRV(d
, 1);
1020 // Argument Parsing and Configuration
1023 mDNSlocal
void PrintUsage(void)
1025 fprintf(stderr
, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1026 "Use \"dnsextd -h\" for help\n");
1029 mDNSlocal
void PrintHelp(void)
1031 fprintf(stderr
, "\n\n");
1035 "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
1036 "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
1037 "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
1038 "Discovery, Update Leases, and Long Lived Queries.)\n\n"
1040 "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
1041 "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
1042 "primary master server for this zone.\n\n"
1044 "The options are as follows:\n\n"
1046 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1048 "-d Run daemon in foreground.\n\n"
1050 "-h Print help.\n\n"
1052 "-v Verbose output.\n\n"
1057 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
1058 // returns 0 (success) if program is to continue execution
1059 // output control arguments (-f, -v) do not affect this routine
1060 mDNSlocal
int ProcessArgs(int argc
, char *argv
[], DaemonInfo
*d
)
1066 cfgfile
= strdup( CONFIG_FILE
);
1067 require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
);
1069 // defaults, may be overriden by command option
1071 // setup our sockaddr
1073 mDNSPlatformMemZero( &d
->addr
, sizeof( d
->addr
) );
1074 d
->addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1075 d
->addr
.sin_port
= UnicastDNSPort
.NotAnInteger
;
1076 d
->addr
.sin_family
= AF_INET
;
1077 #ifndef NOT_HAVE_SA_LEN
1078 d
->addr
.sin_len
= sizeof( d
->addr
);
1081 // setup nameserver's sockaddr
1083 mDNSPlatformMemZero(&d
->ns_addr
, sizeof(d
->ns_addr
));
1084 d
->ns_addr
.sin_family
= AF_INET
;
1085 inet_pton( AF_INET
, LOOPBACK
, &d
->ns_addr
.sin_addr
);
1086 d
->ns_addr
.sin_port
= NSIPCPort
.NotAnInteger
;
1087 #ifndef NOT_HAVE_SA_LEN
1088 d
->ns_addr
.sin_len
= sizeof( d
->ns_addr
);
1093 d
->private_port
= PrivateDNSPort
;
1094 d
->llq_port
= DNSEXTPort
;
1096 while ((opt
= getopt(argc
, argv
, "f:hdv")) != -1)
1100 case 'f': free( cfgfile
); cfgfile
= strdup( optarg
); require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
); break;
1101 case 'h': PrintHelp(); return -1;
1102 case 'd': foreground
= 1; break; // Also used when launched via OS X's launchd mechanism
1103 case 'v': verbose
= 1; break;
1104 default: goto arg_error
;
1108 err
= ParseConfig( d
, cfgfile
);
1109 require_noerr( err
, arg_error
);
1111 // Make sure we've specified some zones
1113 require_action( d
->zones
, arg_error
, err
= mStatus_UnknownErr
);
1115 // if we have a shared secret, use it for the entire zone
1117 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1119 if ( zone
->updateKeys
)
1121 AssignDomainName( &zone
->updateKeys
->domain
, &zone
->name
);
1135 // Initialization Routines
1138 // Allocate memory, initialize locks and bookkeeping variables
1139 mDNSlocal
int InitLeaseTable(DaemonInfo
*d
)
1141 if (pthread_mutex_init(&d
->tablelock
, NULL
)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1142 d
->nbuckets
= LEASETABLE_INIT_NBUCKETS
;
1144 d
->table
= malloc(sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1145 if (!d
->table
) { LogErr("InitLeaseTable", "malloc"); return -1; }
1146 mDNSPlatformMemZero(d
->table
, sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1157 static const int kOn
= 1;
1159 mDNSBool
private = mDNSfalse
;
1160 struct sockaddr_in daddr
;
1164 // set up sockets on which we all ns requests
1166 self
->tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1167 require_action( dnssd_SocketValid(self
->tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1169 #if defined(SO_REUSEADDR)
1170 err
= setsockopt(self
->tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1171 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
1174 err
= bind( self
->tcpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1175 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1177 err
= listen( self
->tcpsd
, LISTENQ
);
1178 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1180 self
->udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1181 require_action( dnssd_SocketValid(self
->udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1183 #if defined(SO_REUSEADDR)
1184 err
= setsockopt(self
->udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1185 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
1188 err
= bind( self
->udpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1189 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->udpsd" ) );
1191 // set up sockets on which we receive llq requests
1193 mDNSPlatformMemZero(&self
->llq_addr
, sizeof(self
->llq_addr
));
1194 self
->llq_addr
.sin_family
= AF_INET
;
1195 self
->llq_addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1196 self
->llq_addr
.sin_port
= ( self
->llq_port
.NotAnInteger
) ? self
->llq_port
.NotAnInteger
: DNSEXTPort
.NotAnInteger
;
1198 if (self
->llq_addr
.sin_port
== self
->addr
.sin_port
)
1200 self
->llq_tcpsd
= self
->tcpsd
;
1201 self
->llq_udpsd
= self
->udpsd
;
1205 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1206 require_action( dnssd_SocketValid(self
->llq_tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1208 #if defined(SO_REUSEADDR)
1209 err
= setsockopt(self
->llq_tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1210 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
1213 err
= bind( self
->llq_tcpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1214 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
1216 err
= listen( self
->llq_tcpsd
, LISTENQ
);
1217 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1219 self
->llq_udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1220 require_action( dnssd_SocketValid(self
->llq_udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1222 #if defined(SO_REUSEADDR)
1223 err
= setsockopt(self
->llq_udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1224 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
1227 err
= bind(self
->llq_udpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1228 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
1231 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1233 err
= socketpair( AF_LOCAL
, SOCK_STREAM
, 0, sockpair
);
1234 require_action( !err
, exit
, LogErr( "SetupSockets", "socketpair" ) );
1236 self
->LLQEventListenSock
= sockpair
[0];
1237 self
->LLQEventNotifySock
= sockpair
[1];
1239 // set up socket on which we receive private requests
1241 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1242 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1243 mDNSPlatformMemZero(&daddr
, sizeof(daddr
));
1244 daddr
.sin_family
= AF_INET
;
1245 daddr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1246 daddr
.sin_port
= ( self
->private_port
.NotAnInteger
) ? self
->private_port
.NotAnInteger
: PrivateDNSPort
.NotAnInteger
;
1248 self
->tlssd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1249 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1251 #if defined(SO_REUSEADDR)
1252 err
= setsockopt(self
->tlssd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1253 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
1256 err
= bind( self
->tlssd
, ( struct sockaddr
* ) &daddr
, sizeof( daddr
) );
1257 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tlssd" ) );
1259 err
= listen( self
->tlssd
, LISTENQ
);
1260 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1262 // Do we have any private zones?
1264 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
1266 if ( zone
->type
== kDNSZonePrivate
)
1275 err
= mDNSPlatformTLSSetupCerts();
1276 require_action( !err
, exit
, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1285 // periodic table updates
1288 // Delete a resource record from the nameserver via a dynamic update
1289 // sd is a socket already connected to the server
1290 mDNSlocal
void DeleteOneRecord(DaemonInfo
*d
, CacheRecord
*rr
, domainname
*zname
, TCPSocket
*sock
)
1294 mDNSu8
*ptr
= pkt
.msg
.data
;
1295 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1298 PktMsg
*reply
= NULL
;
1300 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, buf
));
1302 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1304 ptr
= putZone(&pkt
.msg
, ptr
, end
, zname
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
1306 ptr
= putDeletionRecord(&pkt
.msg
, ptr
, &rr
->resrec
);
1311 zone
= FindZone( d
, zname
);
1313 if ( zone
&& zone
->updateKeys
)
1315 DNSDigest_SignMessage(&pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1319 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1320 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1321 pkt
.src
.sin_family
= AF_INET
;
1322 if (SendPacket( sock
, &pkt
)) { Log("DeleteOneRecord: SendPacket failed"); }
1323 reply
= RecvPacket( sock
, NULL
, &closed
);
1324 if (reply
) HdrNToH(reply
);
1325 require_action( reply
, end
, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
1327 if (!SuccessfulUpdateTransaction(&pkt
, reply
))
1328 Log("Expiration update failed with rcode %d", reply
? reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
: -1);
1331 if (!ptr
) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1332 if (reply
) free(reply
);
1335 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1336 mDNSlocal
void DeleteRecords(DaemonInfo
*d
, mDNSBool DeleteAll
)
1340 TCPSocket
*sock
= ConnectToServer(d
);
1341 if (!sock
) { Log("DeleteRecords: ConnectToServer failed"); return; }
1342 if (gettimeofday(&now
, NULL
)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
1343 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
1345 for (i
= 0; i
< d
->nbuckets
; i
++)
1347 RRTableElem
**ptr
= &d
->table
[i
];
1350 if (DeleteAll
|| (*ptr
)->expire
- now
.tv_sec
< 0)
1353 // delete record from server
1354 DeleteOneRecord(d
, &(*ptr
)->rr
, &(*ptr
)->zone
, sock
);
1356 *ptr
= (*ptr
)->next
;
1360 else ptr
= &(*ptr
)->next
;
1363 pthread_mutex_unlock(&d
->tablelock
);
1364 mDNSPlatformTCPCloseConnection( sock
);
1368 // main update request handling
1371 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
1372 mDNSlocal
void UpdateLeaseTable(PktMsg
*pkt
, DaemonInfo
*d
, mDNSs32 lease
)
1375 LargeCacheRecord lcr
;
1376 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1377 const mDNSu8
*ptr
, *end
;
1382 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
1384 ptr
= pkt
->msg
.data
;
1385 end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
1386 ptr
= getQuestion(&pkt
->msg
, ptr
, end
, 0, &zone
);
1387 if (!ptr
) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup
; }
1388 ptr
= LocateAuthorities(&pkt
->msg
, end
);
1389 if (!ptr
) { Log("UpdateLeaseTable: Format error"); goto cleanup
; }
1391 for (i
= 0; i
< pkt
->msg
.h
.mDNS_numUpdates
; i
++)
1393 mDNSBool DeleteAllRRSets
= mDNSfalse
, DeleteOneRRSet
= mDNSfalse
, DeleteOneRR
= mDNSfalse
;
1395 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1396 if (!ptr
|| lcr
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
) { Log("UpdateLeaseTable: GetLargeResourceRecord failed"); goto cleanup
; }
1397 int bucket
= rr
->namehash
% d
->nbuckets
;
1398 RRTableElem
*tmp
, **rptr
= &d
->table
[bucket
];
1401 if (rr
->rrtype
== kDNSQType_ANY
&& !rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1402 DeleteAllRRSets
= mDNStrue
; // delete all rrsets for a name
1403 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1404 DeleteOneRRSet
= mDNStrue
;
1405 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSClass_NONE
)
1406 DeleteOneRR
= mDNStrue
;
1408 if (DeleteAllRRSets
|| DeleteOneRRSet
|| DeleteOneRR
)
1412 if (SameDomainName((*rptr
)->rr
.resrec
.name
, rr
->name
) &&
1414 (DeleteOneRRSet
&& (*rptr
)->rr
.resrec
.rrtype
== rr
->rrtype
) ||
1415 (DeleteOneRR
&& IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
))))
1418 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp
->rr
.resrec
, &tmp
->rr
.resrec
.rdata
->u
, buf
));
1419 *rptr
= (*rptr
)->next
;
1423 else rptr
= &(*rptr
)->next
;
1428 // see if add or refresh
1429 while (*rptr
&& !IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
)) rptr
= &(*rptr
)->next
;
1433 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1434 (*rptr
)->expire
= tv
.tv_sec
+ (unsigned)lease
;
1435 VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1439 // New record - add to table
1440 if (d
->nelems
> d
->nbuckets
)
1443 bucket
= rr
->namehash
% d
->nbuckets
;
1445 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1446 allocsize
= sizeof(RRTableElem
);
1447 if (rr
->rdlength
> InlineCacheRDSize
) allocsize
+= (rr
->rdlength
- InlineCacheRDSize
);
1448 tmp
= malloc(allocsize
);
1449 if (!tmp
) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup
; }
1450 memcpy(&tmp
->rr
, &lcr
.r
, sizeof(CacheRecord
) + rr
->rdlength
- InlineCacheRDSize
);
1451 tmp
->rr
.resrec
.rdata
= (RData
*)&tmp
->rr
.smallrdatastorage
;
1452 AssignDomainName(&tmp
->name
, rr
->name
);
1453 tmp
->rr
.resrec
.name
= &tmp
->name
;
1454 tmp
->expire
= tv
.tv_sec
+ (unsigned)lease
;
1455 tmp
->cli
.sin_addr
= pkt
->src
.sin_addr
;
1456 AssignDomainName(&tmp
->zone
, &zone
.qname
);
1457 tmp
->next
= d
->table
[bucket
];
1458 d
->table
[bucket
] = tmp
;
1460 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1466 pthread_mutex_unlock(&d
->tablelock
);
1470 // Given a successful reply from a server, create a new reply that contains lease information
1471 // Replies are currently not signed !!!KRS change this
1472 mDNSlocal PktMsg
*FormatLeaseReply(DaemonInfo
*d
, PktMsg
*orig
, mDNSu32 lease
)
1474 PktMsg
*const reply
= malloc(sizeof(*reply
));
1479 if (!reply
) { LogErr("FormatLeaseReply", "malloc"); return NULL
; }
1480 flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
1483 InitializeDNSMessage(&reply
->msg
.h
, orig
->msg
.h
.id
, flags
);
1484 reply
->src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // unused except for log messages
1485 reply
->src
.sin_family
= AF_INET
;
1486 ptr
= putUpdateLease(&reply
->msg
, reply
->msg
.data
, lease
);
1487 if (!ptr
) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply
); return NULL
; }
1488 reply
->len
= ptr
- (mDNSu8
*)&reply
->msg
;
1494 // pkt is thread-local, not requiring locking
1503 PktMsg
* reply
= NULL
;
1504 PktMsg
* leaseReply
;
1507 TCPSocket
* sock
= NULL
;
1511 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == kDNSFlag0_OP_Update
)
1513 int i
, adds
= 0, dels
= 0;
1514 const mDNSu8
*ptr
, *end
= (mDNSu8
*)&request
->msg
+ request
->len
;
1516 gotlease
= GetPktLease(&mDNSStorage
, &request
->msg
, end
, &lease
);
1517 ptr
= LocateAuthorities(&request
->msg
, end
);
1518 for (i
= 0; i
< request
->msg
.h
.mDNS_numUpdates
; i
++)
1520 LargeCacheRecord lcr
;
1521 ptr
= GetLargeResourceRecord(NULL
, &request
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1522 if (lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& lcr
.r
.resrec
.rroriginalttl
) adds
++;else dels
++;
1525 if (adds
&& !gotlease
)
1527 static const mDNSOpaque16 UpdateRefused
= { { kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
, kDNSFlag1_RC_Refused
} };
1528 Log("Rejecting Update Request with %d additions but no lease", adds
);
1529 reply
= malloc(sizeof(*reply
));
1530 mDNSPlatformMemZero(&reply
->src
, sizeof(reply
->src
));
1531 reply
->len
= sizeof(DNSMessageHeader
);
1533 reply
->isZonePublic
= 0;
1534 InitializeDNSMessage(&reply
->msg
.h
, request
->msg
.h
.id
, UpdateRefused
);
1537 if (lease
> 7200) // Don't allow lease greater than two hours; typically 90-minute renewal period
1540 // Send msg to server, read reply
1542 if ( request
->len
<= 512 )
1546 if ( UDPServerTransaction( self
, request
, &buf
, &trunc
) < 0 )
1548 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1552 VLog("HandleRequest - answer truncated. Using TCP");
1556 reply
= &buf
; // success
1565 sock
= ConnectToServer( self
);
1566 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 ) ) );
1568 res
= SendPacket( sock
, request
);
1569 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 ) ) );
1571 reply
= RecvPacket( sock
, &buf
, &closed
);
1574 // IMPORTANT: reply is in network byte order at this point in the code
1575 // We keep it this way because we send it back to the client in the same form
1579 if ( reply
&& ( ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
) ) )
1582 mDNSBool ok
= SuccessfulUpdateTransaction( request
, reply
);
1583 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 ) ) );
1585 UpdateLeaseTable( request
, self
, lease
);
1589 leaseReply
= FormatLeaseReply( self
, reply
, lease
);
1593 Log("HandleRequest - unable to format lease reply");
1596 // %%% Looks like a potential memory leak -- who frees the original reply?
1600 // tell the main thread there was an update so it can send LLQs
1602 if ( send( self
->LLQEventNotifySock
, pingmsg
, sizeof( pingmsg
), 0 ) != sizeof( pingmsg
) )
1604 LogErr("HandleRequest", "send");
1612 mDNSPlatformTCPCloseConnection( sock
);
1615 if ( reply
== &buf
)
1617 reply
= malloc( sizeof( *reply
) );
1621 reply
->len
= buf
.len
;
1622 memcpy(&reply
->msg
, &buf
.msg
, buf
.len
);
1626 LogErr("HandleRequest", "malloc");
1635 // LLQ Support Routines
1638 // Set fields of an LLQ OPT Resource Record
1639 mDNSlocal
void FormatLLQOpt(AuthRecord
*opt
, int opcode
, const mDNSOpaque64
*const id
, mDNSs32 lease
)
1641 mDNSPlatformMemZero(opt
, sizeof(*opt
));
1642 mDNS_SetupResourceRecord(opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, AuthRecordAny
, mDNSNULL
, mDNSNULL
);
1643 opt
->resrec
.rrclass
= NormalMaxDNSMessageData
;
1644 opt
->resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
1645 opt
->resrec
.rdestimate
= sizeof(rdataOPT
);
1646 opt
->resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_LLQ
;
1647 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.vers
= kLLQ_Vers
;
1648 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.llqOp
= opcode
;
1649 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.err
= LLQErr_NoError
;
1650 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.id
= *id
;
1651 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.llqlease
= lease
;
1654 // Calculate effective remaining lease of an LLQ
1655 mDNSlocal mDNSu32
LLQLease(LLQEntry
*e
)
1659 gettimeofday(&t
, NULL
);
1660 if (e
->expire
< t
.tv_sec
) return 0;
1661 else return e
->expire
- t
.tv_sec
;
1664 mDNSlocal
void DeleteLLQ(DaemonInfo
*d
, LLQEntry
*e
)
1666 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
1667 LLQEntry
**ptr
= &d
->LLQTable
[bucket
];
1668 AnswerListElem
*a
= e
->AnswerList
;
1671 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1672 VLog("Deleting LLQ table entry for %##s client %s", e
->qname
.c
, addr
);
1674 if (a
&& !(--a
->refcount
) && d
->AnswerTableCount
>= LLQ_TABLESIZE
)
1676 // currently, generating initial answers blocks the main thread, so we keep the answer list
1677 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1678 // if the ref count drops to zero AND there are more table elements than buckets
1679 // !!!KRS update this when we make the table dynamically growable
1681 CacheRecord
*cr
= a
->KnownAnswers
, *tmp
;
1682 AnswerListElem
**tbl
= &d
->AnswerTable
[bucket
];
1691 while (*tbl
&& *tbl
!= a
) tbl
= &(*tbl
)->next
;
1692 if (*tbl
) { *tbl
= (*tbl
)->next
; free(a
); d
->AnswerTableCount
--; }
1693 else Log("Error: DeleteLLQ - AnswerList not found in table");
1696 // remove LLQ from table, free memory
1697 while(*ptr
&& *ptr
!= e
) ptr
= &(*ptr
)->next
;
1698 if (!*ptr
) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1699 *ptr
= (*ptr
)->next
;
1703 mDNSlocal
int SendLLQ(DaemonInfo
*d
, PktMsg
*pkt
, struct sockaddr_in dst
, TCPSocket
*sock
)
1712 if ( SendPacket( sock
, pkt
) != 0 )
1714 LogErr("DaemonInfo", "MySend");
1715 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1720 if (sendto(d
->llq_udpsd
, &pkt
->msg
, pkt
->len
, 0, (struct sockaddr
*)&dst
, sizeof(dst
)) != (int)pkt
->len
)
1722 LogErr("DaemonInfo", "sendto");
1723 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1732 mDNSlocal CacheRecord
*AnswerQuestion(DaemonInfo
*d
, AnswerListElem
*e
)
1736 TCPSocket
*sock
= NULL
;
1737 const mDNSu8
*ansptr
;
1738 mDNSu8
*end
= q
.msg
.data
;
1739 PktMsg buf
, *reply
= NULL
;
1740 LargeCacheRecord lcr
;
1741 CacheRecord
*AnswerList
= NULL
;
1744 VLog("Querying server for %##s type %d", e
->name
.c
, e
->type
);
1746 InitializeDNSMessage(&q
.msg
.h
, zeroID
, uQueryFlags
);
1748 end
= putQuestion(&q
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->name
, e
->type
, kDNSClass_IN
);
1749 if (!end
) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end
; }
1750 q
.len
= (int)(end
- (mDNSu8
*)&q
.msg
);
1758 if (UDPServerTransaction(d
, &q
, &buf
, &trunc
) < 0)
1759 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e
->name
.c
);
1761 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e
->name
.c
); e
->UseTCP
= mDNStrue
; }
1762 else reply
= &buf
; // success
1769 sock
= ConnectToServer(d
);
1770 if (!sock
) { Log("AnswerQuestion: ConnectToServer failed"); goto end
; }
1771 if (SendPacket( sock
, &q
)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock
); goto end
; }
1772 reply
= RecvPacket( sock
, NULL
, &closed
);
1773 mDNSPlatformTCPCloseConnection( sock
);
1774 require_action( reply
, end
, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1778 if (reply
) HdrNToH(reply
);
1780 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
))
1781 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end
; }
1782 rcode
= (mDNSu8
)(reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1783 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
; }
1785 end
= (mDNSu8
*)&reply
->msg
+ reply
->len
;
1786 ansptr
= LocateAnswers(&reply
->msg
, end
);
1787 if (!ansptr
) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end
; }
1789 for (i
= 0; i
< reply
->msg
.h
.numAnswers
; i
++)
1791 ansptr
= GetLargeResourceRecord(NULL
, &reply
->msg
, ansptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1792 if (!ansptr
) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end
; }
1793 if (lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
)
1795 if (lcr
.r
.resrec
.rrtype
!= e
->type
|| lcr
.r
.resrec
.rrclass
!= kDNSClass_IN
|| !SameDomainName(lcr
.r
.resrec
.name
, &e
->name
))
1797 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1798 lcr
.r
.resrec
.name
->c
, lcr
.r
.resrec
.rrtype
, e
->name
.c
, e
->type
);
1802 CacheRecord
*cr
= CopyCacheRecord(&lcr
.r
, &e
->name
);
1803 if (!cr
) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end
; }
1804 cr
->next
= AnswerList
;
1811 if (reply
&& reply
!= &buf
) free(reply
);
1815 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1816 mDNSlocal
void *UpdateAnswerList(void *args
)
1818 CacheRecord
*cr
, *NewAnswers
, **na
, **ka
; // "new answer", "known answer"
1819 DaemonInfo
*d
= ((UpdateAnswerListArgs
*)args
)->d
;
1820 AnswerListElem
*a
= ((UpdateAnswerListArgs
*)args
)->a
;
1825 // get up to date answers
1826 NewAnswers
= AnswerQuestion(d
, a
);
1828 // first pass - mark all answers for deletion
1829 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1830 (*ka
)->resrec
.rroriginalttl
= (unsigned)-1; // -1 means delete
1832 // second pass - mark answers pre-existent
1833 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1835 for (na
= &NewAnswers
; *na
; na
= &(*na
)->next
)
1837 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
))
1838 { (*ka
)->resrec
.rroriginalttl
= 0; break; } // 0 means no change
1842 // third pass - add new records to Event list
1846 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1847 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
)) break;
1850 // answer is not in list - splice from NewAnswers list, add to Event list
1852 *na
= (*na
)->next
; // splice from list
1853 cr
->next
= a
->EventList
; // add spliced record to event list
1855 cr
->resrec
.rroriginalttl
= 1; // 1 means add
1857 else na
= &(*na
)->next
;
1860 // move all the removes from the answer list to the event list
1861 ka
= &a
->KnownAnswers
;
1864 if ((*ka
)->resrec
.rroriginalttl
== (unsigned)-1)
1868 cr
->next
= a
->EventList
;
1871 else ka
= &(*ka
)->next
;
1874 // lastly, free the remaining records (known answers) in NewAnswers list
1878 NewAnswers
= NewAnswers
->next
;
1885 mDNSlocal
void SendEvents(DaemonInfo
*d
, LLQEntry
*e
)
1889 mDNSu8
*end
= (mDNSu8
*)&response
.msg
.data
;
1891 char rrbuf
[MaxMsg
], addrbuf
[32];
1894 // Should this really be random? Do we use the msgID on the receiving end?
1895 msgID
.NotAnInteger
= random();
1896 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
1897 InitializeDNSMessage(&response
.msg
.h
, msgID
, ResponseFlags
);
1898 end
= putQuestion(&response
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
1899 if (!end
) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
1901 // put adds/removes in packet
1902 for (cr
= e
->AnswerList
->EventList
; cr
; cr
= cr
->next
)
1904 if (verbose
) GetRRDisplayString_rdb(&cr
->resrec
, &cr
->resrec
.rdata
->u
, rrbuf
);
1905 VLog("%s (%s): %s", addrbuf
, (mDNSs32
)cr
->resrec
.rroriginalttl
< 0 ? "Remove" : "Add", rrbuf
);
1906 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAnswers
, &cr
->resrec
, cr
->resrec
.rroriginalttl
);
1907 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
1910 FormatLLQOpt(&opt
, kLLQOp_Event
, &e
->id
, LLQLease(e
));
1911 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
1912 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
1914 response
.len
= (int)(end
- (mDNSu8
*)&response
.msg
);
1915 if (SendLLQ(d
, &response
, e
->cli
, NULL
) < 0) LogMsg("Error: SendEvents - SendLLQ");
1918 mDNSlocal
void PrintLLQAnswers(DaemonInfo
*d
)
1923 Log("Printing LLQ Answer Table contents");
1925 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1927 AnswerListElem
*a
= d
->AnswerTable
[i
];
1931 const CacheRecord
*rr
= a
->KnownAnswers
;
1932 while (rr
) { ancount
++; rr
= rr
->next
; }
1933 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a
, a
->name
.c
, a
->type
, a
->refcount
, ancount
);
1934 for (rr
= a
->KnownAnswers
; rr
; rr
= rr
->next
) Log("\t%s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, rrbuf
));
1940 mDNSlocal
void PrintLLQTable(DaemonInfo
*d
)
1946 Log("Printing LLQ table contents");
1948 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1957 case RequestReceived
: state
= "RequestReceived"; break;
1958 case ChallengeSent
: state
= "ChallengeSent"; break;
1959 case Established
: state
= "Established"; break;
1960 default: state
= "unknown";
1962 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1964 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
1965 addr
, state
, e
->qname
.c
, e
->qtype
, e
->lease
, LLQLease(e
), e
->AnswerList
);
1971 // Send events to clients as a result of a change in the zone
1972 mDNSlocal
void GenLLQEvents(DaemonInfo
*d
)
1977 UpdateAnswerListArgs
*args
;
1979 VLog("Generating LLQ Events");
1981 gettimeofday(&t
, NULL
);
1983 // get all answers up to date
1984 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1986 AnswerListElem
*a
= d
->AnswerTable
[i
];
1989 args
= malloc(sizeof(*args
));
1990 if (!args
) { LogErr("GenLLQEvents", "malloc"); return; }
1993 if (pthread_create(&a
->tid
, NULL
, UpdateAnswerList
, args
) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
1999 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2001 AnswerListElem
*a
= d
->AnswerTable
[i
];
2004 if (pthread_join(a
->tid
, NULL
)) LogErr("GenLLQEvents", "pthread_join");
2009 // for each established LLQ, send events
2010 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2012 e
= &d
->LLQTable
[i
];
2015 if ((*e
)->expire
< t
.tv_sec
) DeleteLLQ(d
, *e
);
2018 if ((*e
)->state
== Established
&& (*e
)->AnswerList
->EventList
) SendEvents(d
, *e
);
2024 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2025 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2027 AnswerListElem
*a
= d
->AnswerTable
[i
];
2032 CacheRecord
*cr
= a
->EventList
, *tmp
;
2037 if ((signed)tmp
->resrec
.rroriginalttl
< 0) free(tmp
);
2040 tmp
->next
= a
->KnownAnswers
;
2041 a
->KnownAnswers
= tmp
;
2042 tmp
->resrec
.rroriginalttl
= 0;
2045 a
->EventList
= NULL
;
2052 mDNSlocal
void SetAnswerList(DaemonInfo
*d
, LLQEntry
*e
)
2054 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
2055 AnswerListElem
*a
= d
->AnswerTable
[bucket
];
2056 while (a
&& (a
->type
!= e
->qtype
||!SameDomainName(&a
->name
, &e
->qname
))) a
= a
->next
;
2059 a
= malloc(sizeof(*a
));
2060 if (!a
) { LogErr("SetAnswerList", "malloc"); return; }
2061 AssignDomainName(&a
->name
, &e
->qname
);
2064 a
->EventList
= NULL
;
2065 a
->UseTCP
= mDNSfalse
;
2066 a
->next
= d
->AnswerTable
[bucket
];
2067 d
->AnswerTable
[bucket
] = a
;
2068 d
->AnswerTableCount
++;
2069 a
->KnownAnswers
= AnswerQuestion(d
, a
);
2076 // Allocate LLQ entry, insert into table
2077 mDNSlocal LLQEntry
*NewLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, mDNSu32 lease
)
2081 int bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2084 e
= malloc(sizeof(*e
));
2085 if (!e
) { LogErr("NewLLQ", "malloc"); return NULL
; }
2087 inet_ntop(AF_INET
, &cli
.sin_addr
, addr
, 32);
2088 VLog("Allocating LLQ entry for client %s question %##s type %d", addr
, qname
->c
, qtype
);
2090 // initialize structure
2092 AssignDomainName(&e
->qname
, qname
);
2094 e
->id
= zeroOpaque64
;
2095 e
->state
= RequestReceived
;
2096 e
->AnswerList
= NULL
;
2098 if (lease
< LLQ_MIN_LEASE
) lease
= LLQ_MIN_LEASE
;
2099 else if (lease
> LLQ_MAX_LEASE
) lease
= LLQ_MAX_LEASE
;
2101 gettimeofday(&t
, NULL
);
2102 e
->expire
= t
.tv_sec
+ (int)lease
;
2106 e
->next
= d
->LLQTable
[bucket
];
2107 d
->LLQTable
[bucket
] = e
;
2112 // Handle a refresh request from client
2113 mDNSlocal
void LLQRefresh(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2117 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2120 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2121 VLog("%s LLQ for %##s from %s", llq
->llqlease
? "Refreshing" : "Deleting", e
->qname
.c
, addr
);
2126 if (llq
->llqlease
< LLQ_MIN_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2127 else if (llq
->llqlease
> LLQ_MAX_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2128 gettimeofday(&t
, NULL
);
2129 e
->expire
= t
.tv_sec
+ llq
->llqlease
;
2132 ack
.src
.sin_addr
.s_addr
= 0; // unused
2133 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2134 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2135 if (!end
) { Log("Error: putQuestion"); return; }
2137 FormatLLQOpt(&opt
, kLLQOp_Refresh
, &e
->id
, llq
->llqlease
? LLQLease(e
) : 0);
2138 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2139 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2141 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2142 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQRefresh");
2144 if (llq
->llqlease
) e
->state
= Established
;
2145 else DeleteLLQ(d
, e
);
2148 // Complete handshake with Ack an initial answers
2149 mDNSlocal
void LLQCompleteHandshake(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2155 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2156 char rrbuf
[MaxMsg
], addrbuf
[32];
2158 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2160 if (!mDNSSameOpaque64(&llq
->id
, &e
->id
) ||
2161 llq
->vers
!= kLLQ_Vers
||
2162 llq
->llqOp
!= kLLQOp_Setup
||
2163 llq
->err
!= LLQErr_NoError
||
2164 llq
->llqlease
> e
->lease
+ LLQ_LEASE_FUDGE
||
2165 llq
->llqlease
< e
->lease
- LLQ_LEASE_FUDGE
)
2167 Log("Incorrect challenge response from %s", addr
);
2171 if (e
->state
== Established
) VLog("Retransmitting LLQ ack + answers for %##s", e
->qname
.c
);
2172 else VLog("Delivering LLQ ack + answers for %##s", e
->qname
.c
);
2174 // format ack + answers
2175 ack
.src
.sin_addr
.s_addr
= 0; // unused
2176 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2177 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2178 if (!end
) { Log("Error: putQuestion"); return; }
2180 if (e
->state
!= Established
) { SetAnswerList(d
, e
); e
->state
= Established
; }
2182 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2183 for (ptr
= e
->AnswerList
->KnownAnswers
; ptr
; ptr
= ptr
->next
)
2185 if (verbose
) GetRRDisplayString_rdb(&ptr
->resrec
, &ptr
->resrec
.rdata
->u
, rrbuf
);
2186 VLog("%s Intitial Answer - %s", addr
, rrbuf
);
2187 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAnswers
, &ptr
->resrec
, 1);
2188 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2191 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2192 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2193 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2195 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2196 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQCompleteHandshake");
2199 mDNSlocal
void LLQSetupChallenge(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
)
2203 mDNSu8
*end
= challenge
.msg
.data
;
2206 if (e
->state
== ChallengeSent
) VLog("Retransmitting LLQ setup challenge for %##s", e
->qname
.c
);
2207 else VLog("Sending LLQ setup challenge for %##s", e
->qname
.c
);
2209 if (!mDNSOpaque64IsZero(&llq
->id
)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2210 if (llq
->llqOp
!= kLLQOp_Setup
) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2212 if (mDNSOpaque64IsZero(&e
->id
)) // don't regenerate random ID for retransmissions
2214 // construct ID <time><random>
2215 gettimeofday(&t
, NULL
);
2216 e
->id
.l
[0] = t
.tv_sec
;
2217 e
->id
.l
[1] = random();
2220 // format response (query + LLQ opt rr)
2221 challenge
.src
.sin_addr
.s_addr
= 0; // unused
2222 InitializeDNSMessage(&challenge
.msg
.h
, msgID
, ResponseFlags
);
2223 end
= putQuestion(&challenge
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2224 if (!end
) { Log("Error: putQuestion"); return; }
2225 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2226 end
= PutResourceRecordTTLJumbo(&challenge
.msg
, end
, &challenge
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2227 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2228 challenge
.len
= (int)(end
- (mDNSu8
*)&challenge
.msg
);
2229 if (SendLLQ(d
, &challenge
, e
->cli
, NULL
)) { Log("Error: LLQSetupChallenge"); return; }
2230 e
->state
= ChallengeSent
;
2233 // Take action on an LLQ message from client. Entry must be initialized and in table
2234 mDNSlocal
void UpdateLLQ(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2238 case RequestReceived
:
2242 gettimeofday(&t
, NULL
);
2243 e
->id
.l
[0] = t
.tv_sec
; // construct ID <time><random>
2244 e
->id
.l
[1] = random();
2246 LLQCompleteHandshake( d
, e
, llq
, msgID
, sock
);
2248 // Set the state to established because we've just set the LLQ up using TCP
2249 e
->state
= Established
;
2253 LLQSetupChallenge(d
, e
, llq
, msgID
);
2257 if (mDNSOpaque64IsZero(&llq
->id
)) LLQSetupChallenge(d
, e
, llq
, msgID
); // challenge sent and lost
2258 else LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
);
2261 if (mDNSOpaque64IsZero(&llq
->id
))
2263 // client started over. reset state.
2264 LLQEntry
*newe
= NewLLQ(d
, e
->cli
, &e
->qname
, e
->qtype
, llq
->llqlease
);
2267 LLQSetupChallenge(d
, newe
, llq
, msgID
);
2270 else if (llq
->llqOp
== kLLQOp_Setup
)
2271 { LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
); return; } // Ack lost
2272 else if (llq
->llqOp
== kLLQOp_Refresh
)
2273 { LLQRefresh(d
, e
, llq
, msgID
, sock
); return; }
2274 else { Log("Unhandled message for established LLQ"); return; }
2278 mDNSlocal LLQEntry
*LookupLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, const mDNSOpaque64
*const id
)
2280 int bucket
= bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2281 LLQEntry
*ptr
= d
->LLQTable
[bucket
];
2285 if (((ptr
->state
== ChallengeSent
&& mDNSOpaque64IsZero(id
) && (cli
.sin_port
== ptr
->cli
.sin_port
)) || // zero-id due to packet loss OK in state ChallengeSent
2286 mDNSSameOpaque64(id
, &ptr
->id
)) && // id match
2287 (cli
.sin_addr
.s_addr
== ptr
->cli
.sin_addr
.s_addr
) && (qtype
== ptr
->qtype
) && SameDomainName(&ptr
->qname
, qname
)) // same source, type, qname
2304 pkt
->msg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
2306 res
= sendto( d
->udpsd
, &pkt
->msg
, pkt
->len
, 0, ( struct sockaddr
* ) &pkt
->src
, sizeof( pkt
->src
) );
2307 require_action( res
== ( int ) pkt
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvNotify", "sendto" ) );
2315 mDNSlocal
int RecvLLQ( DaemonInfo
*d
, PktMsg
*pkt
, TCPSocket
*sock
)
2318 LargeCacheRecord opt
;
2321 const mDNSu8
*qptr
= pkt
->msg
.data
;
2322 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2324 LLQOptData
*llq
= NULL
;
2328 aptr
= LocateAdditionals(&pkt
->msg
, end
); // Can't do this until after HdrNToH(pkt);
2329 inet_ntop(AF_INET
, &pkt
->src
.sin_addr
, addr
, 32);
2331 VLog("Received LLQ msg from %s", addr
);
2332 // sanity-check packet
2333 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2335 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
2339 // Locate the OPT record.
2340 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2341 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2342 // but not necessarily the *last* entry in the Additional Section.
2343 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2345 aptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, aptr
, end
, 0, kDNSRecordTypePacketAdd
, &opt
);
2346 if (!aptr
) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr
, i
); goto end
; }
2347 if (opt
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& opt
.r
.resrec
.rrtype
== kDNSType_OPT
) break;
2351 if (opt
.r
.resrec
.rrtype
!= kDNSType_OPT
) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr
); goto end
; }
2352 if (opt
.r
.resrec
.rdlength
< pkt
->msg
.h
.numQuestions
* DNSOpt_LLQData_Space
) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr
, opt
.r
.resrec
.rdlength
, pkt
->msg
.h
.numQuestions
); }
2354 // dispatch each question
2355 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
2357 qptr
= getQuestion(&pkt
->msg
, qptr
, end
, 0, &q
);
2358 if (!qptr
) { Log("Malformatted LLQ from %s: cannot read question %d", addr
, i
); goto end
; }
2359 llq
= &opt
.r
.resrec
.rdata
->u
.opt
[i
].u
.llq
; // point into OptData at index i
2360 if (llq
->vers
!= kLLQ_Vers
) { Log("LLQ from %s contains bad version %d (expected %d)", addr
, llq
->vers
, kLLQ_Vers
); goto end
; }
2362 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2365 // no entry - if zero ID, create new
2366 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2369 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2379 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
2381 const mDNSu8
* lastPtr
= NULL
;
2382 const mDNSu8
* ptr
= NULL
;
2383 DomainAuthInfo
* keys
;
2384 mDNSu8
* end
= ( mDNSu8
* ) &pkt
->msg
+ pkt
->len
;
2385 LargeCacheRecord lcr
;
2386 mDNSBool hasTSIG
= mDNSfalse
;
2387 mDNSBool strip
= mDNSfalse
;
2388 mDNSBool ok
= mDNSfalse
;
2391 // Unused parameters
2398 bzero(&lcr
, sizeof(lcr
));
2400 if ( pkt
->msg
.h
.numAdditionals
)
2402 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2405 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2408 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2411 Log("Unable to read additional record");
2417 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2421 LogMsg( "IsAuthorized: unable to find Additional section" );
2425 // If we don't know what zone this is, then it's authorized.
2434 if ( IsQuery( pkt
) )
2436 keys
= pkt
->zone
->queryKeys
;
2439 else if ( IsUpdate( pkt
) )
2441 keys
= pkt
->zone
->updateKeys
;
2451 if ( pkt
->isZonePublic
)
2457 // If there are no keys, then we're authorized
2459 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
2461 Log( "Invalid TSIG spec %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2462 *rcode
= kDNSFlag1_RC_NotAuth
;
2463 *tcode
= TSIG_ErrBadKey
;
2469 // Find the right key
2471 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2473 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
2481 Log( "Invalid TSIG name %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2482 *rcode
= kDNSFlag1_RC_NotAuth
;
2483 *tcode
= TSIG_ErrBadKey
;
2489 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2490 // lifting of message verification
2492 pkt
->msg
.h
.numAdditionals
--;
2496 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2500 pkt
->msg
.h
.numAdditionals
++;
2504 if ( hasTSIG
&& strip
)
2506 // Strip the TSIG from the message
2508 pkt
->msg
.h
.numAdditionals
--;
2509 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2517 // request handler wrappers for TCP and UDP requests
2518 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2526 UDPContext
* context
= ( UDPContext
* ) vptr
;
2527 PktMsg
* reply
= NULL
;
2531 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2532 // may give us a long answer that would require truncation for UDP delivery to client
2534 reply
= HandleRequest( context
->d
, &context
->pkt
);
2535 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
2537 res
= sendto( context
->sd
, &reply
->msg
, reply
->len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2538 require_action_quiet( res
== ( int ) reply
->len
, exit
, LogErr( "UDPMessageHandler", "sendto" ) );
2549 pthread_exit( NULL
);
2562 UDPContext
* context
= NULL
;
2566 DomainAuthInfo
* key
;
2567 unsigned int clisize
= sizeof( context
->cliaddr
);
2569 mStatus err
= mStatus_NoError
;
2571 context
= malloc( sizeof( UDPContext
) );
2572 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2574 mDNSPlatformMemZero( context
, sizeof( *context
) );
2578 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
2580 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvUDPMessage", "recvfrom" ) );
2581 context
->pkt
.len
= res
;
2582 require_action( clisize
== sizeof( context
->cliaddr
), exit
, err
= mStatus_UnknownErr
; Log( "Client address of unknown size %d", clisize
) );
2583 context
->pkt
.src
= context
->cliaddr
;
2585 // Set the zone in the packet
2587 SetZone( context
->d
, &context
->pkt
);
2589 // Notify messages handled by main thread
2591 if ( IsNotify( &context
->pkt
) )
2593 int e
= RecvNotify( self
, &context
->pkt
);
2597 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2599 if ( IsLLQRequest( &context
->pkt
) )
2601 // LLQ messages handled by main thread
2602 int e
= RecvLLQ( self
, &context
->pkt
, NULL
);
2607 if ( IsLLQAck(&context
->pkt
) )
2609 // !!!KRS need to do acks + retrans
2615 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2616 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2618 pthread_detach(tid
);
2625 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2627 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2628 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_NXDomain
;
2630 e
= sendto( sd
, &reply
.msg
, reply
.len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2631 require_action_quiet( e
== ( int ) reply
.len
, exit
, LogErr( "RecvUDPMessage", "sendto" ) );
2633 err
= mStatus_NoAuth
;
2638 if ( err
&& context
)
2650 TCPContext
* context
2655 if ( context
->sock
)
2657 mDNSPlatformTCPCloseConnection( context
->sock
);
2671 TCPContext
* context
= ( TCPContext
* ) vptr
;
2672 PktMsg
* reply
= NULL
;
2676 //!!!KRS if this read blocks indefinitely, we can run out of threads
2679 reply
= HandleRequest( context
->d
, &context
->pkt
);
2680 require_action_quiet( reply
, exit
, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2682 // deliver reply to client
2684 res
= SendPacket( context
->sock
, reply
);
2685 require_action( res
>= 0, exit
, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2689 FreeTCPContext( context
);
2706 TCPContext
* context
= ( TCPContext
* ) param
;
2710 DomainAuthInfo
* key
;
2713 mDNSBool freeContext
= mDNStrue
;
2714 mStatus err
= mStatus_NoError
;
2716 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2717 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2718 // wire. We'll let it do that, and wait for the next packet which will be ours.
2720 pkt
= RecvPacket( context
->sock
, &context
->pkt
, &closed
);
2721 if (pkt
) HdrNToH(pkt
);
2722 require_action( pkt
|| !closed
, exit
, err
= mStatus_UnknownErr
; LogMsg( "client disconnected" ) );
2726 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2727 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2728 // are sent over UDP
2730 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2732 // Set's the DNS Zone that is associated with this message
2734 SetZone( context
->d
, &context
->pkt
);
2736 // IsAuthorized will make sure the message is authorized for the designated zone.
2737 // After verifying the signature, it will strip the TSIG from the message
2739 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2741 if ( IsLLQRequest( &context
->pkt
) )
2743 // LLQ messages handled by main thread
2744 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2748 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2752 LogErr( "RecvTCPMessage", "pthread_create" );
2753 err
= mStatus_NoError
;
2757 // Let the thread free the context
2759 freeContext
= mDNSfalse
;
2761 pthread_detach(tid
);
2768 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2770 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2772 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2773 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_Refused
;
2775 SendPacket( context
->sock
, &reply
);
2780 freeContext
= mDNSfalse
;
2787 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2792 FreeTCPContext( context
);
2802 TCPSocketFlags flags
2805 TCPContext
* context
= NULL
;
2806 unsigned int clilen
= sizeof( context
->cliaddr
);
2808 mStatus err
= mStatus_NoError
;
2810 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2811 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2812 mDNSPlatformMemZero( context
, sizeof( sizeof( TCPContext
) ) );
2814 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2815 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2817 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2818 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2820 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2821 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2825 if ( err
&& context
)
2836 // listen for incoming requests, periodically check table for expired records, respond to signals
2837 mDNSlocal
int Run(DaemonInfo
*d
)
2839 int staticMaxFD
, nfds
;
2841 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
2842 mDNSBool EventsPending
= mDNSfalse
;
2844 VLog("Listening for requests...");
2848 if ( d
->tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tcpsd
+ 1;
2849 if ( d
->udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->udpsd
+ 1;
2850 if ( d
->tlssd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tlssd
+ 1;
2851 if ( d
->llq_tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_tcpsd
+ 1;
2852 if ( d
->llq_udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_udpsd
+ 1;
2853 if ( d
->LLQEventListenSock
+ 1 > staticMaxFD
) staticMaxFD
= d
->LLQEventListenSock
+ 1;
2857 EventSource
* source
;
2861 timeout
.tv_sec
= timeout
.tv_usec
= 0;
2862 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2866 if (timenow
.tv_sec
- EventTS
.tv_sec
>= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2867 { GenLLQEvents(d
); EventsPending
= mDNSfalse
; } // events, we go ahead and do it now
2868 else timeout
.tv_usec
= 500000; // else do events after 1/2 second with no new events or LLQs
2872 // if no pending events, timeout when we need to check for expired records
2873 if (tablecheck
.tv_sec
&& timenow
.tv_sec
- tablecheck
.tv_sec
>= 0)
2874 { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; } // table check overdue
2875 if (!tablecheck
.tv_sec
) tablecheck
.tv_sec
= timenow
.tv_sec
+ EXPIRATION_INTERVAL
;
2876 timeout
.tv_sec
= tablecheck
.tv_sec
- timenow
.tv_sec
;
2880 FD_SET( d
->tcpsd
, &rset
);
2881 FD_SET( d
->udpsd
, &rset
);
2882 FD_SET( d
->tlssd
, &rset
);
2883 FD_SET( d
->llq_tcpsd
, &rset
);
2884 FD_SET( d
->llq_udpsd
, &rset
);
2885 FD_SET( d
->LLQEventListenSock
, &rset
);
2887 maxFD
= staticMaxFD
;
2889 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2891 FD_SET( source
->fd
, &rset
);
2893 if ( source
->fd
> maxFD
)
2899 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
2906 // close sockets to prevent clients from making new requests during shutdown
2910 close( d
->llq_tcpsd
);
2911 close( d
->llq_udpsd
);
2912 d
->tcpsd
= d
->udpsd
= d
->tlssd
= d
->llq_tcpsd
= d
->llq_udpsd
= -1;
2913 DeleteRecords(d
, mDNStrue
);
2918 Log( "Received SIGINFO" );
2929 Log( "Received SIGHUP" );
2931 err
= ParseConfig( d
, cfgfile
);
2935 LogErr( "Run", "ParseConfig" );
2943 Log("Received unhandled signal - continuing");
2948 LogErr("Run", "select"); return -1;
2953 if (FD_ISSET(d
->udpsd
, &rset
)) RecvUDPMessage( d
, d
->udpsd
);
2954 if (FD_ISSET(d
->llq_udpsd
, &rset
)) RecvUDPMessage( d
, d
->llq_udpsd
);
2955 if (FD_ISSET(d
->tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->tcpsd
, 0 );
2956 if (FD_ISSET(d
->llq_tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->llq_tcpsd
, 0 );
2957 if (FD_ISSET(d
->tlssd
, &rset
)) AcceptTCPConnection( d
, d
->tlssd
, TCP_SOCKET_FLAGS
);
2958 if (FD_ISSET(d
->LLQEventListenSock
, &rset
))
2960 // clear signalling data off socket
2962 recv(d
->LLQEventListenSock
, buf
, 256, 0);
2965 EventsPending
= mDNStrue
;
2966 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2970 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2972 if ( FD_ISSET( source
->fd
, &rset
) )
2974 source
->callback( source
->context
);
2975 break; // in case we removed this guy from the event loop
2982 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
2983 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
2989 // signal handler sets global variables, which are inspected by main event loop
2990 // (select automatically returns due to the handled signal)
2991 mDNSlocal
void HndlSignal(int sig
)
2993 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
2994 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
2995 if (sig
== SIGHUP
) { hangup
= 1; return; }
3005 DNameListElem
* elem
;
3006 mStatus err
= mStatus_NoError
;
3008 elem
= ( DNameListElem
* ) malloc( sizeof( DNameListElem
) );
3009 require_action( elem
, exit
, err
= mStatus_NoMemoryErr
);
3010 MakeDomainNameFromDNSNameString( &elem
->name
, name
);
3011 elem
->next
= d
->public_names
;
3012 d
->public_names
= elem
;
3020 int main(int argc
, char *argv
[])
3022 int started_via_launchd
= 0;
3026 Log("dnsextd starting");
3028 d
= malloc(sizeof(*d
));
3029 if (!d
) { LogErr("main", "malloc"); exit(1); }
3030 mDNSPlatformMemZero(d
, sizeof(DaemonInfo
));
3032 // Setup the public SRV record names
3034 SetPublicSRV(d
, "_dns-update._udp.");
3035 SetPublicSRV(d
, "_dns-llq._udp.");
3036 SetPublicSRV(d
, "_dns-update-tls._tcp.");
3037 SetPublicSRV(d
, "_dns-query-tls._tcp.");
3038 SetPublicSRV(d
, "_dns-llq-tls._tcp.");
3040 // Setup signal handling
3042 if (signal(SIGHUP
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGHUP");
3043 if (signal(SIGTERM
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGTERM");
3044 if (signal(INFO_SIGNAL
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINFO");
3045 if (signal(SIGINT
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINT");
3046 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) perror("Can't ignore SIGPIPE");
3048 // remove open file limit
3049 rlim
.rlim_max
= RLIM_INFINITY
;
3050 rlim
.rlim_cur
= RLIM_INFINITY
;
3051 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3053 LogErr("main", "setrlimit");
3054 Log("Using default file descriptor resource limit");
3057 if (argc
> 1 && !strcasecmp(argv
[1], "-launchd"))
3059 Log("started_via_launchd");
3060 started_via_launchd
= 1;
3064 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3066 if (!foreground
&& !started_via_launchd
)
3070 LogErr("main", "daemon");
3075 if (InitLeaseTable(d
) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3076 if (SetupSockets(d
) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3077 if (SetUpdateSRV(d
) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3081 Log("dnsextd stopping");
3083 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3089 // These are stubbed out implementations of up-call routines that the various platform support layers
3090 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3091 // link this code in.
3093 // It's an error for these routines to actually be called, so perhaps we should log any call
3095 void mDNSCoreInitComplete( mDNS
* const m
, mStatus result
) { ( void ) m
; ( void ) result
; }
3096 void mDNS_ConfigChanged(mDNS
*const m
) { ( void ) m
; }
3097 void mDNSCoreMachineSleep(mDNS
* const m
, mDNSBool wake
) { ( void ) m
; ( void ) wake
; }
3098 void mDNSCoreReceive(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
3099 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
,
3100 const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID iid
)
3101 { ( void ) m
; ( void ) msg
; ( void ) end
; ( void ) srcaddr
; ( void ) srcport
; ( void ) dstaddr
; ( void ) dstport
; ( void ) iid
; }
3102 DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const int serviceID
, const mDNSAddr
*addr
, const mDNSIPPort port
,
3103 mDNSu32 scoped
, mDNSu32 timeout
, mDNSBool cellIntf
, mDNSBool isExpensive
, mDNSBool isCLAT46
, mDNSu16 resGroupID
, mDNSBool reqA
, mDNSBool reqAAAA
, mDNSBool reqDO
)
3104 { ( void ) m
; ( void ) d
; ( void ) interface
; ( void ) serviceID
; ( void ) addr
; ( void ) port
; ( void ) scoped
; ( void ) timeout
; (void) cellIntf
; (void) isExpensive
; (void) isCLAT46
;
3105 (void) resGroupID
; (void) reqA
; (void) reqAAAA
; (void) reqDO
; return(NULL
); }
3106 void mDNS_AddSearchDomain(const domainname
*const domain
, mDNSInterfaceID InterfaceID
) { (void)domain
; (void) InterfaceID
;}
3107 void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3108 { ( void ) m
; ( void ) fqdn
; ( void ) StatusCallback
; ( void ) StatusContext
; }
3109 mDNSs32
mDNS_Execute (mDNS
*const m
) { ( void ) m
; return 0; }
3110 mDNSs32
mDNS_TimeNow(const mDNS
*const m
) { ( void ) m
; return 0; }
3111 mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3112 void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, InterfaceActivationSpeed activationSpeed
)
3113 { ( void ) m
; ( void ) set
; ( void ) activationSpeed
; }
3114 const char * const mDNS_DomainTypeNames
[1] = {};
3115 mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
3116 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
3117 { ( void ) m
; ( void ) question
; ( void ) DomainType
; ( void ) dom
; ( void ) InterfaceID
; ( void ) Callback
; ( void ) Context
; return 0; }
3118 mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3119 mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, InterfaceActivationSpeed activationSpeed
)
3120 { ( void ) m
; ( void ) set
; ( void ) activationSpeed
; return 0; }
3121 void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
) { ( void ) m
; ( void ) fqdn
; }
3122 void mDNS_SetFQDN(mDNS
* const m
) { ( void ) m
; }
3123 void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3124 { ( void ) m
; ( void ) v4addr
; ( void ) v6addr
; ( void ) router
; }
3125 mStatus
uDNS_SetupDNSConfig( mDNS
*const m
) { ( void ) m
; return 0; }
3126 mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
3127 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, const domainname
*hostname
, mDNSIPPort
*port
, mDNSBool autoTunnel
)
3128 { ( void ) m
; ( void ) info
; ( void ) domain
; ( void ) keyname
; ( void ) b64keydata
; ( void ) hostname
; (void) port
; ( void ) autoTunnel
; return 0; }
3129 mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
) { ( void ) m
; ( void ) question
; return 0; }
3130 void TriggerEventCompletion(void);
3131 void TriggerEventCompletion() {}
3132 int AnonInfoAnswersQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
);
3133 int AnonInfoAnswersQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
) { ( void ) rr
; ( void ) q
; return 1;}
3137 // For convenience when using the "strings" command, this is the last thing in the file
3138 // The "@(#) " pattern is a special prefix the "what" command looks for
3139 const char mDNSResponderVersionString_SCCS
[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
3141 #if _BUILDING_XCODE_PROJECT_
3142 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3143 const char *__crashreporter_info__
= mDNSResponderVersionString_SCCS
+ 5;
3144 asm (".desc ___crashreporter_info__, 0x10");