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( NULL
, 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
;
1510 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == kDNSFlag0_OP_Update
)
1512 int i
, adds
= 0, dels
= 0;
1513 const mDNSu8
*ptr
, *end
= (mDNSu8
*)&request
->msg
+ request
->len
;
1515 lease
= GetPktLease(&mDNSStorage
, &request
->msg
, end
);
1516 ptr
= LocateAuthorities(&request
->msg
, end
);
1517 for (i
= 0; i
< request
->msg
.h
.mDNS_numUpdates
; i
++)
1519 LargeCacheRecord lcr
;
1520 ptr
= GetLargeResourceRecord(NULL
, &request
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1521 if (lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& lcr
.r
.resrec
.rroriginalttl
) adds
++;else dels
++;
1526 static const mDNSOpaque16 UpdateRefused
= { { kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
, kDNSFlag1_RC_Refused
} };
1527 Log("Rejecting Update Request with %d additions but no lease", adds
);
1528 reply
= malloc(sizeof(*reply
));
1529 mDNSPlatformMemZero(&reply
->src
, sizeof(reply
->src
));
1530 reply
->len
= sizeof(DNSMessageHeader
);
1532 reply
->isZonePublic
= 0;
1533 InitializeDNSMessage(&reply
->msg
.h
, request
->msg
.h
.id
, UpdateRefused
);
1536 if (lease
> 7200) // Don't allow lease greater than two hours; typically 90-minute renewal period
1539 // Send msg to server, read reply
1541 if ( request
->len
<= 512 )
1545 if ( UDPServerTransaction( self
, request
, &buf
, &trunc
) < 0 )
1547 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1551 VLog("HandleRequest - answer truncated. Using TCP");
1555 reply
= &buf
; // success
1564 sock
= ConnectToServer( self
);
1565 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 ) ) );
1567 res
= SendPacket( sock
, request
);
1568 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 ) ) );
1570 reply
= RecvPacket( sock
, &buf
, &closed
);
1573 // IMPORTANT: reply is in network byte order at this point in the code
1574 // We keep it this way because we send it back to the client in the same form
1578 if ( reply
&& ( ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
) ) )
1581 mDNSBool ok
= SuccessfulUpdateTransaction( request
, reply
);
1582 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 ) ) );
1584 UpdateLeaseTable( request
, self
, lease
);
1588 leaseReply
= FormatLeaseReply( self
, reply
, lease
);
1592 Log("HandleRequest - unable to format lease reply");
1595 // %%% Looks like a potential memory leak -- who frees the original reply?
1599 // tell the main thread there was an update so it can send LLQs
1601 if ( send( self
->LLQEventNotifySock
, pingmsg
, sizeof( pingmsg
), 0 ) != sizeof( pingmsg
) )
1603 LogErr("HandleRequest", "send");
1611 mDNSPlatformTCPCloseConnection( sock
);
1614 if ( reply
== &buf
)
1616 reply
= malloc( sizeof( *reply
) );
1620 reply
->len
= buf
.len
;
1621 memcpy(&reply
->msg
, &buf
.msg
, buf
.len
);
1625 LogErr("HandleRequest", "malloc");
1634 // LLQ Support Routines
1637 // Set fields of an LLQ OPT Resource Record
1638 mDNSlocal
void FormatLLQOpt(AuthRecord
*opt
, int opcode
, const mDNSOpaque64
*const id
, mDNSs32 lease
)
1640 mDNSPlatformMemZero(opt
, sizeof(*opt
));
1641 mDNS_SetupResourceRecord(opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, AuthRecordAny
, mDNSNULL
, mDNSNULL
);
1642 opt
->resrec
.rrclass
= NormalMaxDNSMessageData
;
1643 opt
->resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
1644 opt
->resrec
.rdestimate
= sizeof(rdataOPT
);
1645 opt
->resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_LLQ
;
1646 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.vers
= kLLQ_Vers
;
1647 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.llqOp
= opcode
;
1648 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.err
= LLQErr_NoError
;
1649 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.id
= *id
;
1650 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.llqlease
= lease
;
1653 // Calculate effective remaining lease of an LLQ
1654 mDNSlocal mDNSu32
LLQLease(LLQEntry
*e
)
1658 gettimeofday(&t
, NULL
);
1659 if (e
->expire
< t
.tv_sec
) return 0;
1660 else return e
->expire
- t
.tv_sec
;
1663 mDNSlocal
void DeleteLLQ(DaemonInfo
*d
, LLQEntry
*e
)
1665 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
1666 LLQEntry
**ptr
= &d
->LLQTable
[bucket
];
1667 AnswerListElem
*a
= e
->AnswerList
;
1670 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1671 VLog("Deleting LLQ table entry for %##s client %s", e
->qname
.c
, addr
);
1673 if (a
&& !(--a
->refcount
) && d
->AnswerTableCount
>= LLQ_TABLESIZE
)
1675 // currently, generating initial answers blocks the main thread, so we keep the answer list
1676 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1677 // if the ref count drops to zero AND there are more table elements than buckets
1678 // !!!KRS update this when we make the table dynamically growable
1680 CacheRecord
*cr
= a
->KnownAnswers
, *tmp
;
1681 AnswerListElem
**tbl
= &d
->AnswerTable
[bucket
];
1690 while (*tbl
&& *tbl
!= a
) tbl
= &(*tbl
)->next
;
1691 if (*tbl
) { *tbl
= (*tbl
)->next
; free(a
); d
->AnswerTableCount
--; }
1692 else Log("Error: DeleteLLQ - AnswerList not found in table");
1695 // remove LLQ from table, free memory
1696 while(*ptr
&& *ptr
!= e
) ptr
= &(*ptr
)->next
;
1697 if (!*ptr
) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1698 *ptr
= (*ptr
)->next
;
1702 mDNSlocal
int SendLLQ(DaemonInfo
*d
, PktMsg
*pkt
, struct sockaddr_in dst
, TCPSocket
*sock
)
1711 if ( SendPacket( sock
, pkt
) != 0 )
1713 LogErr("DaemonInfo", "MySend");
1714 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1719 if (sendto(d
->llq_udpsd
, &pkt
->msg
, pkt
->len
, 0, (struct sockaddr
*)&dst
, sizeof(dst
)) != (int)pkt
->len
)
1721 LogErr("DaemonInfo", "sendto");
1722 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1731 mDNSlocal CacheRecord
*AnswerQuestion(DaemonInfo
*d
, AnswerListElem
*e
)
1735 TCPSocket
*sock
= NULL
;
1736 const mDNSu8
*ansptr
;
1737 mDNSu8
*end
= q
.msg
.data
;
1738 PktMsg buf
, *reply
= NULL
;
1739 LargeCacheRecord lcr
;
1740 CacheRecord
*AnswerList
= NULL
;
1743 VLog("Querying server for %##s type %d", e
->name
.c
, e
->type
);
1745 InitializeDNSMessage(&q
.msg
.h
, zeroID
, uQueryFlags
);
1747 end
= putQuestion(&q
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->name
, e
->type
, kDNSClass_IN
);
1748 if (!end
) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end
; }
1749 q
.len
= (int)(end
- (mDNSu8
*)&q
.msg
);
1757 if (UDPServerTransaction(d
, &q
, &buf
, &trunc
) < 0)
1758 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e
->name
.c
);
1760 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e
->name
.c
); e
->UseTCP
= mDNStrue
; }
1761 else reply
= &buf
; // success
1768 sock
= ConnectToServer(d
);
1769 if (!sock
) { Log("AnswerQuestion: ConnectToServer failed"); goto end
; }
1770 if (SendPacket( sock
, &q
)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock
); goto end
; }
1771 reply
= RecvPacket( sock
, NULL
, &closed
);
1772 mDNSPlatformTCPCloseConnection( sock
);
1773 require_action( reply
, end
, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1777 if (reply
) HdrNToH(reply
);
1779 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
))
1780 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end
; }
1781 rcode
= (mDNSu8
)(reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1782 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
; }
1784 end
= (mDNSu8
*)&reply
->msg
+ reply
->len
;
1785 ansptr
= LocateAnswers(&reply
->msg
, end
);
1786 if (!ansptr
) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end
; }
1788 for (i
= 0; i
< reply
->msg
.h
.numAnswers
; i
++)
1790 ansptr
= GetLargeResourceRecord(NULL
, &reply
->msg
, ansptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1791 if (!ansptr
) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end
; }
1792 if (lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
)
1794 if (lcr
.r
.resrec
.rrtype
!= e
->type
|| lcr
.r
.resrec
.rrclass
!= kDNSClass_IN
|| !SameDomainName(lcr
.r
.resrec
.name
, &e
->name
))
1796 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1797 lcr
.r
.resrec
.name
->c
, lcr
.r
.resrec
.rrtype
, e
->name
.c
, e
->type
);
1801 CacheRecord
*cr
= CopyCacheRecord(&lcr
.r
, &e
->name
);
1802 if (!cr
) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end
; }
1803 cr
->next
= AnswerList
;
1810 if (reply
&& reply
!= &buf
) free(reply
);
1814 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1815 mDNSlocal
void *UpdateAnswerList(void *args
)
1817 CacheRecord
*cr
, *NewAnswers
, **na
, **ka
; // "new answer", "known answer"
1818 DaemonInfo
*d
= ((UpdateAnswerListArgs
*)args
)->d
;
1819 AnswerListElem
*a
= ((UpdateAnswerListArgs
*)args
)->a
;
1824 // get up to date answers
1825 NewAnswers
= AnswerQuestion(d
, a
);
1827 // first pass - mark all answers for deletion
1828 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1829 (*ka
)->resrec
.rroriginalttl
= (unsigned)-1; // -1 means delete
1831 // second pass - mark answers pre-existent
1832 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1834 for (na
= &NewAnswers
; *na
; na
= &(*na
)->next
)
1836 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
))
1837 { (*ka
)->resrec
.rroriginalttl
= 0; break; } // 0 means no change
1841 // third pass - add new records to Event list
1845 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1846 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
)) break;
1849 // answer is not in list - splice from NewAnswers list, add to Event list
1851 *na
= (*na
)->next
; // splice from list
1852 cr
->next
= a
->EventList
; // add spliced record to event list
1854 cr
->resrec
.rroriginalttl
= 1; // 1 means add
1856 else na
= &(*na
)->next
;
1859 // move all the removes from the answer list to the event list
1860 ka
= &a
->KnownAnswers
;
1863 if ((*ka
)->resrec
.rroriginalttl
== (unsigned)-1)
1867 cr
->next
= a
->EventList
;
1870 else ka
= &(*ka
)->next
;
1873 // lastly, free the remaining records (known answers) in NewAnswers list
1877 NewAnswers
= NewAnswers
->next
;
1884 mDNSlocal
void SendEvents(DaemonInfo
*d
, LLQEntry
*e
)
1888 mDNSu8
*end
= (mDNSu8
*)&response
.msg
.data
;
1890 char rrbuf
[MaxMsg
], addrbuf
[32];
1893 // Should this really be random? Do we use the msgID on the receiving end?
1894 msgID
.NotAnInteger
= random();
1895 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
1896 InitializeDNSMessage(&response
.msg
.h
, msgID
, ResponseFlags
);
1897 end
= putQuestion(&response
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
1898 if (!end
) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
1900 // put adds/removes in packet
1901 for (cr
= e
->AnswerList
->EventList
; cr
; cr
= cr
->next
)
1903 if (verbose
) GetRRDisplayString_rdb(&cr
->resrec
, &cr
->resrec
.rdata
->u
, rrbuf
);
1904 VLog("%s (%s): %s", addrbuf
, (mDNSs32
)cr
->resrec
.rroriginalttl
< 0 ? "Remove" : "Add", rrbuf
);
1905 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAnswers
, &cr
->resrec
, cr
->resrec
.rroriginalttl
);
1906 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
1909 FormatLLQOpt(&opt
, kLLQOp_Event
, &e
->id
, LLQLease(e
));
1910 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
1911 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
1913 response
.len
= (int)(end
- (mDNSu8
*)&response
.msg
);
1914 if (SendLLQ(d
, &response
, e
->cli
, NULL
) < 0) LogMsg("Error: SendEvents - SendLLQ");
1917 mDNSlocal
void PrintLLQAnswers(DaemonInfo
*d
)
1922 Log("Printing LLQ Answer Table contents");
1924 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1926 AnswerListElem
*a
= d
->AnswerTable
[i
];
1930 const CacheRecord
*rr
= a
->KnownAnswers
;
1931 while (rr
) { ancount
++; rr
= rr
->next
; }
1932 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a
, a
->name
.c
, a
->type
, a
->refcount
, ancount
);
1933 for (rr
= a
->KnownAnswers
; rr
; rr
= rr
->next
) Log("\t%s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, rrbuf
));
1939 mDNSlocal
void PrintLLQTable(DaemonInfo
*d
)
1945 Log("Printing LLQ table contents");
1947 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1956 case RequestReceived
: state
= "RequestReceived"; break;
1957 case ChallengeSent
: state
= "ChallengeSent"; break;
1958 case Established
: state
= "Established"; break;
1959 default: state
= "unknown";
1961 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1963 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
1964 addr
, state
, e
->qname
.c
, e
->qtype
, e
->lease
, LLQLease(e
), e
->AnswerList
);
1970 // Send events to clients as a result of a change in the zone
1971 mDNSlocal
void GenLLQEvents(DaemonInfo
*d
)
1976 UpdateAnswerListArgs
*args
;
1978 VLog("Generating LLQ Events");
1980 gettimeofday(&t
, NULL
);
1982 // get all answers up to date
1983 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1985 AnswerListElem
*a
= d
->AnswerTable
[i
];
1988 args
= malloc(sizeof(*args
));
1989 if (!args
) { LogErr("GenLLQEvents", "malloc"); return; }
1992 if (pthread_create(&a
->tid
, NULL
, UpdateAnswerList
, args
) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
1998 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2000 AnswerListElem
*a
= d
->AnswerTable
[i
];
2003 if (pthread_join(a
->tid
, NULL
)) LogErr("GenLLQEvents", "pthread_join");
2008 // for each established LLQ, send events
2009 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2011 e
= &d
->LLQTable
[i
];
2014 if ((*e
)->expire
< t
.tv_sec
) DeleteLLQ(d
, *e
);
2017 if ((*e
)->state
== Established
&& (*e
)->AnswerList
->EventList
) SendEvents(d
, *e
);
2023 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2024 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2026 AnswerListElem
*a
= d
->AnswerTable
[i
];
2031 CacheRecord
*cr
= a
->EventList
, *tmp
;
2036 if ((signed)tmp
->resrec
.rroriginalttl
< 0) free(tmp
);
2039 tmp
->next
= a
->KnownAnswers
;
2040 a
->KnownAnswers
= tmp
;
2041 tmp
->resrec
.rroriginalttl
= 0;
2044 a
->EventList
= NULL
;
2051 mDNSlocal
void SetAnswerList(DaemonInfo
*d
, LLQEntry
*e
)
2053 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
2054 AnswerListElem
*a
= d
->AnswerTable
[bucket
];
2055 while (a
&& (a
->type
!= e
->qtype
||!SameDomainName(&a
->name
, &e
->qname
))) a
= a
->next
;
2058 a
= malloc(sizeof(*a
));
2059 if (!a
) { LogErr("SetAnswerList", "malloc"); return; }
2060 AssignDomainName(&a
->name
, &e
->qname
);
2063 a
->EventList
= NULL
;
2064 a
->UseTCP
= mDNSfalse
;
2065 a
->next
= d
->AnswerTable
[bucket
];
2066 d
->AnswerTable
[bucket
] = a
;
2067 d
->AnswerTableCount
++;
2068 a
->KnownAnswers
= AnswerQuestion(d
, a
);
2075 // Allocate LLQ entry, insert into table
2076 mDNSlocal LLQEntry
*NewLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, mDNSu32 lease
)
2080 int bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2083 e
= malloc(sizeof(*e
));
2084 if (!e
) { LogErr("NewLLQ", "malloc"); return NULL
; }
2086 inet_ntop(AF_INET
, &cli
.sin_addr
, addr
, 32);
2087 VLog("Allocating LLQ entry for client %s question %##s type %d", addr
, qname
->c
, qtype
);
2089 // initialize structure
2091 AssignDomainName(&e
->qname
, qname
);
2093 e
->id
= zeroOpaque64
;
2094 e
->state
= RequestReceived
;
2095 e
->AnswerList
= NULL
;
2097 if (lease
< LLQ_MIN_LEASE
) lease
= LLQ_MIN_LEASE
;
2098 else if (lease
> LLQ_MAX_LEASE
) lease
= LLQ_MAX_LEASE
;
2100 gettimeofday(&t
, NULL
);
2101 e
->expire
= t
.tv_sec
+ (int)lease
;
2105 e
->next
= d
->LLQTable
[bucket
];
2106 d
->LLQTable
[bucket
] = e
;
2111 // Handle a refresh request from client
2112 mDNSlocal
void LLQRefresh(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2116 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2119 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2120 VLog("%s LLQ for %##s from %s", llq
->llqlease
? "Refreshing" : "Deleting", e
->qname
.c
, addr
);
2125 if (llq
->llqlease
< LLQ_MIN_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2126 else if (llq
->llqlease
> LLQ_MAX_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2127 gettimeofday(&t
, NULL
);
2128 e
->expire
= t
.tv_sec
+ llq
->llqlease
;
2131 ack
.src
.sin_addr
.s_addr
= 0; // unused
2132 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2133 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2134 if (!end
) { Log("Error: putQuestion"); return; }
2136 FormatLLQOpt(&opt
, kLLQOp_Refresh
, &e
->id
, llq
->llqlease
? LLQLease(e
) : 0);
2137 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2138 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2140 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2141 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQRefresh");
2143 if (llq
->llqlease
) e
->state
= Established
;
2144 else DeleteLLQ(d
, e
);
2147 // Complete handshake with Ack an initial answers
2148 mDNSlocal
void LLQCompleteHandshake(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2154 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2155 char rrbuf
[MaxMsg
], addrbuf
[32];
2157 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2159 if (!mDNSSameOpaque64(&llq
->id
, &e
->id
) ||
2160 llq
->vers
!= kLLQ_Vers
||
2161 llq
->llqOp
!= kLLQOp_Setup
||
2162 llq
->err
!= LLQErr_NoError
||
2163 llq
->llqlease
> e
->lease
+ LLQ_LEASE_FUDGE
||
2164 llq
->llqlease
< e
->lease
- LLQ_LEASE_FUDGE
)
2166 Log("Incorrect challenge response from %s", addr
);
2170 if (e
->state
== Established
) VLog("Retransmitting LLQ ack + answers for %##s", e
->qname
.c
);
2171 else VLog("Delivering LLQ ack + answers for %##s", e
->qname
.c
);
2173 // format ack + answers
2174 ack
.src
.sin_addr
.s_addr
= 0; // unused
2175 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2176 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2177 if (!end
) { Log("Error: putQuestion"); return; }
2179 if (e
->state
!= Established
) { SetAnswerList(d
, e
); e
->state
= Established
; }
2181 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2182 for (ptr
= e
->AnswerList
->KnownAnswers
; ptr
; ptr
= ptr
->next
)
2184 if (verbose
) GetRRDisplayString_rdb(&ptr
->resrec
, &ptr
->resrec
.rdata
->u
, rrbuf
);
2185 VLog("%s Intitial Answer - %s", addr
, rrbuf
);
2186 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAnswers
, &ptr
->resrec
, 1);
2187 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2190 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2191 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2192 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2194 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2195 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQCompleteHandshake");
2198 mDNSlocal
void LLQSetupChallenge(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
)
2202 mDNSu8
*end
= challenge
.msg
.data
;
2205 if (e
->state
== ChallengeSent
) VLog("Retransmitting LLQ setup challenge for %##s", e
->qname
.c
);
2206 else VLog("Sending LLQ setup challenge for %##s", e
->qname
.c
);
2208 if (!mDNSOpaque64IsZero(&llq
->id
)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2209 if (llq
->llqOp
!= kLLQOp_Setup
) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2211 if (mDNSOpaque64IsZero(&e
->id
)) // don't regenerate random ID for retransmissions
2213 // construct ID <time><random>
2214 gettimeofday(&t
, NULL
);
2215 e
->id
.l
[0] = t
.tv_sec
;
2216 e
->id
.l
[1] = random();
2219 // format response (query + LLQ opt rr)
2220 challenge
.src
.sin_addr
.s_addr
= 0; // unused
2221 InitializeDNSMessage(&challenge
.msg
.h
, msgID
, ResponseFlags
);
2222 end
= putQuestion(&challenge
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2223 if (!end
) { Log("Error: putQuestion"); return; }
2224 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2225 end
= PutResourceRecordTTLJumbo(&challenge
.msg
, end
, &challenge
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2226 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2227 challenge
.len
= (int)(end
- (mDNSu8
*)&challenge
.msg
);
2228 if (SendLLQ(d
, &challenge
, e
->cli
, NULL
)) { Log("Error: LLQSetupChallenge"); return; }
2229 e
->state
= ChallengeSent
;
2232 // Take action on an LLQ message from client. Entry must be initialized and in table
2233 mDNSlocal
void UpdateLLQ(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2237 case RequestReceived
:
2241 gettimeofday(&t
, NULL
);
2242 e
->id
.l
[0] = t
.tv_sec
; // construct ID <time><random>
2243 e
->id
.l
[1] = random();
2245 LLQCompleteHandshake( d
, e
, llq
, msgID
, sock
);
2247 // Set the state to established because we've just set the LLQ up using TCP
2248 e
->state
= Established
;
2252 LLQSetupChallenge(d
, e
, llq
, msgID
);
2256 if (mDNSOpaque64IsZero(&llq
->id
)) LLQSetupChallenge(d
, e
, llq
, msgID
); // challenge sent and lost
2257 else LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
);
2260 if (mDNSOpaque64IsZero(&llq
->id
))
2262 // client started over. reset state.
2263 LLQEntry
*newe
= NewLLQ(d
, e
->cli
, &e
->qname
, e
->qtype
, llq
->llqlease
);
2266 LLQSetupChallenge(d
, newe
, llq
, msgID
);
2269 else if (llq
->llqOp
== kLLQOp_Setup
)
2270 { LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
); return; } // Ack lost
2271 else if (llq
->llqOp
== kLLQOp_Refresh
)
2272 { LLQRefresh(d
, e
, llq
, msgID
, sock
); return; }
2273 else { Log("Unhandled message for established LLQ"); return; }
2277 mDNSlocal LLQEntry
*LookupLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, const mDNSOpaque64
*const id
)
2279 int bucket
= bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2280 LLQEntry
*ptr
= d
->LLQTable
[bucket
];
2284 if (((ptr
->state
== ChallengeSent
&& mDNSOpaque64IsZero(id
) && (cli
.sin_port
== ptr
->cli
.sin_port
)) || // zero-id due to packet loss OK in state ChallengeSent
2285 mDNSSameOpaque64(id
, &ptr
->id
)) && // id match
2286 (cli
.sin_addr
.s_addr
== ptr
->cli
.sin_addr
.s_addr
) && (qtype
== ptr
->qtype
) && SameDomainName(&ptr
->qname
, qname
)) // same source, type, qname
2303 pkt
->msg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
2305 res
= sendto( d
->udpsd
, &pkt
->msg
, pkt
->len
, 0, ( struct sockaddr
* ) &pkt
->src
, sizeof( pkt
->src
) );
2306 require_action( res
== ( int ) pkt
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvNotify", "sendto" ) );
2314 mDNSlocal
int RecvLLQ( DaemonInfo
*d
, PktMsg
*pkt
, TCPSocket
*sock
)
2317 LargeCacheRecord opt
;
2320 const mDNSu8
*qptr
= pkt
->msg
.data
;
2321 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2323 LLQOptData
*llq
= NULL
;
2327 aptr
= LocateAdditionals(&pkt
->msg
, end
); // Can't do this until after HdrNToH(pkt);
2328 inet_ntop(AF_INET
, &pkt
->src
.sin_addr
, addr
, 32);
2330 VLog("Received LLQ msg from %s", addr
);
2331 // sanity-check packet
2332 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2334 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
2338 // Locate the OPT record.
2339 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2340 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2341 // but not necessarily the *last* entry in the Additional Section.
2342 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2344 aptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, aptr
, end
, 0, kDNSRecordTypePacketAdd
, &opt
);
2345 if (!aptr
) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr
, i
); goto end
; }
2346 if (opt
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& opt
.r
.resrec
.rrtype
== kDNSType_OPT
) break;
2350 if (opt
.r
.resrec
.rrtype
!= kDNSType_OPT
) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr
); goto end
; }
2351 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
); }
2353 // dispatch each question
2354 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
2356 qptr
= getQuestion(&pkt
->msg
, qptr
, end
, 0, &q
);
2357 if (!qptr
) { Log("Malformatted LLQ from %s: cannot read question %d", addr
, i
); goto end
; }
2358 llq
= (LLQOptData
*)&opt
.r
.resrec
.rdata
->u
.opt
[0].u
.llq
+ i
; // point into OptData at index i
2359 if (llq
->vers
!= kLLQ_Vers
) { Log("LLQ from %s contains bad version %d (expected %d)", addr
, llq
->vers
, kLLQ_Vers
); goto end
; }
2361 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2364 // no entry - if zero ID, create new
2365 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2368 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2378 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
2380 const mDNSu8
* lastPtr
= NULL
;
2381 const mDNSu8
* ptr
= NULL
;
2382 DomainAuthInfo
* keys
;
2383 mDNSu8
* end
= ( mDNSu8
* ) &pkt
->msg
+ pkt
->len
;
2384 LargeCacheRecord lcr
;
2385 mDNSBool hasTSIG
= mDNSfalse
;
2386 mDNSBool strip
= mDNSfalse
;
2387 mDNSBool ok
= mDNSfalse
;
2390 // Unused parameters
2397 bzero(&lcr
, sizeof(lcr
));
2399 if ( pkt
->msg
.h
.numAdditionals
)
2401 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2404 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2407 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2410 Log("Unable to read additional record");
2416 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2420 LogMsg( "IsAuthorized: unable to find Additional section" );
2424 // If we don't know what zone this is, then it's authorized.
2433 if ( IsQuery( pkt
) )
2435 keys
= pkt
->zone
->queryKeys
;
2438 else if ( IsUpdate( pkt
) )
2440 keys
= pkt
->zone
->updateKeys
;
2450 if ( pkt
->isZonePublic
)
2456 // If there are no keys, then we're authorized
2458 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
2460 Log( "Invalid TSIG spec %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2461 *rcode
= kDNSFlag1_RC_NotAuth
;
2462 *tcode
= TSIG_ErrBadKey
;
2468 // Find the right key
2470 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2472 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
2480 Log( "Invalid TSIG name %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2481 *rcode
= kDNSFlag1_RC_NotAuth
;
2482 *tcode
= TSIG_ErrBadKey
;
2488 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2489 // lifting of message verification
2491 pkt
->msg
.h
.numAdditionals
--;
2495 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2499 pkt
->msg
.h
.numAdditionals
++;
2503 if ( hasTSIG
&& strip
)
2505 // Strip the TSIG from the message
2507 pkt
->msg
.h
.numAdditionals
--;
2508 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2516 // request handler wrappers for TCP and UDP requests
2517 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2525 UDPContext
* context
= ( UDPContext
* ) vptr
;
2526 PktMsg
* reply
= NULL
;
2530 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2531 // may give us a long answer that would require truncation for UDP delivery to client
2533 reply
= HandleRequest( context
->d
, &context
->pkt
);
2534 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
2536 res
= sendto( context
->sd
, &reply
->msg
, reply
->len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2537 require_action_quiet( res
== ( int ) reply
->len
, exit
, LogErr( "UDPMessageHandler", "sendto" ) );
2548 pthread_exit( NULL
);
2561 UDPContext
* context
= NULL
;
2565 DomainAuthInfo
* key
;
2566 unsigned int clisize
= sizeof( context
->cliaddr
);
2568 mStatus err
= mStatus_NoError
;
2570 context
= malloc( sizeof( UDPContext
) );
2571 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2573 mDNSPlatformMemZero( context
, sizeof( *context
) );
2577 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
2579 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvUDPMessage", "recvfrom" ) );
2580 context
->pkt
.len
= res
;
2581 require_action( clisize
== sizeof( context
->cliaddr
), exit
, err
= mStatus_UnknownErr
; Log( "Client address of unknown size %d", clisize
) );
2582 context
->pkt
.src
= context
->cliaddr
;
2584 // Set the zone in the packet
2586 SetZone( context
->d
, &context
->pkt
);
2588 // Notify messages handled by main thread
2590 if ( IsNotify( &context
->pkt
) )
2592 int e
= RecvNotify( self
, &context
->pkt
);
2596 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2598 if ( IsLLQRequest( &context
->pkt
) )
2600 // LLQ messages handled by main thread
2601 int e
= RecvLLQ( self
, &context
->pkt
, NULL
);
2606 if ( IsLLQAck(&context
->pkt
) )
2608 // !!!KRS need to do acks + retrans
2614 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2615 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2617 pthread_detach(tid
);
2624 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2626 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2627 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_NXDomain
;
2629 e
= sendto( sd
, &reply
.msg
, reply
.len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2630 require_action_quiet( e
== ( int ) reply
.len
, exit
, LogErr( "RecvUDPMessage", "sendto" ) );
2632 err
= mStatus_NoAuth
;
2637 if ( err
&& context
)
2649 TCPContext
* context
2654 if ( context
->sock
)
2656 mDNSPlatformTCPCloseConnection( context
->sock
);
2670 TCPContext
* context
= ( TCPContext
* ) vptr
;
2671 PktMsg
* reply
= NULL
;
2675 //!!!KRS if this read blocks indefinitely, we can run out of threads
2678 reply
= HandleRequest( context
->d
, &context
->pkt
);
2679 require_action_quiet( reply
, exit
, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2681 // deliver reply to client
2683 res
= SendPacket( context
->sock
, reply
);
2684 require_action( res
>= 0, exit
, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2688 FreeTCPContext( context
);
2705 TCPContext
* context
= ( TCPContext
* ) param
;
2709 DomainAuthInfo
* key
;
2712 mDNSBool freeContext
= mDNStrue
;
2713 mStatus err
= mStatus_NoError
;
2715 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2716 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2717 // wire. We'll let it do that, and wait for the next packet which will be ours.
2719 pkt
= RecvPacket( context
->sock
, &context
->pkt
, &closed
);
2720 if (pkt
) HdrNToH(pkt
);
2721 require_action( pkt
|| !closed
, exit
, err
= mStatus_UnknownErr
; LogMsg( "client disconnected" ) );
2725 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2726 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2727 // are sent over UDP
2729 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2731 // Set's the DNS Zone that is associated with this message
2733 SetZone( context
->d
, &context
->pkt
);
2735 // IsAuthorized will make sure the message is authorized for the designated zone.
2736 // After verifying the signature, it will strip the TSIG from the message
2738 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2740 if ( IsLLQRequest( &context
->pkt
) )
2742 // LLQ messages handled by main thread
2743 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2747 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2751 LogErr( "RecvTCPMessage", "pthread_create" );
2752 err
= mStatus_NoError
;
2756 // Let the thread free the context
2758 freeContext
= mDNSfalse
;
2760 pthread_detach(tid
);
2767 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2769 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2771 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2772 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_Refused
;
2774 SendPacket( context
->sock
, &reply
);
2779 freeContext
= mDNSfalse
;
2786 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2791 FreeTCPContext( context
);
2801 TCPSocketFlags flags
2804 TCPContext
* context
= NULL
;
2805 unsigned int clilen
= sizeof( context
->cliaddr
);
2807 mStatus err
= mStatus_NoError
;
2809 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2810 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2811 mDNSPlatformMemZero( context
, sizeof( sizeof( TCPContext
) ) );
2813 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2814 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2816 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2817 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2819 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2820 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2824 if ( err
&& context
)
2835 // listen for incoming requests, periodically check table for expired records, respond to signals
2836 mDNSlocal
int Run(DaemonInfo
*d
)
2838 int staticMaxFD
, nfds
;
2840 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
2841 mDNSBool EventsPending
= mDNSfalse
;
2843 VLog("Listening for requests...");
2847 if ( d
->tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tcpsd
+ 1;
2848 if ( d
->udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->udpsd
+ 1;
2849 if ( d
->tlssd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tlssd
+ 1;
2850 if ( d
->llq_tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_tcpsd
+ 1;
2851 if ( d
->llq_udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_udpsd
+ 1;
2852 if ( d
->LLQEventListenSock
+ 1 > staticMaxFD
) staticMaxFD
= d
->LLQEventListenSock
+ 1;
2856 EventSource
* source
;
2860 timeout
.tv_sec
= timeout
.tv_usec
= 0;
2861 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2865 if (timenow
.tv_sec
- EventTS
.tv_sec
>= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2866 { GenLLQEvents(d
); EventsPending
= mDNSfalse
; } // events, we go ahead and do it now
2867 else timeout
.tv_usec
= 500000; // else do events after 1/2 second with no new events or LLQs
2871 // if no pending events, timeout when we need to check for expired records
2872 if (tablecheck
.tv_sec
&& timenow
.tv_sec
- tablecheck
.tv_sec
>= 0)
2873 { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; } // table check overdue
2874 if (!tablecheck
.tv_sec
) tablecheck
.tv_sec
= timenow
.tv_sec
+ EXPIRATION_INTERVAL
;
2875 timeout
.tv_sec
= tablecheck
.tv_sec
- timenow
.tv_sec
;
2879 FD_SET( d
->tcpsd
, &rset
);
2880 FD_SET( d
->udpsd
, &rset
);
2881 FD_SET( d
->tlssd
, &rset
);
2882 FD_SET( d
->llq_tcpsd
, &rset
);
2883 FD_SET( d
->llq_udpsd
, &rset
);
2884 FD_SET( d
->LLQEventListenSock
, &rset
);
2886 maxFD
= staticMaxFD
;
2888 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2890 FD_SET( source
->fd
, &rset
);
2892 if ( source
->fd
> maxFD
)
2898 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
2905 // close sockets to prevent clients from making new requests during shutdown
2909 close( d
->llq_tcpsd
);
2910 close( d
->llq_udpsd
);
2911 d
->tcpsd
= d
->udpsd
= d
->tlssd
= d
->llq_tcpsd
= d
->llq_udpsd
= -1;
2912 DeleteRecords(d
, mDNStrue
);
2917 Log( "Received SIGINFO" );
2928 Log( "Received SIGHUP" );
2930 err
= ParseConfig( d
, cfgfile
);
2934 LogErr( "Run", "ParseConfig" );
2942 Log("Received unhandled signal - continuing");
2947 LogErr("Run", "select"); return -1;
2952 if (FD_ISSET(d
->udpsd
, &rset
)) RecvUDPMessage( d
, d
->udpsd
);
2953 if (FD_ISSET(d
->llq_udpsd
, &rset
)) RecvUDPMessage( d
, d
->llq_udpsd
);
2954 if (FD_ISSET(d
->tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->tcpsd
, 0 );
2955 if (FD_ISSET(d
->llq_tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->llq_tcpsd
, 0 );
2956 if (FD_ISSET(d
->tlssd
, &rset
)) AcceptTCPConnection( d
, d
->tlssd
, TCP_SOCKET_FLAGS
);
2957 if (FD_ISSET(d
->LLQEventListenSock
, &rset
))
2959 // clear signalling data off socket
2961 recv(d
->LLQEventListenSock
, buf
, 256, 0);
2964 EventsPending
= mDNStrue
;
2965 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2969 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2971 if ( FD_ISSET( source
->fd
, &rset
) )
2973 source
->callback( source
->context
);
2974 break; // in case we removed this guy from the event loop
2981 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
2982 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
2988 // signal handler sets global variables, which are inspected by main event loop
2989 // (select automatically returns due to the handled signal)
2990 mDNSlocal
void HndlSignal(int sig
)
2992 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
2993 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
2994 if (sig
== SIGHUP
) { hangup
= 1; return; }
3004 DNameListElem
* elem
;
3005 mStatus err
= mStatus_NoError
;
3007 elem
= ( DNameListElem
* ) malloc( sizeof( DNameListElem
) );
3008 require_action( elem
, exit
, err
= mStatus_NoMemoryErr
);
3009 MakeDomainNameFromDNSNameString( &elem
->name
, name
);
3010 elem
->next
= d
->public_names
;
3011 d
->public_names
= elem
;
3019 int main(int argc
, char *argv
[])
3021 int started_via_launchd
= 0;
3025 Log("dnsextd starting");
3027 d
= malloc(sizeof(*d
));
3028 if (!d
) { LogErr("main", "malloc"); exit(1); }
3029 mDNSPlatformMemZero(d
, sizeof(DaemonInfo
));
3031 // Setup the public SRV record names
3033 SetPublicSRV(d
, "_dns-update._udp.");
3034 SetPublicSRV(d
, "_dns-llq._udp.");
3035 SetPublicSRV(d
, "_dns-update-tls._tcp.");
3036 SetPublicSRV(d
, "_dns-query-tls._tcp.");
3037 SetPublicSRV(d
, "_dns-llq-tls._tcp.");
3039 // Setup signal handling
3041 if (signal(SIGHUP
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGHUP");
3042 if (signal(SIGTERM
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGTERM");
3043 if (signal(INFO_SIGNAL
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINFO");
3044 if (signal(SIGINT
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINT");
3045 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) perror("Can't ignore SIGPIPE");
3047 // remove open file limit
3048 rlim
.rlim_max
= RLIM_INFINITY
;
3049 rlim
.rlim_cur
= RLIM_INFINITY
;
3050 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3052 LogErr("main", "setrlimit");
3053 Log("Using default file descriptor resource limit");
3056 if (argc
> 1 && !strcasecmp(argv
[1], "-launchd"))
3058 Log("started_via_launchd");
3059 started_via_launchd
= 1;
3063 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3065 if (!foreground
&& !started_via_launchd
)
3069 LogErr("main", "daemon");
3074 if (InitLeaseTable(d
) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3075 if (SetupSockets(d
) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3076 if (SetUpdateSRV(d
) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3080 Log("dnsextd stopping");
3082 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3088 // These are stubbed out implementations of up-call routines that the various platform support layers
3089 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3090 // link this code in.
3092 // It's an error for these routines to actually be called, so perhaps we should log any call
3094 void mDNSCoreInitComplete( mDNS
* const m
, mStatus result
) { ( void ) m
; ( void ) result
; }
3095 void mDNS_ConfigChanged(mDNS
*const m
) { ( void ) m
; }
3096 void mDNSCoreMachineSleep(mDNS
* const m
, mDNSBool wake
) { ( void ) m
; ( void ) wake
; }
3097 void mDNSCoreReceive(mDNS
*const m
, void *const msg
, const mDNSu8
*const end
,
3098 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
,
3099 const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID iid
)
3100 { ( void ) m
; ( void ) msg
; ( void ) end
; ( void ) srcaddr
; ( void ) srcport
; ( void ) dstaddr
; ( void ) dstport
; ( void ) iid
; }
3101 DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const int serviceID
, const mDNSAddr
*addr
, const mDNSIPPort port
,
3102 mDNSu32 scoped
, mDNSu32 timeout
, mDNSBool cellIntf
, mDNSu16 resGroupID
, mDNSBool reqA
, mDNSBool reqAAAA
, mDNSBool reqDO
)
3103 { ( void ) m
; ( void ) d
; ( void ) interface
; ( void ) serviceID
; ( void ) addr
; ( void ) port
; ( void ) scoped
; ( void ) timeout
; (void) cellIntf
;
3104 (void) resGroupID
; (void) reqA
; (void) reqAAAA
; (void) reqDO
; return(NULL
); }
3105 void mDNS_AddSearchDomain(const domainname
*const domain
, mDNSInterfaceID InterfaceID
) { (void)domain
; (void) InterfaceID
;}
3106 void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3107 { ( void ) m
; ( void ) fqdn
; ( void ) StatusCallback
; ( void ) StatusContext
; }
3108 mDNSs32
mDNS_Execute (mDNS
*const m
) { ( void ) m
; return 0; }
3109 mDNSs32
mDNS_TimeNow(const mDNS
*const m
) { ( void ) m
; return 0; }
3110 mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3111 void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3112 { ( void ) m
; ( void ) set
; ( void ) flapping
; }
3113 const char * const mDNS_DomainTypeNames
[1] = {};
3114 mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
3115 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
3116 { ( void ) m
; ( void ) question
; ( void ) DomainType
; ( void ) dom
; ( void ) InterfaceID
; ( void ) Callback
; ( void ) Context
; return 0; }
3117 mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3118 mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3119 { ( void ) m
; ( void ) set
; ( void ) flapping
; return 0; }
3120 void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
) { ( void ) m
; ( void ) fqdn
; }
3121 void mDNS_SetFQDN(mDNS
* const m
) { ( void ) m
; }
3122 void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3123 { ( void ) m
; ( void ) v4addr
; ( void ) v6addr
; ( void ) router
; }
3124 mStatus
uDNS_SetupDNSConfig( mDNS
*const m
) { ( void ) m
; return 0; }
3125 mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
3126 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, const domainname
*hostname
, mDNSIPPort
*port
, mDNSBool autoTunnel
)
3127 { ( void ) m
; ( void ) info
; ( void ) domain
; ( void ) keyname
; ( void ) b64keydata
; ( void ) hostname
; (void) port
; ( void ) autoTunnel
; return 0; }
3128 mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
) { ( void ) m
; ( void ) question
; return 0; }
3129 void TriggerEventCompletion(void);
3130 void TriggerEventCompletion() {}
3131 int AnonInfoAnswersQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
);
3132 int AnonInfoAnswersQuestion(const ResourceRecord
*const rr
, const DNSQuestion
*const q
) { ( void ) rr
; ( void ) q
; return 1;}
3136 // For convenience when using the "strings" command, this is the last thing in the file
3137 // The "@(#) " pattern is a special prefix the "what" command looks for
3138 const char mDNSResponderVersionString_SCCS
[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
3140 #if _BUILDING_XCODE_PROJECT_
3141 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3142 const char *__crashreporter_info__
= mDNSResponderVersionString_SCCS
+ 5;
3143 asm (".desc ___crashreporter_info__, 0x10");