2 * Copyright (c) 2002-2019 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 // In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
19 // error, which prevents compilation because we build with "-Werror".
20 // Since this is supposed to be portable cross-platform code, we don't care that daemon is
21 // deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
22 #define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
37 #include <sys/resource.h>
43 extern int daemon(int, int);
46 // Solaris doesn't have daemon(), so we define it here
47 #ifdef NOT_HAVE_DAEMON
48 #include "../mDNSPosix/mDNSUNP.h" // For daemon()
49 #endif // NOT_HAVE_DAEMON
52 #include "../mDNSShared/uds_daemon.h"
53 #include "../mDNSShared/dnssd_ipc.h"
54 #include "../mDNSCore/uDNS.h"
55 #include "../mDNSShared/DebugServices.h"
57 // Compatibility workaround
59 #define AF_LOCAL AF_UNIX
65 mDNSexport
const char ProgramName
[] = "dnsextd";
67 #define LOOPBACK "127.0.0.1"
69 # define LISTENQ 128 // tcp connection backlog
71 #define RECV_BUFLEN 9000
72 #define LEASETABLE_INIT_NBUCKETS 256 // initial hashtable size (doubles as table fills)
73 #define EXPIRATION_INTERVAL 300 // check for expired records every 5 minutes
74 #define SRV_TTL 7200 // TTL For _dns-update SRV records
75 #define CONFIG_FILE "/etc/dnsextd.conf"
76 #define TCP_SOCKET_FLAGS kTCPSocketFlags_UseTLS
78 // LLQ Lease bounds (seconds)
79 #define LLQ_MIN_LEASE (15 * 60)
80 #define LLQ_MAX_LEASE (120 * 60)
81 #define LLQ_LEASE_FUDGE 60
83 // LLQ SOA poll interval (microseconds)
84 #define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
85 #define LLQ_MONITOR_INTERVAL 250000
87 #define INFO_SIGNAL SIGINFO
89 #define INFO_SIGNAL SIGUSR1
92 #define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
96 // Structs/fields that must be locked for thread safety are explicitly commented
99 // args passed to UDP request handler thread as void*
104 struct sockaddr_in cliaddr
;
109 // args passed to TCP request handler thread as void*
113 struct sockaddr_in cliaddr
;
114 TCPSocket
*sock
; // socket connected to client
118 // args passed to UpdateAnswerList thread as void*
123 } UpdateAnswerListArgs
;
129 // booleans to determine runtime output
130 // read-only after initialization (no mutex protection)
131 static mDNSBool foreground
= 0;
132 static mDNSBool verbose
= 0;
134 // globals set via signal handler (accessed exclusively by main select loop and signal handler)
135 static mDNSBool terminate
= 0;
136 static mDNSBool dumptable
= 0;
137 static mDNSBool hangup
= 0;
139 // global for config file location
140 static char * cfgfile
= NULL
;
144 // Log messages are delivered to syslog unless -f option specified
147 // common message logging subroutine
148 mDNSlocal
void PrintLog(const char *buffer
)
152 fprintf(stderr
,"%s\n", buffer
);
157 openlog("dnsextd", LOG_CONS
, LOG_DAEMON
);
158 syslog(LOG_ERR
, "%s", buffer
);
163 // Verbose Logging (conditional on -v option)
164 mDNSlocal
void VLog(const char *format
, ...)
169 if (!verbose
) return;
170 va_start(ptr
,format
);
171 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
176 // Unconditional Logging
177 mDNSlocal
void Log(const char *format
, ...)
182 va_start(ptr
,format
);
183 buffer
[mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
)] = 0;
189 // prints message "dnsextd <function>: <operation> - <error message>"
190 // must be compiled w/ -D_REENTRANT for thread-safe errno usage
191 mDNSlocal
void LogErr(const char *fn
, const char *operation
)
193 char buf
[512], errbuf
[256];
194 strerror_r(errno
, errbuf
, sizeof(errbuf
));
195 snprintf(buf
, sizeof(buf
), "%s: %s - %s", fn
, operation
, errbuf
);
200 // Networking Utility Routines
203 // Convert DNS Message Header from Network to Host byte order
204 mDNSlocal
void HdrNToH(PktMsg
*pkt
)
206 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
207 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
208 pkt
->msg
.h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
209 pkt
->msg
.h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
210 pkt
->msg
.h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
211 pkt
->msg
.h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
214 // Convert DNS Message Header from Host to Network byte order
215 mDNSlocal
void HdrHToN(PktMsg
*pkt
)
217 mDNSu16 numQuestions
= pkt
->msg
.h
.numQuestions
;
218 mDNSu16 numAnswers
= pkt
->msg
.h
.numAnswers
;
219 mDNSu16 numAuthorities
= pkt
->msg
.h
.numAuthorities
;
220 mDNSu16 numAdditionals
= pkt
->msg
.h
.numAdditionals
;
221 mDNSu8
*ptr
= (mDNSu8
*)&pkt
->msg
.h
.numQuestions
;
223 // Put all the integer values in IETF byte-order (MSB first, LSB second)
224 *ptr
++ = (mDNSu8
)(numQuestions
>> 8);
225 *ptr
++ = (mDNSu8
)(numQuestions
& 0xFF);
226 *ptr
++ = (mDNSu8
)(numAnswers
>> 8);
227 *ptr
++ = (mDNSu8
)(numAnswers
& 0xFF);
228 *ptr
++ = (mDNSu8
)(numAuthorities
>> 8);
229 *ptr
++ = (mDNSu8
)(numAuthorities
& 0xFF);
230 *ptr
++ = (mDNSu8
)(numAdditionals
>> 8);
231 *ptr
++ = (mDNSu8
)(numAdditionals
& 0xFF);
235 // Add socket to event loop
237 mDNSlocal mStatus
AddSourceToEventLoop( DaemonInfo
* self
, TCPSocket
*sock
, EventCallback callback
, void *context
)
239 EventSource
* newSource
;
240 mStatus err
= mStatus_NoError
;
242 if ( self
->eventSources
.LinkOffset
== 0 )
244 InitLinkedList( &self
->eventSources
, offsetof( EventSource
, next
));
247 newSource
= ( EventSource
*) malloc( sizeof *newSource
);
248 if ( newSource
== NULL
)
250 err
= mStatus_NoMemoryErr
;
254 newSource
->callback
= callback
;
255 newSource
->context
= context
;
256 newSource
->sock
= sock
;
257 newSource
->fd
= mDNSPlatformTCPGetFD( sock
);
259 AddToTail( &self
->eventSources
, newSource
);
267 // Remove socket from event loop
269 mDNSlocal mStatus
RemoveSourceFromEventLoop( DaemonInfo
* self
, TCPSocket
*sock
)
271 EventSource
* source
;
274 for ( source
= ( EventSource
* ) self
->eventSources
.Head
; source
; source
= source
->next
)
276 if ( source
->sock
== sock
)
278 RemoveFromList( &self
->eventSources
, source
);
281 err
= mStatus_NoError
;
286 err
= mStatus_NoSuchNameErr
;
293 // create a socket connected to nameserver
294 // caller terminates connection via close()
295 mDNSlocal TCPSocket
*ConnectToServer(DaemonInfo
*d
)
297 int ntries
= 0, retry
= 0;
301 mDNSIPPort port
= zeroIPPort
;
304 TCPSocket
*sock
= mDNSPlatformTCPSocket(0, mDNSAddrType_IPv4
, &port
, NULL
, mDNSfalse
);
305 if ( !sock
) { LogErr("ConnectToServer", "socket"); return NULL
; }
306 fd
= mDNSPlatformTCPGetFD( sock
);
307 if (!connect( fd
, (struct sockaddr
*)&d
->ns_addr
, sizeof(d
->ns_addr
))) return sock
;
308 mDNSPlatformTCPCloseConnection( sock
);
311 LogErr("ConnectToServer", "connect");
312 Log("ConnectToServer - retrying connection");
313 if (!retry
) retry
= 500000 + random() % 500000;
317 else { Log("ConnectToServer - %d failed attempts. Aborting.", ntries
); return NULL
; }
321 // send an entire block of data over a connected socket
322 mDNSlocal
int MySend(TCPSocket
*sock
, const void *msg
, int len
)
324 int selectval
, n
, nsent
= 0;
326 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
334 fd
= mDNSPlatformTCPGetFD( sock
);
337 selectval
= select( fd
+1, NULL
, &wset
, NULL
, &timeout
);
338 if (selectval
< 0) { LogErr("MySend", "select"); return -1; }
339 if (!selectval
|| !FD_ISSET(fd
, &wset
)) { Log("MySend - timeout"); return -1; }
341 n
= mDNSPlatformWriteTCP( sock
, ( char* ) msg
+ nsent
, len
- nsent
);
343 if (n
< 0) { LogErr("MySend", "send"); return -1; }
349 // Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
350 mDNSlocal
int SendPacket(TCPSocket
*sock
, PktMsg
*pkt
)
352 // send the lenth, in network byte order
353 mDNSu16 len
= htons((mDNSu16
)pkt
->len
);
354 if (MySend(sock
, &len
, sizeof(len
)) < 0) return -1;
357 VLog("SendPacket Q:%d A:%d A:%d A:%d ",
358 ntohs(pkt
->msg
.h
.numQuestions
),
359 ntohs(pkt
->msg
.h
.numAnswers
),
360 ntohs(pkt
->msg
.h
.numAuthorities
),
361 ntohs(pkt
->msg
.h
.numAdditionals
));
362 return MySend(sock
, &pkt
->msg
, pkt
->len
);
365 // Receive len bytes, waiting until we have all of them.
366 // Returns number of bytes read (which should always be the number asked for).
367 static int my_recv(TCPSocket
*sock
, void *const buf
, const int len
, mDNSBool
* closed
)
369 // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
370 // use an explicit while() loop instead.
371 // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
372 // arithmetic on "void *" pointers is compiler-dependent.
375 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
376 int selectval
, remaining
= len
;
377 char *ptr
= (char *)buf
;
384 fd
= mDNSPlatformTCPGetFD( sock
);
388 selectval
= select(fd
+1, &rset
, NULL
, NULL
, &timeout
);
389 if (selectval
< 0) { LogErr("my_recv", "select"); return -1; }
390 if (!selectval
|| !FD_ISSET(fd
, &rset
))
392 Log("my_recv - timeout");
396 num_read
= mDNSPlatformReadTCP( sock
, ptr
, remaining
, closed
);
398 if (((num_read
== 0) && *closed
) || (num_read
< 0) || (num_read
> remaining
)) return -1;
399 if (num_read
== 0) return 0;
401 remaining
-= num_read
;
406 // Return a DNS Message read off of a TCP socket, or NULL on failure
407 // If storage is non-null, result is placed in that buffer. Otherwise,
408 // returned value is allocated with Malloc, and contains sufficient extra
409 // storage for a Lease OPT RR
427 fd
= mDNSPlatformTCPGetFD( sock
);
429 nread
= my_recv( sock
, &msglen
, sizeof( msglen
), closed
);
431 require_action_quiet( nread
!= -1, exit
, err
= mStatus_UnknownErr
);
432 require_action_quiet( nread
> 0, exit
, err
= mStatus_NoError
);
434 msglen
= ntohs( msglen
);
435 require_action_quiet( nread
== sizeof( msglen
), exit
, err
= mStatus_UnknownErr
; Log( "Could not read length field of message") );
439 require_action_quiet( msglen
<= sizeof( storage
->msg
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: provided buffer too small." ) );
444 // buffer extra space to add an OPT RR
446 if ( msglen
> sizeof(DNSMessage
))
448 allocsize
= sizeof(PktMsg
) - sizeof(DNSMessage
) + msglen
;
452 allocsize
= sizeof(PktMsg
);
455 pkt
= malloc(allocsize
);
456 require_action_quiet( pkt
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvPacket", "malloc" ) );
457 mDNSPlatformMemZero( pkt
, sizeof( *pkt
) );
461 srclen
= sizeof(pkt
->src
);
463 if ( getpeername( fd
, ( struct sockaddr
* ) &pkt
->src
, &srclen
) || ( srclen
!= sizeof( pkt
->src
) ) )
465 LogErr("RecvPacket", "getpeername");
466 mDNSPlatformMemZero(&pkt
->src
, sizeof(pkt
->src
));
469 nread
= my_recv(sock
, &pkt
->msg
, msglen
, closed
);
470 require_action_quiet( nread
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvPacket", "recv" ) );
471 require_action_quiet( nread
== msglen
, exit
, err
= mStatus_UnknownErr
; Log( "Could not read entire message" ) );
472 require_action_quiet( pkt
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "RecvPacket: Message too short (%d bytes)", pkt
->len
) );
478 if ( pkt
!= storage
)
499 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
501 if ( SameDomainName( &zone
->name
, name
) )
514 const domainname
* zname
,
515 const domainname
* dname
518 mDNSu16 i
= DomainNameLength( zname
);
519 mDNSu16 j
= DomainNameLength( dname
);
521 if ( ( i
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( j
== ( MAX_DOMAIN_NAME
+ 1 ) ) || ( i
> j
) || ( memcmp( zname
->c
, dname
->c
+ ( j
- i
), i
) != 0 ) )
530 mDNSlocal mDNSBool
IsQuery( PktMsg
* pkt
)
532 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
);
536 mDNSlocal mDNSBool
IsUpdate( PktMsg
* pkt
)
538 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == (mDNSu8
) ( kDNSFlag0_OP_Update
);
542 mDNSlocal mDNSBool
IsNotify(PktMsg
*pkt
)
544 return ( pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) == ( mDNSu8
) ( kDNSFlag0_OP_Notify
);
548 mDNSlocal mDNSBool
IsLLQRequest(PktMsg
*pkt
)
550 const mDNSu8
*ptr
= NULL
, *end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
551 LargeCacheRecord lcr
;
553 mDNSBool result
= mDNSfalse
;
556 if ((mDNSu8
)(pkt
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (mDNSu8
)(kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
)) goto end
;
558 if (!pkt
->msg
.h
.numAdditionals
) goto end
;
559 ptr
= LocateAdditionals(&pkt
->msg
, end
);
562 bzero(&lcr
, sizeof(lcr
));
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
] )
631 const mDNSu8
* ptr
= pkt
->msg
.data
;
632 mDNSBool exception
= mDNSfalse
;
637 pkt
->isZonePublic
= mDNStrue
;
640 // Figure out what type of packet this is
642 if ( IsQuery( pkt
) )
644 DNSQuestion question
;
648 getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
650 AppendDomainName( &zname
, &question
.qname
);
652 exception
= ( ( question
.qtype
== kDNSType_SOA
) || ( question
.qtype
== kDNSType_NS
) || ( ( question
.qtype
== kDNSType_SRV
) && IsPublicSRV( self
, &question
) ) );
654 else if ( IsUpdate( pkt
) )
656 DNSQuestion question
;
658 // It's an update. The format of the zone section is the same as the format for the question section
659 // according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
661 getQuestion( &pkt
->msg
, ptr
, ( ( mDNSu8
* ) &pkt
->msg
) + pkt
->len
, NULL
, &question
);
663 AppendDomainName( &zname
, &question
.qname
);
665 exception
= mDNSfalse
;
668 if ( zname
.c
[0] != '\0' )
670 // Find the right zone
672 for ( pkt
->zone
= self
->zones
; pkt
->zone
; pkt
->zone
= pkt
->zone
->next
)
674 if ( ZoneHandlesName( &pkt
->zone
->name
, &zname
) )
676 VLog( "found correct zone %##s for query", pkt
->zone
->name
.c
);
678 pkt
->isZonePublic
= ( ( pkt
->zone
->type
== kDNSZonePublic
) || exception
);
680 VLog( "zone %##s is %s", pkt
->zone
->name
.c
, ( pkt
->isZonePublic
) ? "public" : "private" );
690 UDPServerTransaction(const DaemonInfo
*d
, const PktMsg
*request
, PktMsg
*reply
, mDNSBool
*trunc
)
693 struct timeval timeout
= { 3, 0 }; // until we remove all calls from main thread, keep timeout short
696 mStatus err
= mStatus_NoError
;
704 sd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
705 require_action( sd
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "socket" ) );
707 // Send the packet to the nameserver
709 VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
710 ntohs(request
->msg
.h
.numQuestions
),
711 ntohs(request
->msg
.h
.numAnswers
),
712 ntohs(request
->msg
.h
.numAuthorities
),
713 ntohs(request
->msg
.h
.numAdditionals
));
714 res
= sendto( sd
, (char *)&request
->msg
, request
->len
, 0, ( struct sockaddr
* ) &d
->ns_addr
, sizeof( d
->ns_addr
) );
715 require_action( res
== (int) request
->len
, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "sendto" ) );
721 res
= select( sd
+ 1, &rset
, NULL
, NULL
, &timeout
);
722 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "select" ) );
723 require_action( ( res
> 0 ) && FD_ISSET( sd
, &rset
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - timeout" ) );
727 reply
->len
= recvfrom( sd
, &reply
->msg
, sizeof(reply
->msg
), 0, NULL
, NULL
);
728 require_action( ( ( int ) reply
->len
) >= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "UDPServerTransaction", "recvfrom" ) );
729 require_action( reply
->len
>= sizeof( DNSMessageHeader
), exit
, err
= mStatus_UnknownErr
; Log( "UDPServerTransaction - Message too short (%d bytes)", reply
->len
) );
731 // Check for truncation bit
733 if ( reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_TC
)
749 // Dynamic Update Utility Routines
752 // check if a request and server response complete a successful dynamic update
753 mDNSlocal mDNSBool
SuccessfulUpdateTransaction(PktMsg
*request
, PktMsg
*reply
)
756 char *vlogmsg
= NULL
;
759 if (!request
|| !reply
) { vlogmsg
= "NULL message"; goto failure
; }
760 if (request
->len
< sizeof(DNSMessageHeader
) || reply
->len
< sizeof(DNSMessageHeader
)) { vlogmsg
= "Malformatted message"; goto failure
; }
762 // check request operation
763 if ((request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (request
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
))
764 { vlogmsg
= "Request opcode not an update"; goto failure
; }
767 if ((reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
)) { vlogmsg
= "Reply contains non-zero rcode"; goto failure
; }
768 if ((reply
->msg
.h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
) != (kDNSFlag0_OP_Update
| kDNSFlag0_QR_Response
))
769 { vlogmsg
= "Reply opcode not an update response"; goto failure
; }
771 VLog("Successful update from %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32));
775 VLog("Request %s: %s", inet_ntop(AF_INET
, &request
->src
.sin_addr
, buf
, 32), vlogmsg
);
779 // Allocate an appropriately sized CacheRecord and copy data from original.
780 // Name pointer in CacheRecord object is set to point to the name specified
782 mDNSlocal CacheRecord
*CopyCacheRecord(const CacheRecord
*orig
, domainname
*name
)
785 size_t size
= sizeof(*cr
);
786 if (orig
->resrec
.rdlength
> InlineCacheRDSize
) size
+= orig
->resrec
.rdlength
- InlineCacheRDSize
;
788 if (!cr
) { LogErr("CopyCacheRecord", "malloc"); return NULL
; }
789 memcpy(cr
, orig
, size
);
790 cr
->resrec
.rdata
= (RData
*)&cr
->smallrdatastorage
;
791 cr
->resrec
.name
= name
;
798 // Lease Hashtable Utility Routines
801 // double hash table size
802 // caller must lock table prior to invocation
803 mDNSlocal
void RehashTable(DaemonInfo
*d
)
805 RRTableElem
*ptr
, *tmp
, **new;
806 int i
, bucket
, newnbuckets
= d
->nbuckets
* 2;
808 VLog("Rehashing lease table (new size %d buckets)", newnbuckets
);
809 new = malloc(sizeof(RRTableElem
*) * newnbuckets
);
810 if (!new) { LogErr("RehashTable", "malloc"); return; }
811 mDNSPlatformMemZero(new, newnbuckets
* sizeof(RRTableElem
*));
813 for (i
= 0; i
< d
->nbuckets
; i
++)
818 bucket
= ptr
->rr
.resrec
.namehash
% newnbuckets
;
821 tmp
->next
= new[bucket
];
825 d
->nbuckets
= newnbuckets
;
830 // print entire contents of hashtable, invoked via SIGINFO
831 mDNSlocal
void PrintLeaseTable(DaemonInfo
*d
)
835 char rrbuf
[MaxMsg
], addrbuf
[16];
839 if (gettimeofday(&now
, NULL
)) { LogErr("PrintTable", "gettimeofday"); return; }
840 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
842 Log("Dumping Lease Table Contents (table contains %d resource records)", d
->nelems
);
843 for (i
= 0; i
< d
->nbuckets
; i
++)
845 for (ptr
= d
->table
[i
]; ptr
; ptr
= ptr
->next
)
847 hr
= ((ptr
->expire
- now
.tv_sec
) / 60) / 60;
848 min
= ((ptr
->expire
- now
.tv_sec
) / 60) % 60;
849 sec
= (ptr
->expire
- now
.tv_sec
) % 60;
850 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
,
851 GetRRDisplayString_rdb(&ptr
->rr
.resrec
, &ptr
->rr
.resrec
.rdata
->u
, rrbuf
));
854 pthread_mutex_unlock(&d
->tablelock
);
858 // Startup SRV Registration Routines
859 // Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
860 // the daemon accepts requests
863 // delete all RRS of a given name/type
864 mDNSlocal mDNSu8
*putRRSetDeletion(DNSMessage
*msg
, mDNSu8
*ptr
, mDNSu8
*limit
, ResourceRecord
*rr
)
866 ptr
= putDomainNameAsLabels(msg
, ptr
, limit
, rr
->name
);
867 if (!ptr
|| ptr
+ 10 >= limit
) return NULL
; // out of space
868 ptr
[0] = (mDNSu8
)(rr
->rrtype
>> 8);
869 ptr
[1] = (mDNSu8
)(rr
->rrtype
& 0xFF);
870 ptr
[2] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
>> 8);
871 ptr
[3] = (mDNSu8
)((mDNSu16
)kDNSQClass_ANY
& 0xFF);
872 mDNSPlatformMemZero(ptr
+4, sizeof(rr
->rroriginalttl
) + sizeof(rr
->rdlength
)); // zero ttl/rdata
873 msg
->h
.mDNS_numUpdates
++;
877 mDNSlocal mDNSu8
*PutUpdateSRV(DaemonInfo
*d
, DNSZone
* zone
, PktMsg
*pkt
, mDNSu8
*ptr
, char *regtype
, mDNSIPPort port
, mDNSBool registration
)
880 char hostname
[1024], buf
[MaxMsg
];
881 mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ sizeof(DNSMessage
);
885 mDNS_SetupResourceRecord(&rr
, NULL
, 0, kDNSType_SRV
, SRV_TTL
, kDNSRecordTypeUnique
, AuthRecordAny
, NULL
, NULL
);
886 rr
.resrec
.rrclass
= kDNSClass_IN
;
887 rr
.resrec
.rdata
->u
.srv
.priority
= 0;
888 rr
.resrec
.rdata
->u
.srv
.weight
= 0;
889 rr
.resrec
.rdata
->u
.srv
.port
= port
;
890 if (gethostname(hostname
, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr
.resrec
.rdata
->u
.srv
.target
, hostname
))
891 rr
.resrec
.rdata
->u
.srv
.target
.c
[0] = '\0';
893 MakeDomainNameFromDNSNameString(&rr
.namestorage
, regtype
);
894 AppendDomainName(&rr
.namestorage
, &zone
->name
);
895 VLog("%s %s", registration
? "Registering SRV record" : "Deleting existing RRSet",
896 GetRRDisplayString_rdb(&rr
.resrec
, &rr
.resrec
.rdata
->u
, buf
));
897 if (registration
) ptr
= PutResourceRecord(&pkt
->msg
, ptr
, &pkt
->msg
.h
.mDNS_numUpdates
, &rr
.resrec
);
898 else ptr
= putRRSetDeletion(&pkt
->msg
, ptr
, end
, &rr
.resrec
);
903 // perform dynamic update.
904 // specify deletion by passing false for the register parameter, otherwise register the records.
905 mDNSlocal
int UpdateSRV(DaemonInfo
*d
, mDNSBool registration
)
907 TCPSocket
*sock
= NULL
;
909 int err
= mStatus_NoError
;
911 sock
= ConnectToServer( d
);
912 require_action( sock
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: ConnectToServer failed" ) );
914 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
917 mDNSu8
*ptr
= pkt
.msg
.data
;
918 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
919 PktMsg
*reply
= NULL
;
923 // Initialize message
924 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
925 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
926 pkt
.src
.sin_family
= AF_INET
;
928 // format message body
929 ptr
= putZone(&pkt
.msg
, ptr
, end
, &zone
->name
, mDNSOpaque16fromIntVal(kDNSClass_IN
));
930 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
932 if ( zone
->type
== kDNSZonePrivate
)
934 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls._tcp.", d
->private_port
, registration
);
935 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
936 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls._tcp.", d
->private_port
, registration
);
937 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
938 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls._tcp.", d
->private_port
, registration
);
939 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
943 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
944 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
945 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
946 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
953 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update-tls.", d
->private_port
, registration
);
954 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
955 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-query-tls.", d
->private_port
, registration
);
956 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
957 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq-tls.", d
->private_port
, registration
);
958 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
961 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-update._udp.", d
->llq_port
, registration
);
962 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
963 ptr
= PutUpdateSRV(d
, zone
, &pkt
, ptr
, "_dns-llq._udp.", d
->llq_port
, registration
);
964 require_action( ptr
, exit
, err
= mStatus_UnknownErr
; Log("UpdateSRV: Error constructing lease expiration update" ) );
969 if ( zone
->updateKeys
)
971 DNSDigest_SignMessage( &pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
972 require_action( ptr
, exit
, Log("UpdateSRV: Error constructing lease expiration update" ) );
975 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
977 // send message, receive reply
979 err
= SendPacket( sock
, &pkt
);
980 require_action( !err
, exit
, Log( "UpdateSRV: SendPacket failed" ) );
982 reply
= RecvPacket( sock
, NULL
, &closed
);
983 require_action( reply
, exit
, err
= mStatus_UnknownErr
; Log( "UpdateSRV: RecvPacket returned NULL" ) );
985 ok
= SuccessfulUpdateTransaction( &pkt
, reply
);
989 Log("SRV record registration failed with rcode %d", reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
);
999 mDNSPlatformTCPCloseConnection( sock
);
1005 // wrapper routines/macros
1006 #define ClearUpdateSRV(d) UpdateSRV(d, 0)
1008 // clear any existing records prior to registration
1009 mDNSlocal
int SetUpdateSRV(DaemonInfo
*d
)
1013 err
= ClearUpdateSRV(d
); // clear any existing record
1014 if (!err
) err
= UpdateSRV(d
, 1);
1019 // Argument Parsing and Configuration
1022 mDNSlocal
void PrintUsage(void)
1024 fprintf(stderr
, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
1025 "Use \"dnsextd -h\" for help\n");
1028 mDNSlocal
void PrintHelp(void)
1030 fprintf(stderr
, "\n\n");
1034 "dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
1035 "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
1036 "that do not natively support these extensions. (See dns-sd.org for more info on DNS Service\n"
1037 "Discovery, Update Leases, and Long Lived Queries.)\n\n"
1039 "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
1040 "and Long Lived Queries are to be administered. dnsextd communicates directly with the\n"
1041 "primary master server for this zone.\n\n"
1043 "The options are as follows:\n\n"
1045 "-f Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
1047 "-d Run daemon in foreground.\n\n"
1049 "-h Print help.\n\n"
1051 "-v Verbose output.\n\n"
1056 // Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
1057 // returns 0 (success) if program is to continue execution
1058 // output control arguments (-f, -v) do not affect this routine
1059 mDNSlocal
int ProcessArgs(int argc
, char *argv
[], DaemonInfo
*d
)
1065 cfgfile
= strdup( CONFIG_FILE
);
1066 require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
);
1068 // defaults, may be overriden by command option
1070 // setup our sockaddr
1072 mDNSPlatformMemZero( &d
->addr
, sizeof( d
->addr
) );
1073 d
->addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1074 d
->addr
.sin_port
= UnicastDNSPort
.NotAnInteger
;
1075 d
->addr
.sin_family
= AF_INET
;
1076 #ifndef NOT_HAVE_SA_LEN
1077 d
->addr
.sin_len
= sizeof( d
->addr
);
1080 // setup nameserver's sockaddr
1082 mDNSPlatformMemZero(&d
->ns_addr
, sizeof(d
->ns_addr
));
1083 d
->ns_addr
.sin_family
= AF_INET
;
1084 inet_pton( AF_INET
, LOOPBACK
, &d
->ns_addr
.sin_addr
);
1085 d
->ns_addr
.sin_port
= NSIPCPort
.NotAnInteger
;
1086 #ifndef NOT_HAVE_SA_LEN
1087 d
->ns_addr
.sin_len
= sizeof( d
->ns_addr
);
1092 d
->private_port
= PrivateDNSPort
;
1093 d
->llq_port
= DNSEXTPort
;
1095 while ((opt
= getopt(argc
, argv
, "f:hdv")) != -1)
1099 case 'f': free( cfgfile
); cfgfile
= strdup( optarg
); require_action( cfgfile
, arg_error
, err
= mStatus_NoMemoryErr
); break;
1100 case 'h': PrintHelp(); return -1;
1101 case 'd': foreground
= 1; break; // Also used when launched via OS X's launchd mechanism
1102 case 'v': verbose
= 1; break;
1103 default: goto arg_error
;
1107 err
= ParseConfig( d
, cfgfile
);
1108 require_noerr( err
, arg_error
);
1110 // Make sure we've specified some zones
1112 require_action( d
->zones
, arg_error
, err
= mStatus_UnknownErr
);
1114 // if we have a shared secret, use it for the entire zone
1116 for ( zone
= d
->zones
; zone
; zone
= zone
->next
)
1118 if ( zone
->updateKeys
)
1120 AssignDomainName( &zone
->updateKeys
->domain
, &zone
->name
);
1134 // Initialization Routines
1137 // Allocate memory, initialize locks and bookkeeping variables
1138 mDNSlocal
int InitLeaseTable(DaemonInfo
*d
)
1140 if (pthread_mutex_init(&d
->tablelock
, NULL
)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
1141 d
->nbuckets
= LEASETABLE_INIT_NBUCKETS
;
1143 d
->table
= malloc(sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1144 if (!d
->table
) { LogErr("InitLeaseTable", "malloc"); return -1; }
1145 mDNSPlatformMemZero(d
->table
, sizeof(RRTableElem
*) * LEASETABLE_INIT_NBUCKETS
);
1156 static const int kOn
= 1;
1158 mDNSBool
private = mDNSfalse
;
1159 struct sockaddr_in daddr
;
1163 // set up sockets on which we all ns requests
1165 self
->tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1166 require_action( dnssd_SocketValid(self
->tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1168 #if defined(SO_REUSEADDR)
1169 err
= setsockopt(self
->tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1170 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
1173 err
= bind( self
->tcpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1174 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tcpsd" ) );
1176 err
= listen( self
->tcpsd
, LISTENQ
);
1177 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1179 self
->udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1180 require_action( dnssd_SocketValid(self
->udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1182 #if defined(SO_REUSEADDR)
1183 err
= setsockopt(self
->udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1184 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
1187 err
= bind( self
->udpsd
, ( struct sockaddr
* ) &self
->addr
, sizeof( self
->addr
) );
1188 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->udpsd" ) );
1190 // set up sockets on which we receive llq requests
1192 mDNSPlatformMemZero(&self
->llq_addr
, sizeof(self
->llq_addr
));
1193 self
->llq_addr
.sin_family
= AF_INET
;
1194 self
->llq_addr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1195 self
->llq_addr
.sin_port
= ( self
->llq_port
.NotAnInteger
) ? self
->llq_port
.NotAnInteger
: DNSEXTPort
.NotAnInteger
;
1197 if (self
->llq_addr
.sin_port
== self
->addr
.sin_port
)
1199 self
->llq_tcpsd
= self
->tcpsd
;
1200 self
->llq_udpsd
= self
->udpsd
;
1204 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1205 require_action( dnssd_SocketValid(self
->llq_tcpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1207 #if defined(SO_REUSEADDR)
1208 err
= setsockopt(self
->llq_tcpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1209 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
1212 err
= bind( self
->llq_tcpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1213 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
1215 err
= listen( self
->llq_tcpsd
, LISTENQ
);
1216 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1218 self
->llq_udpsd
= socket( AF_INET
, SOCK_DGRAM
, 0 );
1219 require_action( dnssd_SocketValid(self
->llq_udpsd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1221 #if defined(SO_REUSEADDR)
1222 err
= setsockopt(self
->llq_udpsd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1223 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
1226 err
= bind(self
->llq_udpsd
, ( struct sockaddr
* ) &self
->llq_addr
, sizeof( self
->llq_addr
) );
1227 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
1230 // set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
1232 err
= socketpair( AF_LOCAL
, SOCK_STREAM
, 0, sockpair
);
1233 require_action( !err
, exit
, LogErr( "SetupSockets", "socketpair" ) );
1235 self
->LLQEventListenSock
= sockpair
[0];
1236 self
->LLQEventNotifySock
= sockpair
[1];
1238 // set up socket on which we receive private requests
1240 self
->llq_tcpsd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1241 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1242 mDNSPlatformMemZero(&daddr
, sizeof(daddr
));
1243 daddr
.sin_family
= AF_INET
;
1244 daddr
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
;
1245 daddr
.sin_port
= ( self
->private_port
.NotAnInteger
) ? self
->private_port
.NotAnInteger
: PrivateDNSPort
.NotAnInteger
;
1247 self
->tlssd
= socket( AF_INET
, SOCK_STREAM
, 0 );
1248 require_action( dnssd_SocketValid(self
->tlssd
), exit
, err
= mStatus_UnknownErr
; LogErr( "SetupSockets", "socket" ) );
1250 #if defined(SO_REUSEADDR)
1251 err
= setsockopt(self
->tlssd
, SOL_SOCKET
, SO_REUSEADDR
, &kOn
, sizeof(kOn
));
1252 require_action( !err
, exit
, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
1255 err
= bind( self
->tlssd
, ( struct sockaddr
* ) &daddr
, sizeof( daddr
) );
1256 require_action( !err
, exit
, LogErr( "SetupSockets", "bind self->tlssd" ) );
1258 err
= listen( self
->tlssd
, LISTENQ
);
1259 require_action( !err
, exit
, LogErr( "SetupSockets", "listen" ) );
1261 // Do we have any private zones?
1263 for ( zone
= self
->zones
; zone
; zone
= zone
->next
)
1265 if ( zone
->type
== kDNSZonePrivate
)
1274 err
= mDNSPlatformTLSSetupCerts();
1275 require_action( !err
, exit
, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
1284 // periodic table updates
1287 // Delete a resource record from the nameserver via a dynamic update
1288 // sd is a socket already connected to the server
1289 mDNSlocal
void DeleteOneRecord(DaemonInfo
*d
, CacheRecord
*rr
, domainname
*zname
, TCPSocket
*sock
)
1293 mDNSu8
*ptr
= pkt
.msg
.data
;
1294 mDNSu8
*end
= (mDNSu8
*)&pkt
.msg
+ sizeof(DNSMessage
);
1297 PktMsg
*reply
= NULL
;
1299 VLog("Expiring record %s", GetRRDisplayString_rdb(&rr
->resrec
, &rr
->resrec
.rdata
->u
, buf
));
1301 InitializeDNSMessage(&pkt
.msg
.h
, zeroID
, UpdateReqFlags
);
1303 ptr
= putZone(&pkt
.msg
, ptr
, end
, zname
, mDNSOpaque16fromIntVal(rr
->resrec
.rrclass
));
1305 ptr
= putDeletionRecord(&pkt
.msg
, ptr
, &rr
->resrec
);
1310 zone
= FindZone( d
, zname
);
1312 if ( zone
&& zone
->updateKeys
)
1314 DNSDigest_SignMessage(&pkt
.msg
, &ptr
, zone
->updateKeys
, 0 );
1318 pkt
.len
= ptr
- (mDNSu8
*)&pkt
.msg
;
1319 pkt
.src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // address field set solely for verbose logging in subroutines
1320 pkt
.src
.sin_family
= AF_INET
;
1321 if (SendPacket( sock
, &pkt
)) { Log("DeleteOneRecord: SendPacket failed"); }
1322 reply
= RecvPacket( sock
, NULL
, &closed
);
1323 if (reply
) HdrNToH(reply
);
1324 require_action( reply
, end
, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
1326 if (!SuccessfulUpdateTransaction(&pkt
, reply
))
1327 Log("Expiration update failed with rcode %d", reply
? reply
->msg
.h
.flags
.b
[1] & kDNSFlag1_RC_Mask
: -1);
1330 if (!ptr
) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
1331 if (reply
) free(reply
);
1334 // iterate over table, deleting expired records (or all records if DeleteAll is true)
1335 mDNSlocal
void DeleteRecords(DaemonInfo
*d
, mDNSBool DeleteAll
)
1339 TCPSocket
*sock
= ConnectToServer(d
);
1340 if (!sock
) { Log("DeleteRecords: ConnectToServer failed"); return; }
1341 if (gettimeofday(&now
, NULL
)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
1342 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
1344 for (i
= 0; i
< d
->nbuckets
; i
++)
1346 RRTableElem
**ptr
= &d
->table
[i
];
1349 if (DeleteAll
|| (*ptr
)->expire
- now
.tv_sec
< 0)
1352 // delete record from server
1353 DeleteOneRecord(d
, &(*ptr
)->rr
, &(*ptr
)->zone
, sock
);
1355 *ptr
= (*ptr
)->next
;
1359 else ptr
= &(*ptr
)->next
;
1362 pthread_mutex_unlock(&d
->tablelock
);
1363 mDNSPlatformTCPCloseConnection( sock
);
1367 // main update request handling
1370 // Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
1371 mDNSlocal
void UpdateLeaseTable(PktMsg
*pkt
, DaemonInfo
*d
, mDNSs32 lease
)
1374 LargeCacheRecord lcr
;
1375 ResourceRecord
*rr
= &lcr
.r
.resrec
;
1376 const mDNSu8
*ptr
, *end
;
1381 if (pthread_mutex_lock(&d
->tablelock
)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
1383 ptr
= pkt
->msg
.data
;
1384 end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
1385 ptr
= getQuestion(&pkt
->msg
, ptr
, end
, 0, &zone
);
1386 if (!ptr
) { Log("UpdateLeaseTable: cannot read zone"); goto cleanup
; }
1387 ptr
= LocateAuthorities(&pkt
->msg
, end
);
1388 if (!ptr
) { Log("UpdateLeaseTable: Format error"); goto cleanup
; }
1390 for (i
= 0; i
< pkt
->msg
.h
.mDNS_numUpdates
; i
++)
1392 mDNSBool DeleteAllRRSets
= mDNSfalse
, DeleteOneRRSet
= mDNSfalse
, DeleteOneRR
= mDNSfalse
;
1394 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAns
, &lcr
);
1395 if (!ptr
|| lcr
.r
.resrec
.RecordType
== kDNSRecordTypePacketNegative
) { Log("UpdateLeaseTable: GetLargeResourceRecord failed"); goto cleanup
; }
1396 int bucket
= rr
->namehash
% d
->nbuckets
;
1397 RRTableElem
*tmp
, **rptr
= &d
->table
[bucket
];
1400 if (rr
->rrtype
== kDNSQType_ANY
&& !rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1401 DeleteAllRRSets
= mDNStrue
; // delete all rrsets for a name
1402 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSQClass_ANY
&& !rr
->rdlength
)
1403 DeleteOneRRSet
= mDNStrue
;
1404 else if (!rr
->rroriginalttl
&& rr
->rrclass
== kDNSClass_NONE
)
1405 DeleteOneRR
= mDNStrue
;
1407 if (DeleteAllRRSets
|| DeleteOneRRSet
|| DeleteOneRR
)
1411 if (SameDomainName((*rptr
)->rr
.resrec
.name
, rr
->name
) &&
1413 (DeleteOneRRSet
&& (*rptr
)->rr
.resrec
.rrtype
== rr
->rrtype
) ||
1414 (DeleteOneRR
&& IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
))))
1417 VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp
->rr
.resrec
, &tmp
->rr
.resrec
.rdata
->u
, buf
));
1418 *rptr
= (*rptr
)->next
;
1422 else rptr
= &(*rptr
)->next
;
1427 // see if add or refresh
1428 while (*rptr
&& !IdenticalResourceRecord(&(*rptr
)->rr
.resrec
, rr
)) rptr
= &(*rptr
)->next
;
1432 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1433 (*rptr
)->expire
= tv
.tv_sec
+ (unsigned)lease
;
1434 VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1438 // New record - add to table
1439 if (d
->nelems
> d
->nbuckets
)
1442 bucket
= rr
->namehash
% d
->nbuckets
;
1444 if (gettimeofday(&tv
, NULL
)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup
; }
1445 allocsize
= sizeof(RRTableElem
);
1446 if (rr
->rdlength
> InlineCacheRDSize
) allocsize
+= (rr
->rdlength
- InlineCacheRDSize
);
1447 tmp
= malloc(allocsize
);
1448 if (!tmp
) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup
; }
1449 memcpy(&tmp
->rr
, &lcr
.r
, sizeof(CacheRecord
) + rr
->rdlength
- InlineCacheRDSize
);
1450 tmp
->rr
.resrec
.rdata
= (RData
*)&tmp
->rr
.smallrdatastorage
;
1451 AssignDomainName(&tmp
->name
, rr
->name
);
1452 tmp
->rr
.resrec
.name
= &tmp
->name
;
1453 tmp
->expire
= tv
.tv_sec
+ (unsigned)lease
;
1454 tmp
->cli
.sin_addr
= pkt
->src
.sin_addr
;
1455 AssignDomainName(&tmp
->zone
, &zone
.qname
);
1456 tmp
->next
= d
->table
[bucket
];
1457 d
->table
[bucket
] = tmp
;
1459 VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr
.r
.resrec
, &lcr
.r
.resrec
.rdata
->u
, buf
));
1465 pthread_mutex_unlock(&d
->tablelock
);
1469 // Given a successful reply from a server, create a new reply that contains lease information
1470 // Replies are currently not signed !!!KRS change this
1471 mDNSlocal PktMsg
*FormatLeaseReply(DaemonInfo
*d
, PktMsg
*orig
, mDNSu32 lease
)
1473 PktMsg
*const reply
= malloc(sizeof(*reply
));
1478 if (!reply
) { LogErr("FormatLeaseReply", "malloc"); return NULL
; }
1479 flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_OP_Update
;
1482 InitializeDNSMessage(&reply
->msg
.h
, orig
->msg
.h
.id
, flags
);
1483 reply
->src
.sin_addr
.s_addr
= zerov4Addr
.NotAnInteger
; // unused except for log messages
1484 reply
->src
.sin_family
= AF_INET
;
1485 ptr
= putUpdateLease(&reply
->msg
, reply
->msg
.data
, lease
);
1486 if (!ptr
) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply
); return NULL
; }
1487 reply
->len
= ptr
- (mDNSu8
*)&reply
->msg
;
1493 // pkt is thread-local, not requiring locking
1502 PktMsg
* reply
= NULL
;
1503 PktMsg
* leaseReply
;
1506 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 gotlease
= GetPktLease(&mDNSStorage
, &request
->msg
, end
, &lease
);
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
++;
1524 if (adds
&& !gotlease
)
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
;
2321 const mDNSu8
*qptr
= pkt
->msg
.data
;
2322 const mDNSu8
*end
= (mDNSu8
*)&pkt
->msg
+ pkt
->len
;
2324 LLQOptData
*llq
= NULL
;
2328 aptr
= LocateAdditionals(&pkt
->msg
, end
); // Can't do this until after HdrNToH(pkt);
2329 inet_ntop(AF_INET
, &pkt
->src
.sin_addr
, addr
, 32);
2331 VLog("Received LLQ msg from %s", addr
);
2332 // sanity-check packet
2333 if (!pkt
->msg
.h
.numQuestions
|| !pkt
->msg
.h
.numAdditionals
)
2335 Log("Malformatted LLQ from %s with %d questions, %d additionals", addr
, pkt
->msg
.h
.numQuestions
, pkt
->msg
.h
.numAdditionals
);
2339 // Locate the OPT record.
2340 // According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
2341 // This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
2342 // but not necessarily the *last* entry in the Additional Section.
2343 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2345 aptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, aptr
, end
, 0, kDNSRecordTypePacketAdd
, &opt
);
2346 if (!aptr
) { Log("Malformatted LLQ from %s: could not get Additional record %u", addr
, i
); goto end
; }
2347 if (opt
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& opt
.r
.resrec
.rrtype
== kDNSType_OPT
) break;
2351 if (opt
.r
.resrec
.rrtype
!= kDNSType_OPT
) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr
); goto end
; }
2352 if (opt
.r
.resrec
.rdlength
< pkt
->msg
.h
.numQuestions
* DNSOpt_LLQData_Space
) { Log("Malformatted LLQ from %s: OPT RR to small (%d bytes for %d questions)", addr
, opt
.r
.resrec
.rdlength
, pkt
->msg
.h
.numQuestions
); }
2354 // dispatch each question
2355 for (i
= 0; i
< pkt
->msg
.h
.numQuestions
; i
++)
2357 qptr
= getQuestion(&pkt
->msg
, qptr
, end
, 0, &q
);
2358 if (!qptr
) { Log("Malformatted LLQ from %s: cannot read question %u", addr
, i
); goto end
; }
2359 llq
= &opt
.r
.resrec
.rdata
->u
.opt
[i
].u
.llq
; // point into OptData at index i
2360 if (llq
->vers
!= kLLQ_Vers
) { Log("LLQ from %s contains bad version %d (expected %d)", addr
, llq
->vers
, kLLQ_Vers
); goto end
; }
2362 e
= LookupLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, &llq
->id
);
2365 // no entry - if zero ID, create new
2366 e
= NewLLQ(d
, pkt
->src
, &q
.qname
, q
.qtype
, llq
->llqlease
);
2369 UpdateLLQ(d
, e
, llq
, pkt
->msg
.h
.id
, sock
);
2379 mDNSlocal mDNSBool
IsAuthorized( DaemonInfo
* d
, PktMsg
* pkt
, DomainAuthInfo
** key
, mDNSu16
* rcode
, mDNSu16
* tcode
)
2381 const mDNSu8
* lastPtr
= NULL
;
2382 const mDNSu8
* ptr
= NULL
;
2383 DomainAuthInfo
* keys
;
2384 mDNSu8
* end
= ( mDNSu8
* ) &pkt
->msg
+ pkt
->len
;
2385 LargeCacheRecord lcr
;
2386 mDNSBool hasTSIG
= mDNSfalse
;
2387 mDNSBool strip
= mDNSfalse
;
2388 mDNSBool ok
= mDNSfalse
;
2391 // Unused parameters
2398 bzero(&lcr
, sizeof(lcr
));
2400 if ( pkt
->msg
.h
.numAdditionals
)
2402 ptr
= LocateAdditionals(&pkt
->msg
, end
);
2405 for (i
= 0; i
< pkt
->msg
.h
.numAdditionals
; i
++)
2408 ptr
= GetLargeResourceRecord(NULL
, &pkt
->msg
, ptr
, end
, 0, kDNSRecordTypePacketAdd
, &lcr
);
2411 Log("Unable to read additional record");
2417 hasTSIG
= ( ptr
&& lcr
.r
.resrec
.RecordType
!= kDNSRecordTypePacketNegative
&& lcr
.r
.resrec
.rrtype
== kDNSType_TSIG
);
2421 LogMsg( "IsAuthorized: unable to find Additional section" );
2425 // If we don't know what zone this is, then it's authorized.
2434 if ( IsQuery( pkt
) )
2436 keys
= pkt
->zone
->queryKeys
;
2439 else if ( IsUpdate( pkt
) )
2441 keys
= pkt
->zone
->updateKeys
;
2451 if ( pkt
->isZonePublic
)
2457 // If there are no keys, then we're authorized
2459 if ( ( hasTSIG
&& !keys
) || ( !hasTSIG
&& keys
) )
2461 Log( "Invalid TSIG spec %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2462 *rcode
= kDNSFlag1_RC_NotAuth
;
2463 *tcode
= TSIG_ErrBadKey
;
2469 // Find the right key
2471 for ( *key
= keys
; *key
; *key
= (*key
)->next
)
2473 if ( SameDomainName( lcr
.r
.resrec
.name
, &(*key
)->keyname
) )
2481 Log( "Invalid TSIG name %##s for zone %##s", lcr
.r
.resrec
.name
->c
, pkt
->zone
->name
.c
);
2482 *rcode
= kDNSFlag1_RC_NotAuth
;
2483 *tcode
= TSIG_ErrBadKey
;
2489 // Okay, we have the correct key and a TSIG record. DNSDigest_VerifyMessage does the heavy
2490 // lifting of message verification
2492 pkt
->msg
.h
.numAdditionals
--;
2496 ok
= DNSDigest_VerifyMessage( &pkt
->msg
, ( mDNSu8
* ) lastPtr
, &lcr
, (*key
), rcode
, tcode
);
2500 pkt
->msg
.h
.numAdditionals
++;
2504 if ( hasTSIG
&& strip
)
2506 // Strip the TSIG from the message
2508 pkt
->msg
.h
.numAdditionals
--;
2509 pkt
->len
= lastPtr
- ( mDNSu8
* ) ( &pkt
->msg
);
2517 // request handler wrappers for TCP and UDP requests
2518 // (read message off socket, fork thread that invokes main processing routine and handles cleanup)
2526 UDPContext
* context
= ( UDPContext
* ) vptr
;
2527 PktMsg
* reply
= NULL
;
2531 // !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
2532 // may give us a long answer that would require truncation for UDP delivery to client
2534 reply
= HandleRequest( context
->d
, &context
->pkt
);
2535 require_action( reply
, exit
, err
= mStatus_UnknownErr
);
2537 res
= sendto( context
->sd
, &reply
->msg
, reply
->len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2538 require_action_quiet( res
== ( int ) reply
->len
, exit
, LogErr( "UDPMessageHandler", "sendto" ) );
2549 pthread_exit( NULL
);
2562 UDPContext
* context
= NULL
;
2566 DomainAuthInfo
* key
;
2567 unsigned int clisize
= sizeof( context
->cliaddr
);
2569 mStatus err
= mStatus_NoError
;
2571 context
= malloc( sizeof( UDPContext
) );
2572 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "RecvUDPMessage", "malloc" ) );
2574 mDNSPlatformMemZero( context
, sizeof( *context
) );
2578 res
= recvfrom(sd
, &context
->pkt
.msg
, sizeof(context
->pkt
.msg
), 0, (struct sockaddr
*)&context
->cliaddr
, &clisize
);
2580 require_action( res
>= 0, exit
, err
= mStatus_UnknownErr
; LogErr( "RecvUDPMessage", "recvfrom" ) );
2581 context
->pkt
.len
= res
;
2582 require_action( clisize
== sizeof( context
->cliaddr
), exit
, err
= mStatus_UnknownErr
; Log( "Client address of unknown size %d", clisize
) );
2583 context
->pkt
.src
= context
->cliaddr
;
2585 // Set the zone in the packet
2587 SetZone( context
->d
, &context
->pkt
);
2589 // Notify messages handled by main thread
2591 if ( IsNotify( &context
->pkt
) )
2593 int e
= RecvNotify( self
, &context
->pkt
);
2597 else if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2599 if ( IsLLQRequest( &context
->pkt
) )
2601 // LLQ messages handled by main thread
2602 int e
= RecvLLQ( self
, &context
->pkt
, NULL
);
2607 if ( IsLLQAck(&context
->pkt
) )
2609 // !!!KRS need to do acks + retrans
2615 err
= pthread_create( &tid
, NULL
, UDPMessageHandler
, context
);
2616 require_action( !err
, exit
, LogErr( "RecvUDPMessage", "pthread_create" ) );
2618 pthread_detach(tid
);
2625 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2627 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2628 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_NXDomain
;
2630 e
= sendto( sd
, &reply
.msg
, reply
.len
, 0, ( struct sockaddr
* ) &context
->pkt
.src
, sizeof( context
->pkt
.src
) );
2631 require_action_quiet( e
== ( int ) reply
.len
, exit
, LogErr( "RecvUDPMessage", "sendto" ) );
2633 err
= mStatus_NoAuth
;
2638 if ( err
&& context
)
2650 TCPContext
* context
2655 if ( context
->sock
)
2657 mDNSPlatformTCPCloseConnection( context
->sock
);
2671 TCPContext
* context
= ( TCPContext
* ) vptr
;
2672 PktMsg
* reply
= NULL
;
2676 //!!!KRS if this read blocks indefinitely, we can run out of threads
2679 reply
= HandleRequest( context
->d
, &context
->pkt
);
2680 require_action_quiet( reply
, exit
, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2682 // deliver reply to client
2684 res
= SendPacket( context
->sock
, reply
);
2685 require_action( res
>= 0, exit
, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET
, &context
->cliaddr
.sin_addr
, buf
, 32 ) ) );
2689 FreeTCPContext( context
);
2706 TCPContext
* context
= ( TCPContext
* ) param
;
2710 DomainAuthInfo
* key
;
2713 mDNSBool freeContext
= mDNStrue
;
2714 mStatus err
= mStatus_NoError
;
2716 // Receive a packet. It's okay if we don't actually read a packet, as long as the closed flag is
2717 // set to false. This is because SSL/TLS layer might gobble up the first packet that we read off the
2718 // wire. We'll let it do that, and wait for the next packet which will be ours.
2720 pkt
= RecvPacket( context
->sock
, &context
->pkt
, &closed
);
2721 if (pkt
) HdrNToH(pkt
);
2722 require_action( pkt
|| !closed
, exit
, err
= mStatus_UnknownErr
; LogMsg( "client disconnected" ) );
2726 // Always do this, regardless of what kind of packet it is. If we wanted LLQ events to be sent over TCP,
2727 // we would change this line of code. As it is now, we will reply to an LLQ via TCP, but then events
2728 // are sent over UDP
2730 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2732 // Set's the DNS Zone that is associated with this message
2734 SetZone( context
->d
, &context
->pkt
);
2736 // IsAuthorized will make sure the message is authorized for the designated zone.
2737 // After verifying the signature, it will strip the TSIG from the message
2739 if ( IsAuthorized( context
->d
, &context
->pkt
, &key
, &rcode
, &tcode
) )
2741 if ( IsLLQRequest( &context
->pkt
) )
2743 // LLQ messages handled by main thread
2744 RecvLLQ( context
->d
, &context
->pkt
, context
->sock
);
2748 err
= pthread_create( &tid
, NULL
, TCPMessageHandler
, context
);
2752 LogErr( "RecvTCPMessage", "pthread_create" );
2753 err
= mStatus_NoError
;
2757 // Let the thread free the context
2759 freeContext
= mDNSfalse
;
2761 pthread_detach(tid
);
2768 LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context
->pkt
.src
.sin_addr
), pkt
->zone
->name
.c
);
2770 memcpy( &reply
, &context
->pkt
, sizeof( PktMsg
) );
2772 reply
.msg
.h
.flags
.b
[0] = kDNSFlag0_QR_Response
| kDNSFlag0_AA
| kDNSFlag0_RD
;
2773 reply
.msg
.h
.flags
.b
[1] = kDNSFlag1_RA
| kDNSFlag1_RC_Refused
;
2775 SendPacket( context
->sock
, &reply
);
2780 freeContext
= mDNSfalse
;
2787 RemoveSourceFromEventLoop( context
->d
, context
->sock
);
2792 FreeTCPContext( context
);
2802 TCPSocketFlags flags
2805 TCPContext
* context
= NULL
;
2806 unsigned int clilen
= sizeof( context
->cliaddr
);
2808 mStatus err
= mStatus_NoError
;
2810 context
= ( TCPContext
* ) malloc( sizeof( TCPContext
) );
2811 require_action( context
, exit
, err
= mStatus_NoMemoryErr
; LogErr( "AcceptTCPConnection", "malloc" ) );
2812 mDNSPlatformMemZero( context
, sizeof( sizeof( TCPContext
) ) );
2814 newSock
= accept( sd
, ( struct sockaddr
* ) &context
->cliaddr
, &clilen
);
2815 require_action( newSock
!= -1, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "accept" ) );
2817 context
->sock
= mDNSPlatformTCPAccept( flags
, newSock
);
2818 require_action( context
->sock
, exit
, err
= mStatus_UnknownErr
; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
2820 err
= AddSourceToEventLoop( self
, context
->sock
, RecvTCPMessage
, context
);
2821 require_action( !err
, exit
, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
2825 if ( err
&& context
)
2836 // listen for incoming requests, periodically check table for expired records, respond to signals
2837 mDNSlocal
int Run(DaemonInfo
*d
)
2839 int staticMaxFD
, nfds
;
2841 struct timeval timenow
, timeout
, EventTS
, tablecheck
= { 0, 0 };
2842 mDNSBool EventsPending
= mDNSfalse
;
2844 VLog("Listening for requests...");
2848 if ( d
->tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tcpsd
+ 1;
2849 if ( d
->udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->udpsd
+ 1;
2850 if ( d
->tlssd
+ 1 > staticMaxFD
) staticMaxFD
= d
->tlssd
+ 1;
2851 if ( d
->llq_tcpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_tcpsd
+ 1;
2852 if ( d
->llq_udpsd
+ 1 > staticMaxFD
) staticMaxFD
= d
->llq_udpsd
+ 1;
2853 if ( d
->LLQEventListenSock
+ 1 > staticMaxFD
) staticMaxFD
= d
->LLQEventListenSock
+ 1;
2857 EventSource
* source
;
2861 timeout
.tv_sec
= timeout
.tv_usec
= 0;
2862 if (gettimeofday(&timenow
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2866 if (timenow
.tv_sec
- EventTS
.tv_sec
>= 5) // if we've been waiting 5 seconds for a "quiet" period to send
2867 { GenLLQEvents(d
); EventsPending
= mDNSfalse
; } // events, we go ahead and do it now
2868 else timeout
.tv_usec
= 500000; // else do events after 1/2 second with no new events or LLQs
2872 // if no pending events, timeout when we need to check for expired records
2873 if (tablecheck
.tv_sec
&& timenow
.tv_sec
- tablecheck
.tv_sec
>= 0)
2874 { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; } // table check overdue
2875 if (!tablecheck
.tv_sec
) tablecheck
.tv_sec
= timenow
.tv_sec
+ EXPIRATION_INTERVAL
;
2876 timeout
.tv_sec
= tablecheck
.tv_sec
- timenow
.tv_sec
;
2880 FD_SET( d
->tcpsd
, &rset
);
2881 FD_SET( d
->udpsd
, &rset
);
2882 FD_SET( d
->tlssd
, &rset
);
2883 FD_SET( d
->llq_tcpsd
, &rset
);
2884 FD_SET( d
->llq_udpsd
, &rset
);
2885 FD_SET( d
->LLQEventListenSock
, &rset
);
2887 maxFD
= staticMaxFD
;
2889 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2891 FD_SET( source
->fd
, &rset
);
2893 if ( source
->fd
> maxFD
)
2899 nfds
= select( maxFD
+ 1, &rset
, NULL
, NULL
, &timeout
);
2906 // close sockets to prevent clients from making new requests during shutdown
2910 close( d
->llq_tcpsd
);
2911 close( d
->llq_udpsd
);
2912 d
->tcpsd
= d
->udpsd
= d
->tlssd
= d
->llq_tcpsd
= d
->llq_udpsd
= -1;
2913 DeleteRecords(d
, mDNStrue
);
2918 Log( "Received SIGINFO" );
2929 Log( "Received SIGHUP" );
2931 err
= ParseConfig( d
, cfgfile
);
2935 LogErr( "Run", "ParseConfig" );
2943 Log("Received unhandled signal - continuing");
2948 LogErr("Run", "select"); return -1;
2953 if (FD_ISSET(d
->udpsd
, &rset
)) RecvUDPMessage( d
, d
->udpsd
);
2954 if (FD_ISSET(d
->llq_udpsd
, &rset
)) RecvUDPMessage( d
, d
->llq_udpsd
);
2955 if (FD_ISSET(d
->tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->tcpsd
, 0 );
2956 if (FD_ISSET(d
->llq_tcpsd
, &rset
)) AcceptTCPConnection( d
, d
->llq_tcpsd
, 0 );
2957 if (FD_ISSET(d
->tlssd
, &rset
)) AcceptTCPConnection( d
, d
->tlssd
, TCP_SOCKET_FLAGS
);
2958 if (FD_ISSET(d
->LLQEventListenSock
, &rset
))
2960 // clear signalling data off socket
2962 recv(d
->LLQEventListenSock
, buf
, 256, 0);
2965 EventsPending
= mDNStrue
;
2966 if (gettimeofday(&EventTS
, NULL
)) { LogErr("Run", "gettimeofday"); return -1; }
2970 for ( source
= ( EventSource
* ) d
->eventSources
.Head
; source
; source
= source
->next
)
2972 if ( FD_ISSET( source
->fd
, &rset
) )
2974 source
->callback( source
->context
);
2975 break; // in case we removed this guy from the event loop
2982 if (EventsPending
) { GenLLQEvents(d
); EventsPending
= mDNSfalse
; }
2983 else { DeleteRecords(d
, mDNSfalse
); tablecheck
.tv_sec
= 0; }
2989 // signal handler sets global variables, which are inspected by main event loop
2990 // (select automatically returns due to the handled signal)
2991 mDNSlocal
void HndlSignal(int sig
)
2993 if (sig
== SIGTERM
|| sig
== SIGINT
) { terminate
= 1; return; }
2994 if (sig
== INFO_SIGNAL
) { dumptable
= 1; return; }
2995 if (sig
== SIGHUP
) { hangup
= 1; return; }
3005 DNameListElem
* elem
;
3006 mStatus err
= mStatus_NoError
;
3008 elem
= ( DNameListElem
* ) malloc( sizeof( DNameListElem
) );
3009 require_action( elem
, exit
, err
= mStatus_NoMemoryErr
);
3010 MakeDomainNameFromDNSNameString( &elem
->name
, name
);
3011 elem
->next
= d
->public_names
;
3012 d
->public_names
= elem
;
3020 int main(int argc
, char *argv
[])
3022 int started_via_launchd
= 0;
3026 Log("dnsextd starting");
3028 d
= malloc(sizeof(*d
));
3029 if (!d
) { LogErr("main", "malloc"); exit(1); }
3030 mDNSPlatformMemZero(d
, sizeof(DaemonInfo
));
3032 // Setup the public SRV record names
3034 SetPublicSRV(d
, "_dns-update._udp.");
3035 SetPublicSRV(d
, "_dns-llq._udp.");
3036 SetPublicSRV(d
, "_dns-update-tls._tcp.");
3037 SetPublicSRV(d
, "_dns-query-tls._tcp.");
3038 SetPublicSRV(d
, "_dns-llq-tls._tcp.");
3040 // Setup signal handling
3042 if (signal(SIGHUP
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGHUP");
3043 if (signal(SIGTERM
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGTERM");
3044 if (signal(INFO_SIGNAL
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINFO");
3045 if (signal(SIGINT
, HndlSignal
) == SIG_ERR
) perror("Can't catch SIGINT");
3046 if (signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) perror("Can't ignore SIGPIPE");
3048 // remove open file limit
3049 rlim
.rlim_max
= RLIM_INFINITY
;
3050 rlim
.rlim_cur
= RLIM_INFINITY
;
3051 if (setrlimit(RLIMIT_NOFILE
, &rlim
) < 0)
3053 LogErr("main", "setrlimit");
3054 Log("Using default file descriptor resource limit");
3057 if (argc
> 1 && !strcasecmp(argv
[1], "-launchd"))
3059 Log("started_via_launchd");
3060 started_via_launchd
= 1;
3064 if (ProcessArgs(argc
, argv
, d
) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
3066 if (!foreground
&& !started_via_launchd
)
3070 LogErr("main", "daemon");
3075 if (InitLeaseTable(d
) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
3076 if (SetupSockets(d
) < 0) { LogErr("main", "SetupSockets"); exit(1); }
3077 if (SetUpdateSRV(d
) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
3081 Log("dnsextd stopping");
3083 if (ClearUpdateSRV(d
) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); } // clear update srv's even if Run or pthread_create returns an error
3089 // These are stubbed out implementations of up-call routines that the various platform support layers
3090 // call. These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
3091 // link this code in.
3093 // It's an error for these routines to actually be called, so perhaps we should log any call
3095 void mDNSCoreInitComplete( mDNS
* const m
, mStatus result
) { ( void ) m
; ( void ) result
; }
3096 void mDNS_ConfigChanged(mDNS
*const m
) { ( void ) m
; }
3097 void mDNSCoreMachineSleep(mDNS
* const m
, mDNSBool wake
) { ( void ) m
; ( void ) wake
; }
3098 void mDNSCoreReceive(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
3099 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
,
3100 const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
, const mDNSInterfaceID iid
)
3101 { ( void ) m
; ( void ) msg
; ( void ) end
; ( void ) srcaddr
; ( void ) srcport
; ( void ) dstaddr
; ( void ) dstport
; ( void ) iid
; }
3102 DNSServer
*mDNS_AddDNSServer(mDNS
*const m
, const domainname
*d
, const mDNSInterfaceID interface
, const int serviceID
, const mDNSAddr
*addr
, const mDNSIPPort port
,
3103 mDNSu32 scopedType
, mDNSu32 timeout
, mDNSBool isCell
, mDNSBool isExpensive
, mDNSBool isConstrained
, mDNSBool isCLAT46
, mDNSu32 resGroupID
, mDNSBool reqA
, mDNSBool reqAAAA
, mDNSBool reqDO
)
3104 { ( void ) m
; ( void ) d
; ( void ) interface
; ( void ) serviceID
; ( void ) addr
; ( void ) port
; ( void ) scopedType
; ( void ) timeout
; (void) isCell
; (void) isExpensive
; (void) isConstrained
; (void) isCLAT46
;
3105 (void) resGroupID
; (void) reqA
; (void) reqAAAA
; (void) reqDO
; return(NULL
); }
3106 void mDNS_AddSearchDomain(const domainname
*const domain
, mDNSInterfaceID InterfaceID
) { (void)domain
; (void) InterfaceID
;}
3107 void mDNS_AddDynDNSHostName(mDNS
*m
, const domainname
*fqdn
, mDNSRecordCallback
*StatusCallback
, const void *StatusContext
)
3108 { ( void ) m
; ( void ) fqdn
; ( void ) StatusCallback
; ( void ) StatusContext
; }
3109 mDNSs32
mDNS_Execute (mDNS
*const m
) { ( void ) m
; return 0; }
3110 mDNSs32
mDNS_TimeNow(const mDNS
*const m
) { ( void ) m
; return 0; }
3111 mStatus
mDNS_Deregister(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3112 void mDNS_DeregisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, InterfaceActivationSpeed activationSpeed
)
3113 { ( void ) m
; ( void ) set
; ( void ) activationSpeed
; }
3114 const char * const mDNS_DomainTypeNames
[1] = {};
3115 mStatus
mDNS_GetDomains(mDNS
*const m
, DNSQuestion
*const question
, mDNS_DomainType DomainType
, const domainname
*dom
,
3116 const mDNSInterfaceID InterfaceID
, mDNSQuestionCallback
*Callback
, void *Context
)
3117 { ( void ) m
; ( void ) question
; ( void ) DomainType
; ( void ) dom
; ( void ) InterfaceID
; ( void ) Callback
; ( void ) Context
; return 0; }
3118 mStatus
mDNS_Register(mDNS
*const m
, AuthRecord
*const rr
) { ( void ) m
; ( void ) rr
; return 0; }
3119 mStatus
mDNS_RegisterInterface(mDNS
*const m
, NetworkInterfaceInfo
*set
, InterfaceActivationSpeed activationSpeed
)
3120 { ( void ) m
; ( void ) set
; ( void ) activationSpeed
; return 0; }
3121 void mDNS_RemoveDynDNSHostName(mDNS
*m
, const domainname
*fqdn
) { ( void ) m
; ( void ) fqdn
; }
3122 void mDNS_SetFQDN(mDNS
* const m
) { ( void ) m
; }
3123 void mDNS_SetPrimaryInterfaceInfo(mDNS
*m
, const mDNSAddr
*v4addr
, const mDNSAddr
*v6addr
, const mDNSAddr
*router
)
3124 { ( void ) m
; ( void ) v4addr
; ( void ) v6addr
; ( void ) router
; }
3125 mStatus
uDNS_SetupDNSConfig( mDNS
*const m
) { ( void ) m
; return 0; }
3126 mStatus
mDNS_SetSecretForDomain(mDNS
*m
, DomainAuthInfo
*info
,
3127 const domainname
*domain
, const domainname
*keyname
, const char *b64keydata
, const domainname
*hostname
, mDNSIPPort
*port
)
3128 { ( void ) m
; ( void ) info
; ( void ) domain
; ( void ) keyname
; ( void ) b64keydata
; ( void ) hostname
; (void) port
; return 0; }
3129 mStatus
mDNS_StopQuery(mDNS
*const m
, DNSQuestion
*const question
) { ( void ) m
; ( void ) question
; return 0; }
3130 void TriggerEventCompletion(void);
3131 void TriggerEventCompletion() {}
3135 // For convenience when using the "strings" command, this is the last thing in the file
3136 // The "@(#) " pattern is a special prefix the "what" command looks for
3137 const char mDNSResponderVersionString_SCCS
[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion
) " (" __DATE__
" " __TIME__
")";
3139 #if _BUILDING_XCODE_PROJECT_
3140 // If the process crashes, then this string will be magically included in the automatically-generated crash log
3141 const char *__crashreporter_info__
= mDNSResponderVersionString_SCCS
+ 5;
3142 asm (".desc ___crashreporter_info__, 0x10");