1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
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 // find last Additional info.
564 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
566 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
567 if (!ptr
) { Log("Unable to read additional record"); goto end
; }
570 if ( lcr
.r
.resrec
.rrtype
== kDNSType_OPT
&& lcr
.r
.resrec
.rdlength
>= DNSOpt_LLQData_Space
&& lcr
.r
.resrec
.rdata
->u
.opt
[0].opt
== kDNSOpt_LLQ
)
580 // !!!KRS implement properly
581 mDNSlocal mDNSBool
IsLLQAck(PktMsg
*pkt
)
583 if ((pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
) &&
584 pkt
->msg
.h
.numQuestions
&& !pkt
->msg
.h
.numAnswers
&& !pkt
->msg
.h
.numAuthorities
) return mDNStrue
;
596 DNameListElem
* elem
;
597 mDNSBool ret
= mDNSfalse
;
598 int i
= ( int ) DomainNameLength( &q
->qname
) - 1;
600 for ( elem
= self
->public_names
; elem
; elem
= elem
->next
)
602 int j
= ( int ) DomainNameLength( &elem
->name
) - 1;
606 for ( ; i
>= 0; i
--, j
-- )
608 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 QR_OP
= ( mDNSu8
) ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
645 if ( IsQuery( pkt
) )
647 DNSQuestion question
;
651 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
653 AppendDomainName( &zname
, &question
.qname
);
655 exception
= ( ( question
.qtype
== kDNSType_SOA
) || ( question
.qtype
== kDNSType_NS
) || ( ( question
.qtype
== kDNSType_SRV
) && IsPublicSRV( self
, &question
) ) );
657 else if ( IsUpdate( pkt
) )
659 DNSQuestion question
;
661 // It's an update. The format of the zone section is the same as the format for the question section
662 // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
664 ptr
= getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
666 AppendDomainName( &zname
, &question
.qname
);
668 exception
= mDNSfalse
;
671 if ( zname
.c
[0] != '\0' )
673 // Find the right zone
675 for ( pkt
->zone
= self
->zones
; pkt
->zone
; pkt
->zone
= pkt
->zone
->next
)
677 if ( ZoneHandlesName( &pkt
->zone
->name
, &zname
) )
679 VLog( "found correct zone %##s for query", pkt
->zone
->name
.c
);
681 pkt
->isZonePublic
= ( ( pkt
->zone
->type
== kDNSZonePublic
) || exception
);
683 VLog( "zone %##s is %s", pkt
->zone
->name
.c
, ( pkt
->isZonePublic
) ? "public" : "private" );
693 UDPServerTransaction(const DaemonInfo
*d
, const PktMsg
*request
, PktMsg
*reply
, mDNSBool
*trunc
)
696 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
699 mStatus err
= mStatus_NoError
;
707 sd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
708 require_action( sd
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "socket" ) );
710 // Send the packet to the nameserver
712 VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
713 ntohs(request
->msg
.h
.numQuestions
),
714 ntohs(request
->msg
.h
.numAnswers
),
715 ntohs(request
->msg
.h
.numAuthorities
),
716 ntohs(request
->msg
.h
.numAdditionals
));
717 res
= sendto( sd
, (char *)&request
->msg
, request
->len
, 0, ( struct sockaddr
* ) &d
->ns_addr
, sizeof( d
->ns_addr
) );
718 require_action( res
== (int) request
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "sendto" ) );
724 res
= select( sd
+ 1, &rset
, NULL
, NULL
, &timeout
);
725 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "select" ) );
726 require_action( ( res
> 0 ) && FD_ISSET( sd
, &rset
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - timeout" ) );
730 reply
->len
= recvfrom( sd
, &reply
->msg
, sizeof(reply
->msg
), 0, NULL
, NULL
);
731 require_action( ( ( int ) reply
->len
) >= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "recvfrom" ) );
732 require_action( reply
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - Message too short (%d bytes)", reply
->len
) );
734 // Check for truncation bit
736 if ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_TC
)
752 // Dynamic Update Utility Routines
755 // check if a request and server response complete a successful dynamic update
756 mDNSlocal mDNSBool
SuccessfulUpdateTransaction(PktMsg
*request
, PktMsg
*reply
)
759 char *vlogmsg
= NULL
;
762 if (!request
|| !reply
) { vlogmsg
= "NULL message"; goto failure
; }
763 if (request
->len
< sizeof(DNSMessageHeader
) || reply
->len
< sizeof(DNSMessageHeader
)) { vlogmsg
= "Malformatted message"; goto failure
; }
765 // check request operation
766 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
))
767 { vlogmsg
= "Request opcode not an update"; goto failure
; }
770 if ((reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)) { vlogmsg
= "Reply contains non-zero rcode"; goto failure
; }
771 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
))
772 { vlogmsg
= "Reply opcode not an update response"; goto failure
; }
774 VLog("Successful update from %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32));
778 VLog("Request %s: %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32), vlogmsg
);
782 // Allocate an appropriately sized CacheRecord and copy data from original.
783 // Name pointer in CacheRecord object is set to point to the name specified
785 mDNSlocal CacheRecord
*CopyCacheRecord(const CacheRecord
*orig
, domainname
*name
)
788 size_t size
= sizeof(*cr
);
789 if (orig
->resrec
.rdlength
> InlineCacheRDSize
) size
+= orig
->resrec
.rdlength
- InlineCacheRDSize
;
791 if (!cr
) { LogErr("CopyCacheRecord", "malloc"); return NULL
; }
792 memcpy(cr
, orig
, size
);
793 cr
->resrec
.rdata
= (RData
*)&cr
->smallrdatastorage
;
794 cr
->resrec
.name
= name
;
801 // Lease Hashtable Utility Routines
804 // double hash table size
805 // caller must lock table prior to invocation
806 mDNSlocal
void RehashTable(DaemonInfo
*d
)
808 RRTableElem
*ptr
, *tmp
, **new;
809 int i
, bucket
, newnbuckets
= d
->nbuckets
* 2;
811 VLog("Rehashing lease table (new size %d buckets)", newnbuckets
);
812 new = malloc(sizeof(RRTableElem
*) * newnbuckets
);
813 if (!new) { LogErr("RehashTable", "malloc"); return; }
814 mDNSPlatformMemZero(new, newnbuckets
* sizeof(RRTableElem
*));
816 for (i
= 0; i
< d
->nbuckets
; i
++)
821 bucket
= ptr
->rr
.resrec
.namehash
% newnbuckets
;
824 tmp
->next
= new[bucket
];
828 d
->nbuckets
= newnbuckets
;
833 // print entire contents of hashtable, invoked via SIGINFO
834 mDNSlocal
void PrintLeaseTable(DaemonInfo
*d
)
838 char rrbuf
[MaxMsg
], addrbuf
[16];
842 if (gettimeofday(&now
, NULL
)) { LogErr("PrintTable", "gettimeofday"); return; }
843 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
845 Log("Dumping Lease Table Contents (table contains %d resource records)", d
->nelems
);
846 for (i
= 0; i
< d
->nbuckets
; i
++)
848 for (ptr
= d
->table
[i
]; ptr
; ptr
= ptr
->next
)
850 hr
= ((ptr
->expire
- now
.tv_sec
) / 60) / 60;
851 min
= ((ptr
->expire
- now
.tv_sec
) / 60) % 60;
852 sec
= (ptr
->expire
- now
.tv_sec
) % 60;
853 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
,
854 GetRRDisplayString_rdb(&ptr
->rr
.resrec
, &ptr
->rr
.resrec
.rdata
->u
, rrbuf
));
857 pthread_mutex_unlock(&d
->tablelock
);
861 // Startup SRV Registration Routines
862 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
863 // the daemon accepts requests
866 // delete all RRS of a given name/type
867 mDNSlocal mDNSu8
*putRRSetDeletion(DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
, ResourceRecord
*rr
)
869 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
870 if (!ptr
|| ptr
+ 10 >= limit
) return NULL
; // out of space
871 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
872 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
873 ptr
[2] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
>> 8);
874 ptr
[3] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
& 0xFF);
875 mDNSPlatformMemZero(ptr
+4, sizeof(rr
->rroriginalttl
) + sizeof(rr
->rdlength
)); // zero ttl/rdata
876 msg
->h
.mDNS_numUpdates
++;
880 mDNSlocal mDNSu8
*PutUpdateSRV(DaemonInfo
*d
, DNSZone
* zone
, PktMsg
*pkt
, mDNSu8
*ptr
, char *regtype
, mDNSIPPort port
, mDNSBool registration
)
883 char hostname
[1024], buf
[MaxMsg
];
884 mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ sizeof(DNSMessage
);
888 mDNS_SetupResourceRecord(&rr
, NULL
, 0, kDNSType_SRV
, SRV_TTL
, kDNSRecordTypeUnique
, AuthRecordAny
, NULL
, NULL
);
889 rr
.resrec
.rrclass
= kDNSClass_IN
;
890 rr
.resrec
.rdata
->u
.srv
.priority
= 0;
891 rr
.resrec
.rdata
->u
.srv
.weight
= 0;
892 rr
.resrec
.rdata
->u
.srv
.port
= port
;
893 if (gethostname(hostname
, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr
.resrec
.rdata
->u
.srv
.target
, hostname
))
894 rr
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0';
896 MakeDomainNameFromDNSNameString(&rr
.namestorage
, regtype
);
897 AppendDomainName(&rr
.namestorage
, &zone
->name
);
898 VLog("%s %s", registration
? "Registering SRV record" : "Deleting existing RRSet",
899 GetRRDisplayString_rdb(&rr
.resrec
, &rr
.resrec
.rdata
->u
, buf
));
900 if (registration
) ptr
= PutResourceRecord(&pkt
->msg
, ptr
, &pkt
->msg
.h
.mDNS_numUpdates
, &rr
.resrec
);
901 else ptr
= putRRSetDeletion(&pkt
->msg
, ptr
, end
, &rr
.resrec
);
906 // perform dynamic update.
907 // specify deletion by passing false for the register parameter, otherwise register the records.
908 mDNSlocal
int UpdateSRV(DaemonInfo
*d
, mDNSBool registration
)
910 TCPSocket
*sock
= NULL
;
912 int err
= mStatus_NoError
;
914 sock
= ConnectToServer( d
);
915 require_action( sock
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: ConnectToServer failed" ) );
917 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
920 mDNSu8
*ptr
= pkt
.msg
.data
;
921 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
922 PktMsg
*reply
= NULL
;
926 // Initialize message
927 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
928 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
929 pkt
.src
.sin_family
= AF_INET
;
931 // format message body
932 ptr
= putZone(&pkt
.msg
, ptr
, end
, &zone
->name
, mDNSOpaque16fromIntVal(kDNSClass_IN
));
933 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
935 if ( zone
->type
== kDNSZonePrivate
)
937 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-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-query-tls._tcp.", d
->private_port
, registration
);
940 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
941 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls._tcp.", d
->private_port
, registration
);
942 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
946 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
947 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
948 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
949 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
956 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-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-query-tls.", d
->private_port
, registration
);
959 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
960 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls.", d
->private_port
, registration
);
961 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
964 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
965 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
966 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
967 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
972 if ( zone
->updateKeys
)
974 DNSDigest_SignMessage( &pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
975 require_action( ptr
, exit
, Log("UpdateSRV: Error constructing lease expiration update" ) );
978 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
980 // send message, receive reply
982 err
= SendPacket( sock
, &pkt
);
983 require_action( !err
, exit
, Log( "UpdateSRV: SendPacket failed" ) );
985 reply
= RecvPacket( sock
, NULL
, &closed
);
986 require_action( reply
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: RecvPacket returned NULL" ) );
988 ok
= SuccessfulUpdateTransaction( &pkt
, reply
);
992 Log("SRV record registration failed with rcode %d", reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1002 mDNSPlatformTCPCloseConnection( sock
);
1008 // wrapper routines/macros
1009 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1011 // clear any existing records prior to registration
1012 mDNSlocal
int SetUpdateSRV(DaemonInfo
*d
)
1016 err
= ClearUpdateSRV(d
); // clear any existing record
1017 if (!err
) err
= UpdateSRV(d
, 1);
1022 // Argument Parsing and Configuration
1025 mDNSlocal
void PrintUsage(void)
1027 fprintf(stderr
, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1028 "Use \"dnsextd -h\" for help\n");
1031 mDNSlocal
void PrintHelp(void)
1033 fprintf(stderr
, "\n\n");
1037 "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
1038 "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
1039 "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
1040 "Discovery, Update Leases, and Long Lived Queries.)\n\n"
1042 "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
1043 "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
1044 "primary master server for this zone.\n\n"
1046 "The options are as follows:\n\n"
1048 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1050 "-d Run daemon in foreground.\n\n"
1052 "-h Print help.\n\n"
1054 "-v Verbose output.\n\n"
1059 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
1060 // returns 0 (success) if program is to continue execution
1061 // output control arguments (-f, -v) do not affect this routine
1062 mDNSlocal
int ProcessArgs(int argc
, char *argv
[], DaemonInfo
*d
)
1068 cfgfile
= strdup( CONFIG_FILE
);
1069 require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
);
1071 // defaults, may be overriden by command option
1073 // setup our sockaddr
1075 mDNSPlatformMemZero( &d
->addr
, sizeof( d
->addr
) );
1076 d
->addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1077 d
->addr
.sin_port
= UnicastDNSPort
.NotAnInteger
;
1078 d
->addr
.sin_family
= AF_INET
;
1079 #ifndef NOT_HAVE_SA_LEN
1080 d
->addr
.sin_len
= sizeof( d
->addr
);
1083 // setup nameserver's sockaddr
1085 mDNSPlatformMemZero(&d
->ns_addr
, sizeof(d
->ns_addr
));
1086 d
->ns_addr
.sin_family
= AF_INET
;
1087 inet_pton( AF_INET
, LOOPBACK
, &d
->ns_addr
.sin_addr
);
1088 d
->ns_addr
.sin_port
= NSIPCPort
.NotAnInteger
;
1089 #ifndef NOT_HAVE_SA_LEN
1090 d
->ns_addr
.sin_len
= sizeof( d
->ns_addr
);
1095 d
->private_port
= PrivateDNSPort
;
1096 d
->llq_port
= DNSEXTPort
;
1098 while ((opt
= getopt(argc
, argv
, "f:hdv")) != -1)
1102 case 'f': free( cfgfile
); cfgfile
= strdup( optarg
); require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
); break;
1103 case 'h': PrintHelp(); return -1;
1104 case 'd': foreground
= 1; break; // Also used when launched via OS X's launchd mechanism
1105 case 'v': verbose
= 1; break;
1106 default: goto arg_error
;
1110 err
= ParseConfig( d
, cfgfile
);
1111 require_noerr( err
, arg_error
);
1113 // Make sure we've specified some zones
1115 require_action( d
->zones
, arg_error
, err
= mStatus_UnknownErr
);
1117 // if we have a shared secret, use it for the entire zone
1119 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1121 if ( zone
->updateKeys
)
1123 AssignDomainName( &zone
->updateKeys
->domain
, &zone
->name
);
1137 // Initialization Routines
1140 // Allocate memory, initialize locks and bookkeeping variables
1141 mDNSlocal
int InitLeaseTable(DaemonInfo
*d
)
1143 if (pthread_mutex_init(&d
->tablelock
, NULL
)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1144 d
->nbuckets
= LEASETABLE_INIT_NBUCKETS
;
1146 d
->table
= malloc(sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1147 if (!d
->table
) { LogErr("InitLeaseTable", "malloc"); return -1; }
1148 mDNSPlatformMemZero(d
->table
, sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1159 static const int kOn
= 1;
1161 mDNSBool
private = mDNSfalse
;
1162 struct sockaddr_in daddr
;
1166 // set up sockets on which we all ns requests
1168 self
->tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1169 require_action( dnssd_SocketValid(self
->tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1171 #if defined(SO_REUSEADDR)
1172 err
= setsockopt(self
->tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1173 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
1176 err
= bind( self
->tcpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1177 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1179 err
= listen( self
->tcpsd
, LISTENQ
);
1180 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1182 self
->udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1183 require_action( dnssd_SocketValid(self
->udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1185 #if defined(SO_REUSEADDR)
1186 err
= setsockopt(self
->udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1187 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
1190 err
= bind( self
->udpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1191 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->udpsd" ) );
1193 // set up sockets on which we receive llq requests
1195 mDNSPlatformMemZero(&self
->llq_addr
, sizeof(self
->llq_addr
));
1196 self
->llq_addr
.sin_family
= AF_INET
;
1197 self
->llq_addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1198 self
->llq_addr
.sin_port
= ( self
->llq_port
.NotAnInteger
) ? self
->llq_port
.NotAnInteger
: DNSEXTPort
.NotAnInteger
;
1200 if (self
->llq_addr
.sin_port
== self
->addr
.sin_port
)
1202 self
->llq_tcpsd
= self
->tcpsd
;
1203 self
->llq_udpsd
= self
->udpsd
;
1207 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1208 require_action( dnssd_SocketValid(self
->llq_tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1210 #if defined(SO_REUSEADDR)
1211 err
= setsockopt(self
->llq_tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1212 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
1215 err
= bind( self
->llq_tcpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1216 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
1218 err
= listen( self
->llq_tcpsd
, LISTENQ
);
1219 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1221 self
->llq_udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1222 require_action( dnssd_SocketValid(self
->llq_udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1224 #if defined(SO_REUSEADDR)
1225 err
= setsockopt(self
->llq_udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1226 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
1229 err
= bind(self
->llq_udpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1230 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
1233 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1235 err
= socketpair( AF_LOCAL
, SOCK_STREAM
, 0, sockpair
);
1236 require_action( !err
, exit
, LogErr( "SetupSockets", "socketpair" ) );
1238 self
->LLQEventListenSock
= sockpair
[0];
1239 self
->LLQEventNotifySock
= sockpair
[1];
1241 // set up socket on which we receive private requests
1243 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1244 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1245 mDNSPlatformMemZero(&daddr
, sizeof(daddr
));
1246 daddr
.sin_family
= AF_INET
;
1247 daddr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1248 daddr
.sin_port
= ( self
->private_port
.NotAnInteger
) ? self
->private_port
.NotAnInteger
: PrivateDNSPort
.NotAnInteger
;
1250 self
->tlssd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1251 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1253 #if defined(SO_REUSEADDR)
1254 err
= setsockopt(self
->tlssd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1255 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
1258 err
= bind( self
->tlssd
, ( struct sockaddr
* ) &daddr
, sizeof( daddr
) );
1259 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tlssd" ) );
1261 err
= listen( self
->tlssd
, LISTENQ
);
1262 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1264 // Do we have any private zones?
1266 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
1268 if ( zone
->type
== kDNSZonePrivate
)
1277 err
= mDNSPlatformTLSSetupCerts();
1278 require_action( !err
, exit
, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1287 // periodic table updates
1290 // Delete a resource record from the nameserver via a dynamic update
1291 // sd is a socket already connected to the server
1292 mDNSlocal
void DeleteOneRecord(DaemonInfo
*d
, CacheRecord
*rr
, domainname
*zname
, TCPSocket
*sock
)
1296 mDNSu8
*ptr
= pkt
.msg
.data
;
1297 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1300 PktMsg
*reply
= NULL
;
1302 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, buf
));
1304 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1306 ptr
= putZone(&pkt
.msg
, ptr
, end
, zname
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
1308 ptr
= putDeletionRecord(&pkt
.msg
, ptr
, &rr
->resrec
);
1313 zone
= FindZone( d
, zname
);
1315 if ( zone
&& zone
->updateKeys
)
1317 DNSDigest_SignMessage(&pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1321 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1322 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1323 pkt
.src
.sin_family
= AF_INET
;
1324 if (SendPacket( sock
, &pkt
)) { Log("DeleteOneRecord: SendPacket failed"); }
1325 reply
= RecvPacket( sock
, NULL
, &closed
);
1326 if (reply
) HdrNToH(reply
);
1327 require_action( reply
, end
, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
1329 if (!SuccessfulUpdateTransaction(&pkt
, reply
))
1330 Log("Expiration update failed with rcode %d", reply
? reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
: -1);
1333 if (!ptr
) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1334 if (reply
) free(reply
);
1337 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1338 mDNSlocal
void DeleteRecords(DaemonInfo
*d
, mDNSBool DeleteAll
)
1342 TCPSocket
*sock
= ConnectToServer(d
);
1343 if (!sock
) { Log("DeleteRecords: ConnectToServer failed"); return; }
1344 if (gettimeofday(&now
, NULL
)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
1345 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
1347 for (i
= 0; i
< d
->nbuckets
; i
++)
1349 RRTableElem
**ptr
= &d
->table
[i
];
1352 if (DeleteAll
|| (*ptr
)->expire
- now
.tv_sec
< 0)
1355 // delete record from server
1356 DeleteOneRecord(d
, &(*ptr
)->rr
, &(*ptr
)->zone
, sock
);
1358 *ptr
= (*ptr
)->next
;
1362 else ptr
= &(*ptr
)->next
;
1365 pthread_mutex_unlock(&d
->tablelock
);
1366 mDNSPlatformTCPCloseConnection( sock
);
1370 // main update request handling
1373 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
1374 mDNSlocal
void UpdateLeaseTable(PktMsg
*pkt
, DaemonInfo
*d
, mDNSs32 lease
)
1376 RRTableElem
**rptr
, *tmp
;
1377 int i
, allocsize
, bucket
;
1378 LargeCacheRecord lcr
;
1379 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1380 const mDNSu8
*ptr
, *end
;
1385 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
1387 ptr
= pkt
->msg
.data
;
1388 end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
1389 ptr
= getQuestion(&pkt
->msg
, ptr
, end
, 0, &zone
);
1390 if (!ptr
) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup
; }
1391 ptr
= LocateAuthorities(&pkt
->msg
, end
);
1392 if (!ptr
) { Log("UpdateLeaseTable: Format error"); goto cleanup
; }
1394 for (i
= 0; i
< pkt
->msg
.h
.mDNS_numUpdates
; i
++)
1396 mDNSBool DeleteAllRRSets
= mDNSfalse
, DeleteOneRRSet
= mDNSfalse
, DeleteOneRR
= mDNSfalse
;
1398 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1399 if (!ptr
|| lcr
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
) { Log("UpdateLeaseTable: GetLargeResourceRecord failed"); goto cleanup
; }
1400 bucket
= rr
->namehash
% d
->nbuckets
;
1401 rptr
= &d
->table
[bucket
];
1404 if (rr
->rrtype
== kDNSQType_ANY
&& !rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1405 DeleteAllRRSets
= mDNStrue
; // delete all rrsets for a name
1406 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1407 DeleteOneRRSet
= mDNStrue
;
1408 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSClass_NONE
)
1409 DeleteOneRR
= mDNStrue
;
1411 if (DeleteAllRRSets
|| DeleteOneRRSet
|| DeleteOneRR
)
1415 if (SameDomainName((*rptr
)->rr
.resrec
.name
, rr
->name
) &&
1417 (DeleteOneRRSet
&& (*rptr
)->rr
.resrec
.rrtype
== rr
->rrtype
) ||
1418 (DeleteOneRR
&& IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
))))
1421 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp
->rr
.resrec
, &tmp
->rr
.resrec
.rdata
->u
, buf
));
1422 *rptr
= (*rptr
)->next
;
1426 else rptr
= &(*rptr
)->next
;
1431 // see if add or refresh
1432 while (*rptr
&& !IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
)) rptr
= &(*rptr
)->next
;
1436 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1437 (*rptr
)->expire
= tv
.tv_sec
+ (unsigned)lease
;
1438 VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1442 // New record - add to table
1443 if (d
->nelems
> d
->nbuckets
)
1446 bucket
= rr
->namehash
% d
->nbuckets
;
1447 rptr
= &d
->table
[bucket
];
1449 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1450 allocsize
= sizeof(RRTableElem
);
1451 if (rr
->rdlength
> InlineCacheRDSize
) allocsize
+= (rr
->rdlength
- InlineCacheRDSize
);
1452 tmp
= malloc(allocsize
);
1453 if (!tmp
) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup
; }
1454 memcpy(&tmp
->rr
, &lcr
.r
, sizeof(CacheRecord
) + rr
->rdlength
- InlineCacheRDSize
);
1455 tmp
->rr
.resrec
.rdata
= (RData
*)&tmp
->rr
.smallrdatastorage
;
1456 AssignDomainName(&tmp
->name
, rr
->name
);
1457 tmp
->rr
.resrec
.name
= &tmp
->name
;
1458 tmp
->expire
= tv
.tv_sec
+ (unsigned)lease
;
1459 tmp
->cli
.sin_addr
= pkt
->src
.sin_addr
;
1460 AssignDomainName(&tmp
->zone
, &zone
.qname
);
1461 tmp
->next
= d
->table
[bucket
];
1462 d
->table
[bucket
] = tmp
;
1464 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1470 pthread_mutex_unlock(&d
->tablelock
);
1474 // Given a successful reply from a server, create a new reply that contains lease information
1475 // Replies are currently not signed !!!KRS change this
1476 mDNSlocal PktMsg
*FormatLeaseReply(DaemonInfo
*d
, PktMsg
*orig
, mDNSu32 lease
)
1483 reply
= malloc(sizeof(*reply
));
1484 if (!reply
) { LogErr("FormatLeaseReply", "malloc"); return NULL
; }
1485 flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
1488 InitializeDNSMessage(&reply
->msg
.h
, orig
->msg
.h
.id
, flags
);
1489 reply
->src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // unused except for log messages
1490 reply
->src
.sin_family
= AF_INET
;
1491 ptr
= reply
->msg
.data
;
1492 end
= (mDNSu8
*)&reply
->msg
+ sizeof(DNSMessage
);
1493 ptr
= putUpdateLease(&reply
->msg
, ptr
, lease
);
1494 if (!ptr
) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply
); return NULL
; }
1495 reply
->len
= ptr
- (mDNSu8
*)&reply
->msg
;
1501 // pkt is thread-local, not requiring locking
1510 PktMsg
* reply
= NULL
;
1511 PktMsg
* leaseReply
;
1514 TCPSocket
* sock
= NULL
;
1517 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == kDNSFlag0_OP_Update
)
1519 int i
, adds
= 0, dels
= 0;
1520 const mDNSu8
*ptr
, *end
= (mDNSu8
*)&request
->msg
+ request
->len
;
1522 lease
= GetPktLease(&mDNSStorage
, &request
->msg
, end
);
1523 ptr
= LocateAuthorities(&request
->msg
, end
);
1524 for (i
= 0; i
< request
->msg
.h
.mDNS_numUpdates
; i
++)
1526 LargeCacheRecord lcr
;
1527 ptr
= GetLargeResourceRecord(NULL
, &request
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1528 if (lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& lcr
.r
.resrec
.rroriginalttl
) adds
++;else dels
++;
1533 static const mDNSOpaque16 UpdateRefused
= { { kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
, kDNSFlag1_RC_Refused
} };
1534 Log("Rejecting Update Request with %d additions but no lease", adds
);
1535 reply
= malloc(sizeof(*reply
));
1536 mDNSPlatformMemZero(&reply
->src
, sizeof(reply
->src
));
1537 reply
->len
= sizeof(DNSMessageHeader
);
1539 reply
->isZonePublic
= 0;
1540 InitializeDNSMessage(&reply
->msg
.h
, request
->msg
.h
.id
, UpdateRefused
);
1543 if (lease
> 7200) // Don't allow lease greater than two hours; typically 90-minute renewal period
1546 // Send msg to server, read reply
1548 if ( request
->len
<= 512 )
1552 if ( UDPServerTransaction( self
, request
, &buf
, &trunc
) < 0 )
1554 Log("HandleRequest - UDPServerTransaction failed. Trying TCP");
1558 VLog("HandleRequest - answer truncated. Using TCP");
1562 reply
= &buf
; // success
1571 sock
= ConnectToServer( self
);
1572 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 ) ) );
1574 res
= SendPacket( sock
, request
);
1575 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 ) ) );
1577 reply
= RecvPacket( sock
, &buf
, &closed
);
1580 // IMPORTANT: reply is in network byte order at this point in the code
1581 // We keep it this way because we send it back to the client in the same form
1585 if ( reply
&& ( ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
) ) )
1588 mDNSBool ok
= SuccessfulUpdateTransaction( request
, reply
);
1589 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 ) ) );
1591 UpdateLeaseTable( request
, self
, lease
);
1595 leaseReply
= FormatLeaseReply( self
, reply
, lease
);
1599 Log("HandleRequest - unable to format lease reply");
1602 // %%% Looks like a potential memory leak -- who frees the original reply?
1606 // tell the main thread there was an update so it can send LLQs
1608 if ( send( self
->LLQEventNotifySock
, pingmsg
, sizeof( pingmsg
), 0 ) != sizeof( pingmsg
) )
1610 LogErr("HandleRequest", "send");
1618 mDNSPlatformTCPCloseConnection( sock
);
1621 if ( reply
== &buf
)
1623 reply
= malloc( sizeof( *reply
) );
1627 reply
->len
= buf
.len
;
1628 memcpy(&reply
->msg
, &buf
.msg
, buf
.len
);
1632 LogErr("HandleRequest", "malloc");
1641 // LLQ Support Routines
1644 // Set fields of an LLQ OPT Resource Record
1645 mDNSlocal
void FormatLLQOpt(AuthRecord
*opt
, int opcode
, const mDNSOpaque64
*const id
, mDNSs32 lease
)
1647 mDNSPlatformMemZero(opt
, sizeof(*opt
));
1648 mDNS_SetupResourceRecord(opt
, mDNSNULL
, mDNSInterface_Any
, kDNSType_OPT
, kStandardTTL
, kDNSRecordTypeKnownUnique
, AuthRecordAny
, mDNSNULL
, mDNSNULL
);
1649 opt
->resrec
.rrclass
= NormalMaxDNSMessageData
;
1650 opt
->resrec
.rdlength
= sizeof(rdataOPT
); // One option in this OPT record
1651 opt
->resrec
.rdestimate
= sizeof(rdataOPT
);
1652 opt
->resrec
.rdata
->u
.opt
[0].opt
= kDNSOpt_LLQ
;
1653 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.vers
= kLLQ_Vers
;
1654 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.llqOp
= opcode
;
1655 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.err
= LLQErr_NoError
;
1656 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.id
= *id
;
1657 opt
->resrec
.rdata
->u
.opt
[0].u
.llq
.llqlease
= lease
;
1660 // Calculate effective remaining lease of an LLQ
1661 mDNSlocal mDNSu32
LLQLease(LLQEntry
*e
)
1665 gettimeofday(&t
, NULL
);
1666 if (e
->expire
< t
.tv_sec
) return 0;
1667 else return e
->expire
- t
.tv_sec
;
1670 mDNSlocal
void DeleteLLQ(DaemonInfo
*d
, LLQEntry
*e
)
1672 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
1673 LLQEntry
**ptr
= &d
->LLQTable
[bucket
];
1674 AnswerListElem
*a
= e
->AnswerList
;
1677 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1678 VLog("Deleting LLQ table entry for %##s client %s", e
->qname
.c
, addr
);
1680 if (a
&& !(--a
->refcount
) && d
->AnswerTableCount
>= LLQ_TABLESIZE
)
1682 // currently, generating initial answers blocks the main thread, so we keep the answer list
1683 // even if the ref count drops to zero. To prevent unbounded table growth, we free shared answers
1684 // if the ref count drops to zero AND there are more table elements than buckets
1685 // !!!KRS update this when we make the table dynamically growable
1687 CacheRecord
*cr
= a
->KnownAnswers
, *tmp
;
1688 AnswerListElem
**tbl
= &d
->AnswerTable
[bucket
];
1697 while (*tbl
&& *tbl
!= a
) tbl
= &(*tbl
)->next
;
1698 if (*tbl
) { *tbl
= (*tbl
)->next
; free(a
); d
->AnswerTableCount
--; }
1699 else Log("Error: DeleteLLQ - AnswerList not found in table");
1702 // remove LLQ from table, free memory
1703 while(*ptr
&& *ptr
!= e
) ptr
= &(*ptr
)->next
;
1704 if (!*ptr
) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
1705 *ptr
= (*ptr
)->next
;
1709 mDNSlocal
int SendLLQ(DaemonInfo
*d
, PktMsg
*pkt
, struct sockaddr_in dst
, TCPSocket
*sock
)
1718 if ( SendPacket( sock
, pkt
) != 0 )
1720 LogErr("DaemonInfo", "MySend");
1721 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1726 if (sendto(d
->llq_udpsd
, &pkt
->msg
, pkt
->len
, 0, (struct sockaddr
*)&dst
, sizeof(dst
)) != (int)pkt
->len
)
1728 LogErr("DaemonInfo", "sendto");
1729 Log("Could not send response to client %s", inet_ntop(AF_INET
, &dst
.sin_addr
, addr
, 32));
1738 mDNSlocal CacheRecord
*AnswerQuestion(DaemonInfo
*d
, AnswerListElem
*e
)
1742 TCPSocket
*sock
= NULL
;
1743 const mDNSu8
*ansptr
;
1744 mDNSu8
*end
= q
.msg
.data
;
1745 PktMsg buf
, *reply
= NULL
;
1746 LargeCacheRecord lcr
;
1747 CacheRecord
*AnswerList
= NULL
;
1750 VLog("Querying server for %##s type %d", e
->name
.c
, e
->type
);
1752 InitializeDNSMessage(&q
.msg
.h
, zeroID
, uQueryFlags
);
1754 end
= putQuestion(&q
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->name
, e
->type
, kDNSClass_IN
);
1755 if (!end
) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end
; }
1756 q
.len
= (int)(end
- (mDNSu8
*)&q
.msg
);
1764 if (UDPServerTransaction(d
, &q
, &buf
, &trunc
) < 0)
1765 Log("AnswerQuestion %##s - UDPServerTransaction failed. Trying TCP", e
->name
.c
);
1767 { VLog("AnswerQuestion %##s - answer truncated. Using TCP", e
->name
.c
); e
->UseTCP
= mDNStrue
; }
1768 else reply
= &buf
; // success
1775 sock
= ConnectToServer(d
);
1776 if (!sock
) { Log("AnswerQuestion: ConnectToServer failed"); goto end
; }
1777 if (SendPacket( sock
, &q
)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock
); goto end
; }
1778 reply
= RecvPacket( sock
, NULL
, &closed
);
1779 mDNSPlatformTCPCloseConnection( sock
);
1780 require_action( reply
, end
, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
1784 if (reply
) HdrNToH(reply
);
1786 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
))
1787 { Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end
; }
1788 rcode
= (mDNSu8
)(reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
1789 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
; }
1791 end
= (mDNSu8
*)&reply
->msg
+ reply
->len
;
1792 ansptr
= LocateAnswers(&reply
->msg
, end
);
1793 if (!ansptr
) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end
; }
1795 for (i
= 0; i
< reply
->msg
.h
.numAnswers
; i
++)
1797 ansptr
= GetLargeResourceRecord(NULL
, &reply
->msg
, ansptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1798 if (!ansptr
) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end
; }
1799 if (lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
)
1801 if (lcr
.r
.resrec
.rrtype
!= e
->type
|| lcr
.r
.resrec
.rrclass
!= kDNSClass_IN
|| !SameDomainName(lcr
.r
.resrec
.name
, &e
->name
))
1803 Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d. Discarding",
1804 lcr
.r
.resrec
.name
->c
, lcr
.r
.resrec
.rrtype
, e
->name
.c
, e
->type
);
1808 CacheRecord
*cr
= CopyCacheRecord(&lcr
.r
, &e
->name
);
1809 if (!cr
) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end
; }
1810 cr
->next
= AnswerList
;
1817 if (reply
&& reply
!= &buf
) free(reply
);
1821 // Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
1822 mDNSlocal
void *UpdateAnswerList(void *args
)
1824 CacheRecord
*cr
, *NewAnswers
, **na
, **ka
; // "new answer", "known answer"
1825 DaemonInfo
*d
= ((UpdateAnswerListArgs
*)args
)->d
;
1826 AnswerListElem
*a
= ((UpdateAnswerListArgs
*)args
)->a
;
1831 // get up to date answers
1832 NewAnswers
= AnswerQuestion(d
, a
);
1834 // first pass - mark all answers for deletion
1835 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1836 (*ka
)->resrec
.rroriginalttl
= (unsigned)-1; // -1 means delete
1838 // second pass - mark answers pre-existent
1839 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1841 for (na
= &NewAnswers
; *na
; na
= &(*na
)->next
)
1843 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
))
1844 { (*ka
)->resrec
.rroriginalttl
= 0; break; } // 0 means no change
1848 // third pass - add new records to Event list
1852 for (ka
= &a
->KnownAnswers
; *ka
; ka
= &(*ka
)->next
)
1853 if (IdenticalResourceRecord(&(*ka
)->resrec
, &(*na
)->resrec
)) break;
1856 // answer is not in list - splice from NewAnswers list, add to Event list
1858 *na
= (*na
)->next
; // splice from list
1859 cr
->next
= a
->EventList
; // add spliced record to event list
1861 cr
->resrec
.rroriginalttl
= 1; // 1 means add
1863 else na
= &(*na
)->next
;
1866 // move all the removes from the answer list to the event list
1867 ka
= &a
->KnownAnswers
;
1870 if ((*ka
)->resrec
.rroriginalttl
== (unsigned)-1)
1874 cr
->next
= a
->EventList
;
1877 else ka
= &(*ka
)->next
;
1880 // lastly, free the remaining records (known answers) in NewAnswers list
1884 NewAnswers
= NewAnswers
->next
;
1891 mDNSlocal
void SendEvents(DaemonInfo
*d
, LLQEntry
*e
)
1895 mDNSu8
*end
= (mDNSu8
*)&response
.msg
.data
;
1897 char rrbuf
[MaxMsg
], addrbuf
[32];
1900 // Should this really be random? Do we use the msgID on the receiving end?
1901 msgID
.NotAnInteger
= random();
1902 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
1903 InitializeDNSMessage(&response
.msg
.h
, msgID
, ResponseFlags
);
1904 end
= putQuestion(&response
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
1905 if (!end
) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
1907 // put adds/removes in packet
1908 for (cr
= e
->AnswerList
->EventList
; cr
; cr
= cr
->next
)
1910 if (verbose
) GetRRDisplayString_rdb(&cr
->resrec
, &cr
->resrec
.rdata
->u
, rrbuf
);
1911 VLog("%s (%s): %s", addrbuf
, (mDNSs32
)cr
->resrec
.rroriginalttl
< 0 ? "Remove" : "Add", rrbuf
);
1912 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAnswers
, &cr
->resrec
, cr
->resrec
.rroriginalttl
);
1913 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
1916 FormatLLQOpt(&opt
, kLLQOp_Event
, &e
->id
, LLQLease(e
));
1917 end
= PutResourceRecordTTLJumbo(&response
.msg
, end
, &response
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
1918 if (!end
) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
1920 response
.len
= (int)(end
- (mDNSu8
*)&response
.msg
);
1921 if (SendLLQ(d
, &response
, e
->cli
, NULL
) < 0) LogMsg("Error: SendEvents - SendLLQ");
1924 mDNSlocal
void PrintLLQAnswers(DaemonInfo
*d
)
1929 Log("Printing LLQ Answer Table contents");
1931 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1933 AnswerListElem
*a
= d
->AnswerTable
[i
];
1937 const CacheRecord
*rr
= a
->KnownAnswers
;
1938 while (rr
) { ancount
++; rr
= rr
->next
; }
1939 Log("%p : Question %##s; type %d; referenced by %d LLQs; %d answers:", a
, a
->name
.c
, a
->type
, a
->refcount
, ancount
);
1940 for (rr
= a
->KnownAnswers
; rr
; rr
= rr
->next
) Log("\t%s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, rrbuf
));
1946 mDNSlocal
void PrintLLQTable(DaemonInfo
*d
)
1952 Log("Printing LLQ table contents");
1954 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1963 case RequestReceived
: state
= "RequestReceived"; break;
1964 case ChallengeSent
: state
= "ChallengeSent"; break;
1965 case Established
: state
= "Established"; break;
1966 default: state
= "unknown";
1968 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
1970 Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
1971 addr
, state
, e
->qname
.c
, e
->qtype
, e
->lease
, LLQLease(e
), e
->AnswerList
);
1977 // Send events to clients as a result of a change in the zone
1978 mDNSlocal
void GenLLQEvents(DaemonInfo
*d
)
1983 UpdateAnswerListArgs
*args
;
1985 VLog("Generating LLQ Events");
1987 gettimeofday(&t
, NULL
);
1989 // get all answers up to date
1990 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
1992 AnswerListElem
*a
= d
->AnswerTable
[i
];
1995 args
= malloc(sizeof(*args
));
1996 if (!args
) { LogErr("GenLLQEvents", "malloc"); return; }
1999 if (pthread_create(&a
->tid
, NULL
, UpdateAnswerList
, args
) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
2005 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2007 AnswerListElem
*a
= d
->AnswerTable
[i
];
2010 if (pthread_join(a
->tid
, NULL
)) LogErr("GenLLQEvents", "pthread_join");
2015 // for each established LLQ, send events
2016 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2018 e
= &d
->LLQTable
[i
];
2021 if ((*e
)->expire
< t
.tv_sec
) DeleteLLQ(d
, *e
);
2024 if ((*e
)->state
== Established
&& (*e
)->AnswerList
->EventList
) SendEvents(d
, *e
);
2030 // now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
2031 for (i
= 0; i
< LLQ_TABLESIZE
; i
++)
2033 AnswerListElem
*a
= d
->AnswerTable
[i
];
2038 CacheRecord
*cr
= a
->EventList
, *tmp
;
2043 if ((signed)tmp
->resrec
.rroriginalttl
< 0) free(tmp
);
2046 tmp
->next
= a
->KnownAnswers
;
2047 a
->KnownAnswers
= tmp
;
2048 tmp
->resrec
.rroriginalttl
= 0;
2051 a
->EventList
= NULL
;
2058 mDNSlocal
void SetAnswerList(DaemonInfo
*d
, LLQEntry
*e
)
2060 int bucket
= DomainNameHashValue(&e
->qname
) % LLQ_TABLESIZE
;
2061 AnswerListElem
*a
= d
->AnswerTable
[bucket
];
2062 while (a
&& (a
->type
!= e
->qtype
||!SameDomainName(&a
->name
, &e
->qname
))) a
= a
->next
;
2065 a
= malloc(sizeof(*a
));
2066 if (!a
) { LogErr("SetAnswerList", "malloc"); return; }
2067 AssignDomainName(&a
->name
, &e
->qname
);
2070 a
->EventList
= NULL
;
2071 a
->UseTCP
= mDNSfalse
;
2072 a
->next
= d
->AnswerTable
[bucket
];
2073 d
->AnswerTable
[bucket
] = a
;
2074 d
->AnswerTableCount
++;
2075 a
->KnownAnswers
= AnswerQuestion(d
, a
);
2082 // Allocate LLQ entry, insert into table
2083 mDNSlocal LLQEntry
*NewLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, mDNSu32 lease
)
2087 int bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2090 e
= malloc(sizeof(*e
));
2091 if (!e
) { LogErr("NewLLQ", "malloc"); return NULL
; }
2093 inet_ntop(AF_INET
, &cli
.sin_addr
, addr
, 32);
2094 VLog("Allocating LLQ entry for client %s question %##s type %d", addr
, qname
->c
, qtype
);
2096 // initialize structure
2098 AssignDomainName(&e
->qname
, qname
);
2100 e
->id
= zeroOpaque64
;
2101 e
->state
= RequestReceived
;
2102 e
->AnswerList
= NULL
;
2104 if (lease
< LLQ_MIN_LEASE
) lease
= LLQ_MIN_LEASE
;
2105 else if (lease
> LLQ_MAX_LEASE
) lease
= LLQ_MAX_LEASE
;
2107 gettimeofday(&t
, NULL
);
2108 e
->expire
= t
.tv_sec
+ (int)lease
;
2112 e
->next
= d
->LLQTable
[bucket
];
2113 d
->LLQTable
[bucket
] = e
;
2118 // Handle a refresh request from client
2119 mDNSlocal
void LLQRefresh(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2123 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2126 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2127 VLog("%s LLQ for %##s from %s", llq
->llqlease
? "Refreshing" : "Deleting", e
->qname
.c
, addr
);
2132 if (llq
->llqlease
< LLQ_MIN_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2133 else if (llq
->llqlease
> LLQ_MAX_LEASE
) llq
->llqlease
= LLQ_MIN_LEASE
;
2134 gettimeofday(&t
, NULL
);
2135 e
->expire
= t
.tv_sec
+ llq
->llqlease
;
2138 ack
.src
.sin_addr
.s_addr
= 0; // unused
2139 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2140 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2141 if (!end
) { Log("Error: putQuestion"); return; }
2143 FormatLLQOpt(&opt
, kLLQOp_Refresh
, &e
->id
, llq
->llqlease
? LLQLease(e
) : 0);
2144 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2145 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2147 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2148 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQRefresh");
2150 if (llq
->llqlease
) e
->state
= Established
;
2151 else DeleteLLQ(d
, e
);
2154 // Complete handshake with Ack an initial answers
2155 mDNSlocal
void LLQCompleteHandshake(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2161 mDNSu8
*end
= (mDNSu8
*)&ack
.msg
.data
;
2162 char rrbuf
[MaxMsg
], addrbuf
[32];
2164 inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addr
, 32);
2166 if (!mDNSSameOpaque64(&llq
->id
, &e
->id
) ||
2167 llq
->vers
!= kLLQ_Vers
||
2168 llq
->llqOp
!= kLLQOp_Setup
||
2169 llq
->err
!= LLQErr_NoError
||
2170 llq
->llqlease
> e
->lease
+ LLQ_LEASE_FUDGE
||
2171 llq
->llqlease
< e
->lease
- LLQ_LEASE_FUDGE
)
2173 Log("Incorrect challenge response from %s", addr
);
2177 if (e
->state
== Established
) VLog("Retransmitting LLQ ack + answers for %##s", e
->qname
.c
);
2178 else VLog("Delivering LLQ ack + answers for %##s", e
->qname
.c
);
2180 // format ack + answers
2181 ack
.src
.sin_addr
.s_addr
= 0; // unused
2182 InitializeDNSMessage(&ack
.msg
.h
, msgID
, ResponseFlags
);
2183 end
= putQuestion(&ack
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2184 if (!end
) { Log("Error: putQuestion"); return; }
2186 if (e
->state
!= Established
) { SetAnswerList(d
, e
); e
->state
= Established
; }
2188 if (verbose
) inet_ntop(AF_INET
, &e
->cli
.sin_addr
, addrbuf
, 32);
2189 for (ptr
= e
->AnswerList
->KnownAnswers
; ptr
; ptr
= ptr
->next
)
2191 if (verbose
) GetRRDisplayString_rdb(&ptr
->resrec
, &ptr
->resrec
.rdata
->u
, rrbuf
);
2192 VLog("%s Intitial Answer - %s", addr
, rrbuf
);
2193 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAnswers
, &ptr
->resrec
, 1);
2194 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2197 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2198 end
= PutResourceRecordTTLJumbo(&ack
.msg
, end
, &ack
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2199 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2201 ack
.len
= (int)(end
- (mDNSu8
*)&ack
.msg
);
2202 if (SendLLQ(d
, &ack
, e
->cli
, sock
)) Log("Error: LLQCompleteHandshake");
2205 mDNSlocal
void LLQSetupChallenge(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
)
2209 mDNSu8
*end
= challenge
.msg
.data
;
2212 if (e
->state
== ChallengeSent
) VLog("Retransmitting LLQ setup challenge for %##s", e
->qname
.c
);
2213 else VLog("Sending LLQ setup challenge for %##s", e
->qname
.c
);
2215 if (!mDNSOpaque64IsZero(&llq
->id
)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
2216 if (llq
->llqOp
!= kLLQOp_Setup
) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
2218 if (mDNSOpaque64IsZero(&e
->id
)) // don't regenerate random ID for retransmissions
2220 // construct ID <time><random>
2221 gettimeofday(&t
, NULL
);
2222 e
->id
.l
[0] = t
.tv_sec
;
2223 e
->id
.l
[1] = random();
2226 // format response (query + LLQ opt rr)
2227 challenge
.src
.sin_addr
.s_addr
= 0; // unused
2228 InitializeDNSMessage(&challenge
.msg
.h
, msgID
, ResponseFlags
);
2229 end
= putQuestion(&challenge
.msg
, end
, end
+ AbsoluteMaxDNSMessageData
, &e
->qname
, e
->qtype
, kDNSClass_IN
);
2230 if (!end
) { Log("Error: putQuestion"); return; }
2231 FormatLLQOpt(&opt
, kLLQOp_Setup
, &e
->id
, LLQLease(e
));
2232 end
= PutResourceRecordTTLJumbo(&challenge
.msg
, end
, &challenge
.msg
.h
.numAdditionals
, &opt
.resrec
, 0);
2233 if (!end
) { Log("Error: PutResourceRecordTTLJumbo"); return; }
2234 challenge
.len
= (int)(end
- (mDNSu8
*)&challenge
.msg
);
2235 if (SendLLQ(d
, &challenge
, e
->cli
, NULL
)) { Log("Error: LLQSetupChallenge"); return; }
2236 e
->state
= ChallengeSent
;
2239 // Take action on an LLQ message from client. Entry must be initialized and in table
2240 mDNSlocal
void UpdateLLQ(DaemonInfo
*d
, LLQEntry
*e
, LLQOptData
*llq
, mDNSOpaque16 msgID
, TCPSocket
*sock
)
2244 case RequestReceived
:
2248 gettimeofday(&t
, NULL
);
2249 e
->id
.l
[0] = t
.tv_sec
; // construct ID <time><random>
2250 e
->id
.l
[1] = random();
2252 LLQCompleteHandshake( d
, e
, llq
, msgID
, sock
);
2254 // Set the state to established because we've just set the LLQ up using TCP
2255 e
->state
= Established
;
2259 LLQSetupChallenge(d
, e
, llq
, msgID
);
2263 if (mDNSOpaque64IsZero(&llq
->id
)) LLQSetupChallenge(d
, e
, llq
, msgID
); // challenge sent and lost
2264 else LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
);
2267 if (mDNSOpaque64IsZero(&llq
->id
))
2269 // client started over. reset state.
2270 LLQEntry
*newe
= NewLLQ(d
, e
->cli
, &e
->qname
, e
->qtype
, llq
->llqlease
);
2273 LLQSetupChallenge(d
, newe
, llq
, msgID
);
2276 else if (llq
->llqOp
== kLLQOp_Setup
)
2277 { LLQCompleteHandshake(d
, e
, llq
, msgID
, sock
); return; } // Ack lost
2278 else if (llq
->llqOp
== kLLQOp_Refresh
)
2279 { LLQRefresh(d
, e
, llq
, msgID
, sock
); return; }
2280 else { Log("Unhandled message for established LLQ"); return; }
2284 mDNSlocal LLQEntry
*LookupLLQ(DaemonInfo
*d
, struct sockaddr_in cli
, domainname
*qname
, mDNSu16 qtype
, const mDNSOpaque64
*const id
)
2286 int bucket
= bucket
= DomainNameHashValue(qname
) % LLQ_TABLESIZE
;
2287 LLQEntry
*ptr
= d
->LLQTable
[bucket
];
2291 if (((ptr
->state
== ChallengeSent
&& mDNSOpaque64IsZero(id
) && (cli
.sin_port
== ptr
->cli
.sin_port
)) || // zero-id due to packet loss OK in state ChallengeSent
2292 mDNSSameOpaque64(id
, &ptr
->id
)) && // id match
2293 (cli
.sin_addr
.s_addr
== ptr
->cli
.sin_addr
.s_addr
) && (qtype
== ptr
->qtype
) && SameDomainName(&ptr
->qname
, qname
)) // same source, type, qname
2310 pkt
->msg
.h
.flags
.b
[0] |= kDNSFlag0_QR_Response
;
2312 res
= sendto( d
->udpsd
, &pkt
->msg
, pkt
->len
, 0, ( struct sockaddr
* ) &pkt
->src
, sizeof( pkt
->src
) );
2313 require_action( res
== ( int ) pkt
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvNotify", "sendto" ) );
2321 mDNSlocal
int RecvLLQ( DaemonInfo
*d
, PktMsg
*pkt
, TCPSocket
*sock
)
2324 LargeCacheRecord opt
;
2327 const mDNSu8
*qptr
= pkt
->msg
.data
;
2328 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2330 LLQOptData
*llq
= NULL
;
2334 aptr
= LocateAdditionals(&pkt
->msg
, end
); // Can't do this until after HdrNToH(pkt);
2335 inet_ntop(AF_INET
, &pkt
->src
.sin_addr
, addr
, 32);
2337 VLog("Received LLQ msg from %s", addr
);
2338 // sanity-check packet
2339 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2341 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
2345 // Locate the OPT record.
2346 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2347 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2348 // but not necessarily the *last* entry in the Additional Section.
2349 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2351 aptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, aptr
, end
, 0, kDNSRecordTypePacketAdd
, &opt
);
2352 if (!aptr
) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr
, i
); goto end
; }
2353 if (opt
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& opt
.r
.resrec
.rrtype
== kDNSType_OPT
) break;
2357 if (opt
.r
.resrec
.rrtype
!= kDNSType_OPT
) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr
); goto end
; }
2358 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
); }
2360 // dispatch each question
2361 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
2363 qptr
= getQuestion(&pkt
->msg
, qptr
, end
, 0, &q
);
2364 if (!qptr
) { Log("Malformatted LLQ from %s: cannot read question %d", addr
, i
); goto end
; }
2365 llq
= (LLQOptData
*)&opt
.r
.resrec
.rdata
->u
.opt
[0].u
.llq
+ i
; // point into OptData at index i
2366 if (llq
->vers
!= kLLQ_Vers
) { Log("LLQ from %s contains bad version %d (expected %d)", addr
, llq
->vers
, kLLQ_Vers
); goto end
; }
2368 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2371 // no entry - if zero ID, create new
2372 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2375 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2385 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
2387 const mDNSu8
* lastPtr
= NULL
;
2388 const mDNSu8
* ptr
= NULL
;
2389 DomainAuthInfo
* keys
;
2390 mDNSu8
* end
= ( mDNSu8
* ) &pkt
->msg
+ pkt
->len
;
2391 LargeCacheRecord lcr
;
2392 mDNSBool hasTSIG
= mDNSfalse
;
2393 mDNSBool strip
= mDNSfalse
;
2394 mDNSBool ok
= mDNSfalse
;
2397 // Unused parameters
2405 if ( pkt
->msg
.h
.numAdditionals
)
2407 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2410 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2413 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2416 Log("Unable to read additional record");
2422 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2426 LogMsg( "IsAuthorized: unable to find Additional section" );
2430 // If we don't know what zone this is, then it's authorized.
2439 if ( IsQuery( pkt
) )
2441 keys
= pkt
->zone
->queryKeys
;
2444 else if ( IsUpdate( pkt
) )
2446 keys
= pkt
->zone
->updateKeys
;
2456 if ( pkt
->isZonePublic
)
2462 // If there are no keys, then we're authorized
2464 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
2466 Log( "Invalid TSIG spec %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2467 *rcode
= kDNSFlag1_RC_NotAuth
;
2468 *tcode
= TSIG_ErrBadKey
;
2474 // Find the right key
2476 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2478 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
2486 Log( "Invalid TSIG name %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2487 *rcode
= kDNSFlag1_RC_NotAuth
;
2488 *tcode
= TSIG_ErrBadKey
;
2494 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2495 // lifting of message verification
2497 pkt
->msg
.h
.numAdditionals
--;
2501 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2505 pkt
->msg
.h
.numAdditionals
++;
2509 if ( hasTSIG
&& strip
)
2511 // Strip the TSIG from the message
2513 pkt
->msg
.h
.numAdditionals
--;
2514 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2522 // request handler wrappers for TCP and UDP requests
2523 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2531 UDPContext
* context
= ( UDPContext
* ) vptr
;
2532 PktMsg
* reply
= NULL
;
2536 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2537 // may give us a long answer that would require truncation for UDP delivery to client
2539 reply
= HandleRequest( context
->d
, &context
->pkt
);
2540 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
2542 res
= sendto( context
->sd
, &reply
->msg
, reply
->len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2543 require_action_quiet( res
== ( int ) reply
->len
, exit
, LogErr( "UDPMessageHandler", "sendto" ) );
2554 pthread_exit( NULL
);
2567 UDPContext
* context
= NULL
;
2571 DomainAuthInfo
* key
;
2572 unsigned int clisize
= sizeof( context
->cliaddr
);
2574 mStatus err
= mStatus_NoError
;
2576 context
= malloc( sizeof( UDPContext
) );
2577 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2579 mDNSPlatformMemZero( context
, sizeof( *context
) );
2583 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
2585 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvUDPMessage", "recvfrom" ) );
2586 context
->pkt
.len
= res
;
2587 require_action( clisize
== sizeof( context
->cliaddr
), exit
, err
= mStatus_UnknownErr
; Log( "Client address of unknown size %d", clisize
) );
2588 context
->pkt
.src
= context
->cliaddr
;
2590 // Set the zone in the packet
2592 SetZone( context
->d
, &context
->pkt
);
2594 // Notify messages handled by main thread
2596 if ( IsNotify( &context
->pkt
) )
2598 int e
= RecvNotify( self
, &context
->pkt
);
2602 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2604 if ( IsLLQRequest( &context
->pkt
) )
2606 // LLQ messages handled by main thread
2607 int e
= RecvLLQ( self
, &context
->pkt
, NULL
);
2612 if ( IsLLQAck(&context
->pkt
) )
2614 // !!!KRS need to do acks + retrans
2620 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2621 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2623 pthread_detach(tid
);
2630 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2632 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2633 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_NXDomain
;
2635 e
= sendto( sd
, &reply
.msg
, reply
.len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2636 require_action_quiet( e
== ( int ) reply
.len
, exit
, LogErr( "RecvUDPMessage", "sendto" ) );
2638 err
= mStatus_NoAuth
;
2643 if ( err
&& context
)
2655 TCPContext
* context
2660 if ( context
->sock
)
2662 mDNSPlatformTCPCloseConnection( context
->sock
);
2676 TCPContext
* context
= ( TCPContext
* ) vptr
;
2677 PktMsg
* reply
= NULL
;
2681 //!!!KRS if this read blocks indefinitely, we can run out of threads
2684 reply
= HandleRequest( context
->d
, &context
->pkt
);
2685 require_action_quiet( reply
, exit
, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2687 // deliver reply to client
2689 res
= SendPacket( context
->sock
, reply
);
2690 require_action( res
>= 0, exit
, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2694 FreeTCPContext( context
);
2711 TCPContext
* context
= ( TCPContext
* ) param
;
2715 DomainAuthInfo
* key
;
2718 mDNSBool freeContext
= mDNStrue
;
2719 mStatus err
= mStatus_NoError
;
2721 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2722 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2723 // wire. We'll let it do that, and wait for the next packet which will be ours.
2725 pkt
= RecvPacket( context
->sock
, &context
->pkt
, &closed
);
2726 if (pkt
) HdrNToH(pkt
);
2727 require_action( pkt
|| !closed
, exit
, err
= mStatus_UnknownErr
; LogMsg( "client disconnected" ) );
2731 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2732 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2733 // are sent over UDP
2735 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2737 // Set's the DNS Zone that is associated with this message
2739 SetZone( context
->d
, &context
->pkt
);
2741 // IsAuthorized will make sure the message is authorized for the designated zone.
2742 // After verifying the signature, it will strip the TSIG from the message
2744 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2746 if ( IsLLQRequest( &context
->pkt
) )
2748 // LLQ messages handled by main thread
2749 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2753 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2757 LogErr( "RecvTCPMessage", "pthread_create" );
2758 err
= mStatus_NoError
;
2762 // Let the thread free the context
2764 freeContext
= mDNSfalse
;
2766 pthread_detach(tid
);
2773 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2775 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2777 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2778 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_Refused
;
2780 SendPacket( context
->sock
, &reply
);
2785 freeContext
= mDNSfalse
;
2792 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2797 FreeTCPContext( context
);
2807 TCPSocketFlags flags
2810 TCPContext
* context
= NULL
;
2811 unsigned int clilen
= sizeof( context
->cliaddr
);
2813 mStatus err
= mStatus_NoError
;
2815 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2816 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2817 mDNSPlatformMemZero( context
, sizeof( sizeof( TCPContext
) ) );
2819 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2820 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2822 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2823 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2825 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2826 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2830 if ( err
&& context
)
2841 // listen for incoming requests, periodically check table for expired records, respond to signals
2842 mDNSlocal
int Run(DaemonInfo
*d
)
2844 int staticMaxFD
, nfds
;
2846 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
2847 mDNSBool EventsPending
= mDNSfalse
;
2849 VLog("Listening for requests...");
2853 if ( d
->tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tcpsd
+ 1;
2854 if ( d
->udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->udpsd
+ 1;
2855 if ( d
->tlssd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tlssd
+ 1;
2856 if ( d
->llq_tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_tcpsd
+ 1;
2857 if ( d
->llq_udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_udpsd
+ 1;
2858 if ( d
->LLQEventListenSock
+ 1 > staticMaxFD
) staticMaxFD
= d
->LLQEventListenSock
+ 1;
2862 EventSource
* source
;
2866 timeout
.tv_sec
= timeout
.tv_usec
= 0;
2867 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2871 if (timenow
.tv_sec
- EventTS
.tv_sec
>= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2872 { GenLLQEvents(d
); EventsPending
= mDNSfalse
; } // events, we go ahead and do it now
2873 else timeout
.tv_usec
= 500000; // else do events after 1/2 second with no new events or LLQs
2877 // if no pending events, timeout when we need to check for expired records
2878 if (tablecheck
.tv_sec
&& timenow
.tv_sec
- tablecheck
.tv_sec
>= 0)
2879 { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; } // table check overdue
2880 if (!tablecheck
.tv_sec
) tablecheck
.tv_sec
= timenow
.tv_sec
+ EXPIRATION_INTERVAL
;
2881 timeout
.tv_sec
= tablecheck
.tv_sec
- timenow
.tv_sec
;
2885 FD_SET( d
->tcpsd
, &rset
);
2886 FD_SET( d
->udpsd
, &rset
);
2887 FD_SET( d
->tlssd
, &rset
);
2888 FD_SET( d
->llq_tcpsd
, &rset
);
2889 FD_SET( d
->llq_udpsd
, &rset
);
2890 FD_SET( d
->LLQEventListenSock
, &rset
);
2892 maxFD
= staticMaxFD
;
2894 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2896 FD_SET( source
->fd
, &rset
);
2898 if ( source
->fd
> maxFD
)
2904 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
2911 // close sockets to prevent clients from making new requests during shutdown
2915 close( d
->llq_tcpsd
);
2916 close( d
->llq_udpsd
);
2917 d
->tcpsd
= d
->udpsd
= d
->tlssd
= d
->llq_tcpsd
= d
->llq_udpsd
= -1;
2918 DeleteRecords(d
, mDNStrue
);
2923 Log( "Received SIGINFO" );
2934 Log( "Received SIGHUP" );
2936 err
= ParseConfig( d
, cfgfile
);
2940 LogErr( "Run", "ParseConfig" );
2948 Log("Received unhandled signal - continuing");
2953 LogErr("Run", "select"); return -1;
2958 if (FD_ISSET(d
->udpsd
, &rset
)) RecvUDPMessage( d
, d
->udpsd
);
2959 if (FD_ISSET(d
->llq_udpsd
, &rset
)) RecvUDPMessage( d
, d
->llq_udpsd
);
2960 if (FD_ISSET(d
->tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->tcpsd
, 0 );
2961 if (FD_ISSET(d
->llq_tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->llq_tcpsd
, 0 );
2962 if (FD_ISSET(d
->tlssd
, &rset
)) AcceptTCPConnection( d
, d
->tlssd
, TCP_SOCKET_FLAGS
);
2963 if (FD_ISSET(d
->LLQEventListenSock
, &rset
))
2965 // clear signalling data off socket
2967 recv(d
->LLQEventListenSock
, buf
, 256, 0);
2970 EventsPending
= mDNStrue
;
2971 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2975 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2977 if ( FD_ISSET( source
->fd
, &rset
) )
2979 source
->callback( source
->context
);
2980 break; // in case we removed this guy from the event loop
2987 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
2988 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
2994 // signal handler sets global variables, which are inspected by main event loop
2995 // (select automatically returns due to the handled signal)
2996 mDNSlocal
void HndlSignal(int sig
)
2998 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
2999 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
3000 if (sig
== SIGHUP
) { hangup
= 1; return; }
3010 DNameListElem
* elem
;
3011 mStatus err
= mStatus_NoError
;
3013 elem
= ( DNameListElem
* ) malloc( sizeof( DNameListElem
) );
3014 require_action( elem
, exit
, err
= mStatus_NoMemoryErr
);
3015 MakeDomainNameFromDNSNameString( &elem
->name
, name
);
3016 elem
->next
= d
->public_names
;
3017 d
->public_names
= elem
;
3025 int main(int argc
, char *argv
[])
3027 int started_via_launchd
= 0;
3031 Log("dnsextd starting");
3033 d
= malloc(sizeof(*d
));
3034 if (!d
) { LogErr("main", "malloc"); exit(1); }
3035 mDNSPlatformMemZero(d
, sizeof(DaemonInfo
));
3037 // Setup the public SRV record names
3039 SetPublicSRV(d
, "_dns-update._udp.");
3040 SetPublicSRV(d
, "_dns-llq._udp.");
3041 SetPublicSRV(d
, "_dns-update-tls._tcp.");
3042 SetPublicSRV(d
, "_dns-query-tls._tcp.");
3043 SetPublicSRV(d
, "_dns-llq-tls._tcp.");
3045 // Setup signal handling
3047 if (signal(SIGHUP
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGHUP");
3048 if (signal(SIGTERM
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGTERM");
3049 if (signal(INFO_SIGNAL
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINFO");
3050 if (signal(SIGINT
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINT");
3051 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) perror("Can't ignore SIGPIPE");
3053 // remove open file limit
3054 rlim
.rlim_max
= RLIM_INFINITY
;
3055 rlim
.rlim_cur
= RLIM_INFINITY
;
3056 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3058 LogErr("main", "setrlimit");
3059 Log("Using default file descriptor resource limit");
3062 if (argc
> 1 && !strcasecmp(argv
[1], "-launchd"))
3064 Log("started_via_launchd");
3065 started_via_launchd
= 1;
3069 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3071 if (!foreground
&& !started_via_launchd
)
3075 LogErr("main", "daemon");
3080 if (InitLeaseTable(d
) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3081 if (SetupSockets(d
) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3082 if (SetUpdateSRV(d
) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3086 Log("dnsextd stopping");
3088 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3094 // These are stubbed out implementations of up-call routines that the various platform support layers
3095 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3096 // link this code in.
3098 // It's an error for these routines to actually be called, so perhaps we should log any call
3100 void mDNSCoreInitComplete( mDNS
* const m
, mStatus result
) { ( void ) m
; ( void ) result
; }
3101 void mDNS_ConfigChanged(mDNS
*const m
) { ( void ) m
; }
3102 void mDNSCoreMachineSleep(mDNS
* const m
, mDNSBool wake
) { ( void ) m
; ( void ) wake
; }
3103 void mDNSCoreReceive(mDNS
*const m
, void *const msg
, const mDNSu8
*const end
,
3104 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
,
3105 const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID iid
)
3106 { ( void ) m
; ( void ) msg
; ( void ) end
; ( void ) srcaddr
; ( void ) srcport
; ( void ) dstaddr
; ( void ) dstport
; ( void ) iid
; }
3107 DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const mDNSAddr
*addr
, const mDNSIPPort port
, mDNSBool scoped
, mDNSu32 timeout
, mDNSBool cellIntf
, mDNSu16 resGroupID
)
3108 { ( void ) m
; ( void ) d
; ( void ) interface
; ( void ) addr
; ( void ) port
; ( void ) scoped
; ( void ) timeout
; (void) cellIntf
; (void) resGroupID
; return(NULL
); }
3109 void mDNS_AddSearchDomain(const domainname
*const domain
, mDNSInterfaceID InterfaceID
) { (void)domain
; (void) InterfaceID
;}
3110 void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3111 { ( void ) m
; ( void ) fqdn
; ( void ) StatusCallback
; ( void ) StatusContext
; }
3112 mDNSs32
mDNS_Execute (mDNS
*const m
) { ( void ) m
; return 0; }
3113 mDNSs32
mDNS_TimeNow(const mDNS
*const m
) { ( void ) m
; return 0; }
3114 mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3115 void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3116 { ( void ) m
; ( void ) set
; ( void ) flapping
; }
3117 const char * const mDNS_DomainTypeNames
[1] = {};
3118 mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
3119 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
3120 { ( void ) m
; ( void ) question
; ( void ) DomainType
; ( void ) dom
; ( void ) InterfaceID
; ( void ) Callback
; ( void ) Context
; return 0; }
3121 mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3122 mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, mDNSBool flapping
)
3123 { ( void ) m
; ( void ) set
; ( void ) flapping
; return 0; }
3124 void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
) { ( void ) m
; ( void ) fqdn
; }
3125 void mDNS_SetFQDN(mDNS
* const m
) { ( void ) m
; }
3126 void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3127 { ( void ) m
; ( void ) v4addr
; ( void ) v6addr
; ( void ) router
; }
3128 mStatus
uDNS_SetupDNSConfig( mDNS
*const m
) { ( void ) m
; return 0; }
3129 mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
3130 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, const domainname
*hostname
, mDNSIPPort
*port
, mDNSBool autoTunnel
)
3131 { ( void ) m
; ( void ) info
; ( void ) domain
; ( void ) keyname
; ( void ) b64keydata
; ( void ) hostname
; (void) port
; ( void ) autoTunnel
; return 0; }
3132 mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
) { ( void ) m
; ( void ) question
; return 0; }
3133 void TriggerEventCompletion(void);
3134 void TriggerEventCompletion() {}
3138 // For convenience when using the "strings" command, this is the last thing in the file
3139 // The "@(#) " pattern is a special prefix the "what" command looks for
3140 const char mDNSResponderVersionString_SCCS
[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
3142 #if _BUILDING_XCODE_PROJECT_
3143 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3144 const char *__crashreporter_info__
= mDNSResponderVersionString_SCCS
+ 5;
3145 asm (".desc ___crashreporter_info__, 0x10");