147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* -*- Mode: C; tab-width: 4 -*-
247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License");
647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * you may not use this file except in compliance with the License.
747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * You may obtain a copy of the License at
847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *     http://www.apache.org/licenses/LICENSE-2.0
1047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
1147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Unless required by applicable law or agreed to in writing, software
1247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS,
1347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * See the License for the specific language governing permissions and
1547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * limitations under the License.
1647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt */
1747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
1847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if __APPLE__
1947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In Mac OS X 10.5 and later trying to use the daemon function gives a “‘daemon’ is deprecated”
2047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// error, which prevents compilation because we build with "-Werror".
2147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Since this is supposed to be portable cross-platform code, we don't care that daemon is
2247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// deprecated on Mac OS X 10.5, so we use this preprocessor trick to eliminate the error message.
2347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define daemon yes_we_know_that_daemon_is_deprecated_in_os_x_10_5_thankyou
2447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
2547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
2647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <signal.h>
2747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <pthread.h>
2847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdlib.h>
2947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <unistd.h>
3047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <sys/types.h>
3147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <sys/socket.h>
3247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <netinet/in.h>
3347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <arpa/inet.h>
3447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdio.h>
3547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <syslog.h>
3647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <string.h>
3747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <sys/time.h>
3847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <sys/resource.h>
3947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <time.h>
4047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <errno.h>
4147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if __APPLE__
4347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#undef daemon
4447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltextern int daemon(int, int);
4547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
4647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Solaris doesn't have daemon(), so we define it here
4847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifdef NOT_HAVE_DAEMON
4947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "../mDNSPosix/mDNSUNP.h"		// For daemon()
5047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // NOT_HAVE_DAEMON
5147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "dnsextd.h"
5347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "../mDNSShared/uds_daemon.h"
5447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "../mDNSShared/dnssd_ipc.h"
5547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "../mDNSCore/uDNS.h"
5647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "../mDNSShared/DebugServices.h"
5747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Compatibility workaround
5947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef AF_LOCAL
6047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define AF_LOCAL AF_UNIX
6147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
6247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
6347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
6447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Constants
6547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
6647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const char ProgramName[] = "dnsextd";
6747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
6847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LOOPBACK					"127.0.0.1"
6947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if !defined(LISTENQ)
7047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	define LISTENQ					128					// tcp connection backlog
7147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
7247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define RECV_BUFLEN					9000
7347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LEASETABLE_INIT_NBUCKETS	256					// initial hashtable size (doubles as table fills)
7447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define EXPIRATION_INTERVAL			300					// check for expired records every 5 minutes
7547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define SRV_TTL						7200				// TTL For _dns-update SRV records
7647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define CONFIG_FILE					"/etc/dnsextd.conf"
7747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define TCP_SOCKET_FLAGS   			kTCPSocketFlags_UseTLS
7847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// LLQ Lease bounds (seconds)
8047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LLQ_MIN_LEASE (15 * 60)
8147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LLQ_MAX_LEASE (120 * 60)
8247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LLQ_LEASE_FUDGE 60
8347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
8447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// LLQ SOA poll interval (microseconds)
8547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LLQ_MONITOR_ERR_INTERVAL (60 * 1000000)
8647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define LLQ_MONITOR_INTERVAL 250000
8747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifdef SIGINFO
8847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define INFO_SIGNAL SIGINFO
8947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#else
9047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define INFO_SIGNAL SIGUSR1
9147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
9247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define SAME_INADDR(x,y) (*((mDNSu32 *)&x) == *((mDNSu32 *)&y))
9447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
9647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Data Structures
9747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Structs/fields that must be locked for thread safety are explicitly commented
9847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
9947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
10047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// args passed to UDP request handler thread as void*
10147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
10247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct
10347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
10447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    PktMsg pkt;
10547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    struct sockaddr_in cliaddr;
10647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    DaemonInfo *d;
10747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int sd;
10847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} UDPContext;
10947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// args passed to TCP request handler thread as void*
11147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct
11247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
11347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg	pkt;
11447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    struct sockaddr_in cliaddr;
11547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    TCPSocket *sock;           // socket connected to client
11647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    DaemonInfo *d;
11747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} TCPContext;
11847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// args passed to UpdateAnswerList thread as void*
12047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct
12147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
12247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    DaemonInfo *d;
12347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    AnswerListElem *a;
12447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} UpdateAnswerListArgs;
12547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
12747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Global Variables
12847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
12947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
13047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// booleans to determine runtime output
13147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// read-only after initialization (no mutex protection)
13247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool foreground = 0;
13347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool verbose = 0;
13447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
13547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// globals set via signal handler (accessed exclusively by main select loop and signal handler)
13647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool terminate = 0;
13747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool dumptable = 0;
13847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNSBool hangup    = 0;
13947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
14047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// global for config file location
14147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic char *   cfgfile   = NULL;
14247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
14347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
14447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Logging Routines
14547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Log messages are delivered to syslog unless -f option specified
14647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
14747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
14847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// common message logging subroutine
14947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void PrintLog(const char *buffer)
15047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
15147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (foreground)
15247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
15347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fprintf(stderr,"%s\n", buffer);
15447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fflush(stderr);
15547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
15647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
15747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
15847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		openlog("dnsextd", LOG_CONS, LOG_DAEMON);
15947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		syslog(LOG_ERR, "%s", buffer);
16047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		closelog();
16147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
16247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
16347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
16447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Verbose Logging (conditional on -v option)
16547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void VLog(const char *format, ...)
16647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
16747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt   	char buffer[512];
16847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_list ptr;
16947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
17047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!verbose) return;
17147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_start(ptr,format);
17247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
17347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_end(ptr);
17447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 	PrintLog(buffer);
17547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
17647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
17747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Unconditional Logging
17847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void Log(const char *format, ...)
17947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
18047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt   	char buffer[512];
18147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_list ptr;
18247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_start(ptr,format);
18447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
18547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_end(ptr);
18647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 	PrintLog(buffer);
18747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
18847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Error Logging
19047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// prints message "dnsextd <function>: <operation> - <error message>"
19147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// must be compiled w/ -D_REENTRANT for thread-safe errno usage
19247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void LogErr(const char *fn, const char *operation)
19347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
19447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buf[512], errbuf[256];
19547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	strerror_r(errno, errbuf, sizeof(errbuf));
19647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	snprintf(buf, sizeof(buf), "%s: %s - %s", fn, operation, errbuf);
19747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PrintLog(buf);
19847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
19947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
20147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Networking Utility Routines
20247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
20347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Convert DNS Message Header from Network to Host byte order
20547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void HdrNToH(PktMsg *pkt)
20647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
20747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
20847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
20947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->msg.h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
21047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->msg.h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
21147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->msg.h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
21247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->msg.h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
21347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
21447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
21547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Convert DNS Message Header from Host to Network byte order
21647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void HdrHToN(PktMsg *pkt)
21747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
21847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 numQuestions   = pkt->msg.h.numQuestions;
21947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 numAnswers     = pkt->msg.h.numAnswers;
22047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 numAuthorities = pkt->msg.h.numAuthorities;
22147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 numAdditionals = pkt->msg.h.numAdditionals;
22247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *ptr = (mDNSu8 *)&pkt->msg.h.numQuestions;
22347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
22447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Put all the integer values in IETF byte-order (MSB first, LSB second)
22547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numQuestions   >> 8);
22647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numQuestions   &  0xFF);
22747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numAnswers     >> 8);
22847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numAnswers     &  0xFF);
22947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numAuthorities >> 8);
23047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numAuthorities &  0xFF);
23147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numAdditionals >> 8);
23247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(numAdditionals &  0xFF);
23347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
23447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
23547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
23647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Add socket to event loop
23747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
23847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus AddSourceToEventLoop( DaemonInfo * self, TCPSocket *sock, EventCallback callback, void *context )
23947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
24047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	EventSource	* newSource;
24147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err = mStatus_NoError;
24247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
24347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( self->eventSources.LinkOffset == 0 )
24447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
24547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		InitLinkedList( &self->eventSources, offsetof( EventSource, next));
24647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
24747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
24847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	newSource = ( EventSource*) malloc( sizeof *newSource );
24947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( newSource == NULL )
25047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
25147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = mStatus_NoMemoryErr;
25247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		goto exit;
25347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
25447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
25547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	newSource->callback = callback;
25647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	newSource->context = context;
25747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	newSource->sock = sock;
25847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	newSource->fd = mDNSPlatformTCPGetFD( sock );
25947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AddToTail( &self->eventSources, newSource );
26147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
26347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
26547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
26647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Remove socket from event loop
26947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
27047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus RemoveSourceFromEventLoop( DaemonInfo * self, TCPSocket *sock )
27147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
27247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	EventSource	*	source;
27347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err;
27447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
27547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for ( source = ( EventSource* ) self->eventSources.Head; source; source = source->next )
27647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
27747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( source->sock == sock )
27847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
27947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			RemoveFromList( &self->eventSources, source );
28047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
28147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			free( source );
28247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			err = mStatus_NoError;
28347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			goto exit;
28447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
28547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
28647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
28747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = mStatus_NoSuchNameErr;
28847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
28947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
29047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
29147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
29247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
29347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
29447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// create a socket connected to nameserver
29547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// caller terminates connection via close()
29647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
29747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
29847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int ntries = 0, retry = 0;
29947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
30047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (1)
30147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
30247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSIPPort port = zeroIPPort;
30347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int fd;
30447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
30547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		TCPSocket *sock = mDNSPlatformTCPSocket( NULL, 0, &port );
30647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( !sock ) { LogErr("ConnectToServer", "socket");  return NULL; }
30747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fd = mDNSPlatformTCPGetFD( sock );
30847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
30947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformTCPCloseConnection( sock );
31047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (++ntries < 10)
31147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
31247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogErr("ConnectToServer", "connect");
31347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("ConnectToServer - retrying connection");
31447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!retry) retry = 500000 + random() % 500000;
31547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			usleep(retry);
31647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			retry *= 2;
31747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
31847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else { Log("ConnectToServer - %d failed attempts.  Aborting.", ntries); return NULL; }
31947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
32047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
32147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
32247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// send an entire block of data over a connected socket
32347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int MySend(TCPSocket *sock, const void *msg, int len)
32447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
32547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int selectval, n, nsent = 0;
32647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fd_set wset;
32747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
32847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
32947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (nsent < len)
33047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
33147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int fd;
33247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_ZERO(&wset);
33447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fd = mDNSPlatformTCPGetFD( sock );
33647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET( fd, &wset );
33847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		selectval = select( fd+1, NULL, &wset, NULL, &timeout);
33947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (selectval < 0) { LogErr("MySend", "select");  return -1; }
34047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!selectval || !FD_ISSET(fd, &wset)) { Log("MySend - timeout"); return -1; }
34147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
34247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		n = mDNSPlatformWriteTCP( sock, ( char* ) msg + nsent, len - nsent);
34347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
34447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (n < 0) { LogErr("MySend", "send");  return -1; }
34547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		nsent += n;
34647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
34747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return 0;
34847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
34947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Transmit a DNS message, prefixed by its length, over TCP, blocking if necessary
35147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int SendPacket(TCPSocket *sock, PktMsg *pkt)
35247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
35347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// send the lenth, in network byte order
35447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 len = htons((mDNSu16)pkt->len);
35547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (MySend(sock, &len, sizeof(len)) < 0) return -1;
35647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// send the message
35847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("SendPacket Q:%d A:%d A:%d A:%d ",
35947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(pkt->msg.h.numQuestions),
36047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(pkt->msg.h.numAnswers),
36147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(pkt->msg.h.numAuthorities),
36247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(pkt->msg.h.numAdditionals));
36347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return MySend(sock, &pkt->msg, pkt->len);
36447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
36547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
36647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Receive len bytes, waiting until we have all of them.
36747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns number of bytes read (which should always be the number asked for).
36847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic int my_recv(TCPSocket *sock, void *const buf, const int len, mDNSBool * closed)
36947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    {
37047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions;
37147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // use an explicit while() loop instead.
37247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // Also, don't try to do '+=' arithmetic on the original "void *" pointer --
37347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // arithmetic on "void *" pointers is compiler-dependent.
37447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
37547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fd_set rset;
37647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
37747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    int selectval, remaining = len;
37847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    char *ptr = (char *)buf;
37947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ssize_t num_read;
38047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (remaining)
38247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	{
38347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int fd;
38447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		fd = mDNSPlatformTCPGetFD( sock );
38647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_ZERO(&rset);
38847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET(fd, &rset);
38947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		selectval = select(fd+1, &rset, NULL, NULL, &timeout);
39047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (selectval < 0) { LogErr("my_recv", "select");  return -1; }
39147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!selectval || !FD_ISSET(fd, &rset))
39247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
39347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("my_recv - timeout");
39447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return -1;
39547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
39647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		num_read = mDNSPlatformReadTCP( sock, ptr, remaining, closed );
39847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	if (((num_read == 0) && *closed) || (num_read < 0) || (num_read > remaining)) return -1;
40047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (num_read == 0) return 0;
40147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	ptr       += num_read;
40247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	remaining -= num_read;
40347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    	}
40447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    return(len);
40547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    }
40647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
40747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Return a DNS Message read off of a TCP socket, or NULL on failure
40847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If storage is non-null, result is placed in that buffer.  Otherwise,
40947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// returned value is allocated with Malloc, and contains sufficient extra
41047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// storage for a Lease OPT RR
41147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
41247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal PktMsg*
41347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltRecvPacket
41447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
41547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPSocket *	sock,
41647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	storage,
41747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool	*	closed
41847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
41947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
42047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				nread;
42147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int 			allocsize;
42247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16			msglen = 0;
42347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	pkt = NULL;
42447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned int	srclen;
42547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				fd;
42647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err = 0;
42747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
42847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fd = mDNSPlatformTCPGetFD( sock );
42947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
43047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	nread = my_recv( sock, &msglen, sizeof( msglen ), closed );
43147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
43247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( nread != -1, exit, err = mStatus_UnknownErr );
43347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( nread > 0, exit, err = mStatus_NoError );
43447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
43547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msglen = ntohs( msglen );
43647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( nread == sizeof( msglen ), exit, err = mStatus_UnknownErr; Log( "Could not read length field of message") );
43747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
43847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( storage )
43947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
44047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action_quiet( msglen <= sizeof( storage->msg ), exit, err = mStatus_UnknownErr; Log( "RecvPacket: provided buffer too small." ) );
44147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt = storage;
44247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
44347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
44447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
44547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// buffer extra space to add an OPT RR
44647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
44747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( msglen > sizeof(DNSMessage))
44847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
44947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			allocsize = sizeof(PktMsg) - sizeof(DNSMessage) + msglen;
45047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
45147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
45247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
45347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			allocsize = sizeof(PktMsg);
45447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
45547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
45647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt = malloc(allocsize);
45747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action_quiet( pkt, exit, err = mStatus_NoMemoryErr; LogErr( "RecvPacket", "malloc" ) );
45847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformMemZero( pkt, sizeof( *pkt ) );
45947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
46047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
46147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->len = msglen;
46247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	srclen = sizeof(pkt->src);
46347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
46447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( getpeername( fd, ( struct sockaddr* ) &pkt->src, &srclen ) || ( srclen != sizeof( pkt->src ) ) )
46547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
46647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogErr("RecvPacket", "getpeername");
46747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformMemZero(&pkt->src, sizeof(pkt->src));
46847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
46947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	nread = my_recv(sock, &pkt->msg, msglen, closed );
47147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( nread >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvPacket", "recv" ) );
47247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( nread == msglen, exit, err = mStatus_UnknownErr ; Log( "Could not read entire message" ) );
47347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( pkt->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr ; Log( "RecvPacket: Message too short (%d bytes)", pkt->len ) );
47447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
47647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( err && pkt )
47847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
47947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( pkt != storage )
48047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
48147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			free(pkt);
48247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
48347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
48447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt = NULL;
48547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
48647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
48747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return pkt;
48847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
48947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal DNSZone*
49247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltFindZone
49347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
49447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo	*	self,
49547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname	*	name
49647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
49747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
49847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSZone * zone;
49947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
50047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for ( zone = self->zones; zone; zone = zone->next )
50147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
50247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( SameDomainName( &zone->name, name ) )
50347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
50447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				break;
50547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
50647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
50747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
50847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return zone;
50947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
51047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
51147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
51247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool
51347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltZoneHandlesName
51447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
51547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainname * zname,
51647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainname * dname
51747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
51847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
51947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16	i = DomainNameLength( zname );
52047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16	j = DomainNameLength( dname );
52147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
52247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( ( i == ( MAX_DOMAIN_NAME + 1 ) ) || ( j == ( MAX_DOMAIN_NAME + 1 ) ) || ( i > j )  || ( memcmp( zname->c, dname->c + ( j - i ), i ) != 0 ) )
52347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
52447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return mDNSfalse;
52547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
52647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
52747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return mDNStrue;
52847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
52947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
53047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
53147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool IsQuery( PktMsg * pkt )
53247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
53347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery );
53447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
53547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
53647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
53747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool IsUpdate( PktMsg * pkt )
53847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
53947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_OP_Update );
54047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
54147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
54247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
54347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool IsNotify(PktMsg *pkt)
54447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
54547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( mDNSu8) ( kDNSFlag0_OP_Notify );
54647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
54747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
54847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
54947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool IsLLQRequest(PktMsg *pkt)
55047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
55147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = NULL, *end = (mDNSu8 *)&pkt->msg + pkt->len;
55247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LargeCacheRecord lcr;
55347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
55447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool result = mDNSfalse;
55547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
55647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrNToH(pkt);
55747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((mDNSu8)(pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (mDNSu8)(kDNSFlag0_QR_Query | kDNSFlag0_OP_StdQuery)) goto end;
55847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
55947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!pkt->msg.h.numAdditionals) goto end;
56047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = LocateAdditionals(&pkt->msg, end);
56147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) goto end;
56247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
56347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// find last Additional info.
56447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < pkt->msg.h.numAdditionals; i++)
56547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
56647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
56747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { Log("Unable to read additional record"); goto end; }
56847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
56947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
57047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( lcr.r.resrec.rrtype == kDNSType_OPT && lcr.r.resrec.rdlength >= DNSOpt_LLQData_Space && lcr.r.resrec.rdata->u.opt[0].opt == kDNSOpt_LLQ )
57147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
57247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		result = mDNStrue;
57347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
57447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
57547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end:
57647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(pkt);
57747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return result;
57847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
57947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
58047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// !!!KRS implement properly
58147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool IsLLQAck(PktMsg *pkt)
58247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
58347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == (mDNSu8) ( kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery ) &&
58447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt->msg.h.numQuestions && !pkt->msg.h.numAnswers && !pkt->msg.h.numAuthorities) return mDNStrue;
58547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return mDNSfalse;
58647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
58747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
58847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
58947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool
59047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltIsPublicSRV
59147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
59247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo	*	self,
59347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSQuestion	*	q
59447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
59547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
59647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNameListElem	*	elem;
59747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			ret		= mDNSfalse;
59847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int					i		= ( int ) DomainNameLength( &q->qname ) - 1;
59947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
60047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for ( elem = self->public_names; elem; elem = elem->next )
60147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
60247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int	j = ( int ) DomainNameLength( &elem->name ) - 1;
60347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
60447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( i > j )
60547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
60647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			for ( ; i >= 0; i--, j-- )
60747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
60847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if ( q->qname.c[ i ] != elem->name.c[ j ] )
60947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
61047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					ret = mDNStrue;
61147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					goto exit;
61247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
61347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
61447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
61547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
61647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
61747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
61847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
61947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ret;
62047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
62147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
62247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
62347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void
62447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltSetZone
62547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
62647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo	* self,
62747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		* pkt
62847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
62947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
63047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname			zname;
63147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8				QR_OP;
63247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8	*	ptr = pkt->msg.data;
63347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			exception = mDNSfalse;
63447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
63547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Initialize
63647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
63747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->zone			= NULL;
63847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->isZonePublic	= mDNStrue;
63947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	zname.c[0]			= '\0';
64047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Figure out what type of packet this is
64247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	QR_OP = ( mDNSu8 ) ( pkt->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask );
64447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( IsQuery( pkt ) )
64647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
64747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DNSQuestion question;
64847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// It's a query
65047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
65247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AppendDomainName( &zname, &question.qname );
65447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		exception = ( ( question.qtype == kDNSType_SOA ) || ( question.qtype == kDNSType_NS ) || ( ( question.qtype == kDNSType_SRV ) && IsPublicSRV( self, &question ) ) );
65647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
65747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if ( IsUpdate( pkt ) )
65847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
65947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DNSQuestion question;
66047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// It's an update.  The format of the zone section is the same as the format for the question section
66247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// according to RFC 2136, so we'll just treat this as a question so we can get at the zone.
66347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = getQuestion( &pkt->msg, ptr, ( ( mDNSu8* ) &pkt->msg ) + pkt->len, NULL, &question );
66547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AppendDomainName( &zname, &question.qname );
66747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		exception = mDNSfalse;
66947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
67047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
67147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( zname.c[0] != '\0' )
67247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
67347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Find the right zone
67447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
67547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for ( pkt->zone = self->zones; pkt->zone; pkt->zone = pkt->zone->next )
67647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
67747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ( ZoneHandlesName( &pkt->zone->name, &zname ) )
67847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
67947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				VLog( "found correct zone %##s for query", pkt->zone->name.c );
68047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				pkt->isZonePublic = ( ( pkt->zone->type == kDNSZonePublic ) || exception );
68247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				VLog( "zone %##s is %s", pkt->zone->name.c, ( pkt->isZonePublic ) ? "public" : "private" );
68447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				break;
68647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
68747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
68847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
68947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
69047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
69147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
69247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int
69347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltUDPServerTransaction(const DaemonInfo *d, const PktMsg *request, PktMsg *reply, mDNSBool *trunc)
69447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
69547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fd_set			rset;
69647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval	timeout = { 3, 0 };  // until we remove all calls from main thread, keep timeout short
69747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				sd;
69847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				res;
69947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err = mStatus_NoError;
70047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
70147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Initialize
70247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
70347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*trunc = mDNSfalse;
70447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
70547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Create a socket
70647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
70747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt 	sd = socket( AF_INET, SOCK_DGRAM, 0 );
70847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( sd >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "socket" ) );
70947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
71047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Send the packet to the nameserver
71147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
71247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("UDPServerTransaction Q:%d A:%d A:%d A:%d ",
71347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(request->msg.h.numQuestions),
71447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(request->msg.h.numAnswers),
71547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(request->msg.h.numAuthorities),
71647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ntohs(request->msg.h.numAdditionals));
71747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	res = sendto( sd, (char *)&request->msg, request->len, 0, ( struct sockaddr* ) &d->ns_addr, sizeof( d->ns_addr ) );
71847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( res == (int) request->len, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "sendto" ) );
71947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
72047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Wait for reply
72147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
72247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FD_ZERO( &rset );
72347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FD_SET( sd, &rset );
72447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	res = select( sd + 1, &rset, NULL, NULL, &timeout );
72547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( res >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "select" ) );
72647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( ( res > 0 ) && FD_ISSET( sd, &rset ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - timeout" ) );
72747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
72847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Receive reply
72947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply->len = recvfrom( sd, &reply->msg, sizeof(reply->msg), 0, NULL, NULL );
73147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( ( ( int ) reply->len ) >= 0, exit, err = mStatus_UnknownErr; LogErr( "UDPServerTransaction", "recvfrom" ) );
73247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( reply->len >= sizeof( DNSMessageHeader ), exit, err = mStatus_UnknownErr; Log( "UDPServerTransaction - Message too short (%d bytes)", reply->len ) );
73347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Check for truncation bit
73547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( reply->msg.h.flags.b[0] & kDNSFlag0_TC )
73747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
73847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*trunc = mDNStrue;
73947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
74047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
74147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
74247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
74347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( sd >= 0 )
74447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
74547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		close( sd );
74647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
74747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
74847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
74947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
75047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
75147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
75247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Dynamic Update Utility Routines
75347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
75447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
75547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// check if a request and server response complete a successful dynamic update
75647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool SuccessfulUpdateTransaction(PktMsg *request, PktMsg *reply)
75747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
75847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buf[32];
75947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char *vlogmsg = NULL;
76047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
76147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// check messages
76247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!request || !reply) { vlogmsg = "NULL message"; goto failure; }
76347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (request->len < sizeof(DNSMessageHeader) || reply->len < sizeof(DNSMessageHeader)) { vlogmsg = "Malformatted message"; goto failure; }
76447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
76547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// check request operation
76647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask))
76747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ vlogmsg = "Request opcode not an update"; goto failure; }
76847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
76947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// check result
77047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask)) { vlogmsg = "Reply contains non-zero rcode";  goto failure; }
77147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_OP_Update | kDNSFlag0_QR_Response))
77247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ vlogmsg = "Reply opcode not an update response"; goto failure; }
77347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
77447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Successful update from %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32));
77547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return mDNStrue;
77647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
77747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	failure:
77847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Request %s: %s", inet_ntop(AF_INET, &request->src.sin_addr, buf, 32), vlogmsg);
77947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return mDNSfalse;
78047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
78147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
78247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Allocate an appropriately sized CacheRecord and copy data from original.
78347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Name pointer in CacheRecord object is set to point to the name specified
78447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
78547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal CacheRecord *CopyCacheRecord(const CacheRecord *orig, domainname *name)
78647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
78747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CacheRecord *cr;
78847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	size_t size = sizeof(*cr);
78947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (orig->resrec.rdlength > InlineCacheRDSize) size += orig->resrec.rdlength - InlineCacheRDSize;
79047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	cr = malloc(size);
79147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!cr) { LogErr("CopyCacheRecord", "malloc"); return NULL; }
79247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	memcpy(cr, orig, size);
79347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	cr->resrec.rdata = (RData*)&cr->smallrdatastorage;
79447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	cr->resrec.name = name;
79547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
79647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return cr;
79747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
79847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
79947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
80047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
80147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Lease Hashtable Utility Routines
80247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
80347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
80447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// double hash table size
80547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// caller must lock table prior to invocation
80647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RehashTable(DaemonInfo *d)
80747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
80847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	RRTableElem *ptr, *tmp, **new;
80947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i, bucket, newnbuckets = d->nbuckets * 2;
81047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
81147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Rehashing lease table (new size %d buckets)", newnbuckets);
81247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	new = malloc(sizeof(RRTableElem *) * newnbuckets);
81347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!new) { LogErr("RehashTable", "malloc");  return; }
81447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(new, newnbuckets * sizeof(RRTableElem *));
81547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
81647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < d->nbuckets; i++)
81747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
81847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = d->table[i];
81947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (ptr)
82047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
82147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			bucket = ptr->rr.resrec.namehash % newnbuckets;
82247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			tmp = ptr;
82347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			ptr = ptr->next;
82447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			tmp->next = new[bucket];
82547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			new[bucket] = tmp;
82647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
82747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
82847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->nbuckets = newnbuckets;
82947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	free(d->table);
83047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->table = new;
83147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
83247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
83347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// print entire contents of hashtable, invoked via SIGINFO
83447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void PrintLeaseTable(DaemonInfo *d)
83547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
83647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
83747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	RRTableElem *ptr;
83847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char rrbuf[MaxMsg], addrbuf[16];
83947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval now;
84047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int hr, min, sec;
84147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
84247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (gettimeofday(&now, NULL)) { LogErr("PrintTable", "gettimeofday"); return; }
84347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (pthread_mutex_lock(&d->tablelock)) { LogErr("PrintTable", "pthread_mutex_lock"); return; }
84447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
84547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	Log("Dumping Lease Table Contents (table contains %d resource records)", d->nelems);
84647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < d->nbuckets; i++)
84747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
84847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (ptr = d->table[i]; ptr; ptr = ptr->next)
84947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
85047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			hr = ((ptr->expire - now.tv_sec) / 60) / 60;
85147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			min = ((ptr->expire - now.tv_sec) / 60) % 60;
85247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			sec = (ptr->expire - now.tv_sec) % 60;
85347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			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,
85447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				GetRRDisplayString_rdb(&ptr->rr.resrec, &ptr->rr.resrec.rdata->u, rrbuf));
85547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
85647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
85747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pthread_mutex_unlock(&d->tablelock);
85847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
85947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
86047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
86147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Startup SRV Registration Routines
86247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Register _dns-update._udp/_tcp.<zone> SRV records indicating the port on which
86347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the daemon accepts requests
86447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
86547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
86647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// delete all RRS of a given name/type
86747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu8 *putRRSetDeletion(DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit,  ResourceRecord *rr)
86847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
86947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
87047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr || ptr + 10 >= limit) return NULL;  // out of space
87147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
87247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
87347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[2] = (mDNSu8)((mDNSu16)kDNSQClass_ANY >> 8);
87447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[3] = (mDNSu8)((mDNSu16)kDNSQClass_ANY &  0xFF);
87547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(ptr+4, sizeof(rr->rroriginalttl) + sizeof(rr->rdlength)); // zero ttl/rdata
87647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.mDNS_numUpdates++;
87747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr + 10;
87847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
87947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
88047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu8 *PutUpdateSRV(DaemonInfo *d, DNSZone * zone, PktMsg *pkt, mDNSu8 *ptr, char *regtype, mDNSIPPort port, mDNSBool registration)
88147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
88247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord rr;
88347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char hostname[1024], buf[MaxMsg];
88447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *end = (mDNSu8 *)&pkt->msg + sizeof(DNSMessage);
88547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
88647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	( void ) d;
88747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
88847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_SetupResourceRecord(&rr, NULL, 0, kDNSType_SRV, SRV_TTL, kDNSRecordTypeUnique, AuthRecordAny, NULL, NULL);
88947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rrclass = kDNSClass_IN;
89047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdata->u.srv.priority = 0;
89147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdata->u.srv.weight   = 0;
89247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdata->u.srv.port     = port;
89347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (gethostname(hostname, 1024) < 0 || !MakeDomainNameFromDNSNameString(&rr.resrec.rdata->u.srv.target, hostname))
89447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr.resrec.rdata->u.srv.target.c[0] = '\0';
89547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
89647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainNameFromDNSNameString(&rr.namestorage, regtype);
89747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AppendDomainName(&rr.namestorage, &zone->name);
89847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("%s  %s", registration ? "Registering SRV record" : "Deleting existing RRSet",
89947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		 GetRRDisplayString_rdb(&rr.resrec, &rr.resrec.rdata->u, buf));
90047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (registration) ptr = PutResourceRecord(&pkt->msg, ptr, &pkt->msg.h.mDNS_numUpdates, &rr.resrec);
90147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else              ptr = putRRSetDeletion(&pkt->msg, ptr, end, &rr.resrec);
90247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr;
90347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
90447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
90547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
90647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// perform dynamic update.
90747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// specify deletion by passing false for the register parameter, otherwise register the records.
90847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int UpdateSRV(DaemonInfo *d, mDNSBool registration)
90947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
91047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPSocket *sock = NULL;
91147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSZone * zone;
91247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int err = mStatus_NoError;
91347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
91447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	sock = ConnectToServer( d );
91547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( sock, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: ConnectToServer failed" ) );
91647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
91747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for ( zone = d->zones; zone; zone = zone->next )
91847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
91947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		PktMsg pkt;
92047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *ptr = pkt.msg.data;
92147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
92247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		PktMsg *reply = NULL;
92347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool closed;
92447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool ok;
92547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
92647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Initialize message
92747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
92847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
92947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt.src.sin_family = AF_INET;
93047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
93147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// format message body
93247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = putZone(&pkt.msg, ptr, end, &zone->name, mDNSOpaque16fromIntVal(kDNSClass_IN));
93347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
93447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
93547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	   if ( zone->type == kDNSZonePrivate )
93647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            {
93747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls._tcp.", d->private_port, registration);
93847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
93947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls._tcp.", d->private_port, registration);
94047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
94147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls._tcp.", d->private_port, registration);
94247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
94347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
94447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ( !registration )
94547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
94647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
94747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
94847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
94947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
95047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
95147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
95247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt        else
95347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            {
95447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ( !registration )
95547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
95647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update-tls.", d->private_port, registration);
95747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
95847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-query-tls.", d->private_port, registration);
95947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
96047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq-tls.", d->private_port, registration);
96147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
96247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
96347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
96447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-update._udp.", d->llq_port, registration);
96547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
96647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            ptr = PutUpdateSRV(d, zone, &pkt, ptr, "_dns-llq._udp.", d->llq_port, registration);
96747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            require_action( ptr, exit, err = mStatus_UnknownErr; Log("UpdateSRV: Error constructing lease expiration update" ) );
96847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
96947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
97047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		HdrHToN(&pkt);
97147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
97247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( zone->updateKeys )
97347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
97447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			DNSDigest_SignMessage( &pkt.msg, &ptr, zone->updateKeys, 0 );
97547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			require_action( ptr, exit, Log("UpdateSRV: Error constructing lease expiration update" ) );
97647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
97747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
97847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt.len = ptr - (mDNSu8 *)&pkt.msg;
97947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// send message, receive reply
98147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = SendPacket( sock, &pkt );
98347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, Log( "UpdateSRV: SendPacket failed" ) );
98447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		reply = RecvPacket( sock, NULL, &closed );
98647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( reply, exit, err = mStatus_UnknownErr; Log( "UpdateSRV: RecvPacket returned NULL" ) );
98747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ok = SuccessfulUpdateTransaction( &pkt, reply );
98947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
99047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( !ok )
99147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
99247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("SRV record registration failed with rcode %d", reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
99347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
99447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
99547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free( reply );
99647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
99747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
99847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
99947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
100047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( sock )
100147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
100247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformTCPCloseConnection( sock );
100347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
100447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
100547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
100647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
100747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
100847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// wrapper routines/macros
100947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define ClearUpdateSRV(d) UpdateSRV(d, 0)
101047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
101147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// clear any existing records prior to registration
101247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int SetUpdateSRV(DaemonInfo *d)
101347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
101447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int err;
101547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
101647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = ClearUpdateSRV(d);         // clear any existing record
101747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!err) err = UpdateSRV(d, 1);
101847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
101947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
102047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
102147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
102247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Argument Parsing and Configuration
102347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
102447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
102547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void PrintUsage(void)
102647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
102747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "Usage: dnsextd [-f <config file>] [-vhd] ...\n"
102847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"Use \"dnsextd -h\" for help\n");
102947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
103047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
103147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void PrintHelp(void)
103247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
103347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "\n\n");
103447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PrintUsage();
103547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
103647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr,
103747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"dnsextd is a daemon that implements DNS extensions supporting Dynamic DNS Update Leases\n"
103847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            "and Long Lived Queries, used in Wide-Area DNS Service Discovery, on behalf of name servers\n"
103947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"that do not natively support these extensions.  (See dns-sd.org for more info on DNS Service\n"
104047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"Discovery, Update Leases, and Long Lived Queries.)\n\n"
104147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
104247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            "dnsextd requires one argument,the zone, which is the domain for which Update Leases\n"
104347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt            "and Long Lived Queries are to be administered.  dnsextd communicates directly with the\n"
104447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"primary master server for this zone.\n\n"
104547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
104647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"The options are as follows:\n\n"
104747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
104847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"-f    Specify configuration file. The default is /etc/dnsextd.conf.\n\n"
104947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
105047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"-d    Run daemon in foreground.\n\n"
105147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
105247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"-h    Print help.\n\n"
105347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
105447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"-v    Verbose output.\n\n"
105547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		);
105647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
105747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
105847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
105947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: ProcessArgs called before process is daemonized, and therefore must open no descriptors
106047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// returns 0 (success) if program is to continue execution
106147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// output control arguments (-f, -v) do not affect this routine
106247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int ProcessArgs(int argc, char *argv[], DaemonInfo *d)
106347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
106447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSZone	*	zone;
106547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int			opt;
106647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int			err = 0;
106747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
106847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	cfgfile = strdup( CONFIG_FILE );
106947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr );
107047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
107147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // defaults, may be overriden by command option
107247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
107347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// setup our sockaddr
107447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
107547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero( &d->addr, sizeof( d->addr ) );
107647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->addr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
107747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->addr.sin_port		= UnicastDNSPort.NotAnInteger;
107847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->addr.sin_family		= AF_INET;
107947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef NOT_HAVE_SA_LEN
108047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->addr.sin_len			= sizeof( d->addr );
108147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
108247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
108347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// setup nameserver's sockaddr
108447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
108547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(&d->ns_addr, sizeof(d->ns_addr));
108647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->ns_addr.sin_family	= AF_INET;
108747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	inet_pton( AF_INET, LOOPBACK, &d->ns_addr.sin_addr );
108847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->ns_addr.sin_port		= NSIPCPort.NotAnInteger;
108947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef NOT_HAVE_SA_LEN
109047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->ns_addr.sin_len		= sizeof( d->ns_addr );
109147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
109247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
109347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// setup our ports
109447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
109547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->private_port = PrivateDNSPort;
109647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->llq_port     = DNSEXTPort;
109747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
109847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while ((opt = getopt(argc, argv, "f:hdv")) != -1)
109947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
110047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		switch(opt)
110147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
110247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 'f': free( cfgfile ); cfgfile = strdup( optarg ); require_action( cfgfile, arg_error, err = mStatus_NoMemoryErr ); break;
110347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 'h': PrintHelp();    return -1;
110447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 'd': foreground = 1; break;		// Also used when launched via OS X's launchd mechanism
110547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 'v': verbose = 1;    break;
110647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			default:  goto arg_error;
110747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
110847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
110947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
111047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = ParseConfig( d, cfgfile );
111147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_noerr( err, arg_error );
111247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
111347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Make sure we've specified some zones
111447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
111547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( d->zones, arg_error, err = mStatus_UnknownErr );
111647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
111747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// if we have a shared secret, use it for the entire zone
111847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
111947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for ( zone = d->zones; zone; zone = zone->next )
112047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
112147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( zone->updateKeys )
112247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
112347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			AssignDomainName( &zone->updateKeys->domain, &zone->name );
112447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
112547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
112647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
112747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return 0;
112847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
112947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltarg_error:
113047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
113147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PrintUsage();
113247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return -1;
113347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
113447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
113547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
113647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
113747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Initialization Routines
113847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
113947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
114047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Allocate memory, initialize locks and bookkeeping variables
114147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int InitLeaseTable(DaemonInfo *d)
114247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
114347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (pthread_mutex_init(&d->tablelock, NULL)) { LogErr("InitLeaseTable", "pthread_mutex_init"); return -1; }
114447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->nbuckets = LEASETABLE_INIT_NBUCKETS;
114547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->nelems = 0;
114647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->table = malloc(sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
114747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!d->table) { LogErr("InitLeaseTable", "malloc"); return -1; }
114847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(d->table, sizeof(RRTableElem *) * LEASETABLE_INIT_NBUCKETS);
114947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return 0;
115047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
115147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
115247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
115347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int
115447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltSetupSockets
115547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
115647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo * self
115747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
115847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
115947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const int kOn = 1;
116047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int					sockpair[2];
116147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			private = mDNSfalse;
116247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct sockaddr_in	daddr;
116347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSZone			*	zone;
116447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus				err = 0;
116547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
116647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// set up sockets on which we all ns requests
116747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
116847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
116947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( dnssd_SocketValid(self->tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
117047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
117147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(SO_REUSEADDR)
117247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = setsockopt(self->tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
117347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tcpsd" ) );
117447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
117547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
117647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = bind( self->tcpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
117747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "bind self->tcpsd" ) );
117847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
117947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = listen( self->tcpsd, LISTENQ );
118047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
118147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
118247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
118347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( dnssd_SocketValid(self->udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
118447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
118547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(SO_REUSEADDR)
118647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = setsockopt(self->udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
118747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->udpsd" ) );
118847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
118947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
119047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = bind( self->udpsd, ( struct sockaddr* ) &self->addr, sizeof( self->addr ) );
119147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "bind self->udpsd" ) );
119247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
119347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// set up sockets on which we receive llq requests
119447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
119547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(&self->llq_addr, sizeof(self->llq_addr));
119647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->llq_addr.sin_family		= AF_INET;
119747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->llq_addr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
119847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->llq_addr.sin_port			= ( self->llq_port.NotAnInteger ) ? self->llq_port.NotAnInteger : DNSEXTPort.NotAnInteger;
119947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
120047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (self->llq_addr.sin_port == self->addr.sin_port)
120147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
120247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		self->llq_tcpsd = self->tcpsd;
120347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		self->llq_udpsd = self->udpsd;
120447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
120547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
120647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
120747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
120847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( dnssd_SocketValid(self->llq_tcpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
120947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
121047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(SO_REUSEADDR)
121147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = setsockopt(self->llq_tcpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
121247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_tcpsd" ) );
121347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
121447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
121547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = bind( self->llq_tcpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
121647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_tcpsd" ) );
121747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
121847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = listen( self->llq_tcpsd, LISTENQ );
121947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
122047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
122147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		self->llq_udpsd = socket( AF_INET, SOCK_DGRAM, 0 );
122247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( dnssd_SocketValid(self->llq_udpsd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
122347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
122447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(SO_REUSEADDR)
122547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = setsockopt(self->llq_udpsd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
122647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->llq_udpsd" ) );
122747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
122847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
122947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = bind(self->llq_udpsd, ( struct sockaddr* ) &self->llq_addr, sizeof( self->llq_addr ) );
123047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, LogErr( "SetupSockets", "bind self->llq_udpsd" ) );
123147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
123247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
123347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// set up Unix domain socket pair for LLQ polling thread to signal main thread that a change to the zone occurred
123447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
123547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = socketpair( AF_LOCAL, SOCK_STREAM, 0, sockpair );
123647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "socketpair" ) );
123747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
123847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->LLQEventListenSock = sockpair[0];
123947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->LLQEventNotifySock = sockpair[1];
124047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
124147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// set up socket on which we receive private requests
124247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
124347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->llq_tcpsd = socket( AF_INET, SOCK_STREAM, 0 );
124447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
124547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(&daddr, sizeof(daddr));
124647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	daddr.sin_family		= AF_INET;
124747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	daddr.sin_addr.s_addr	= zerov4Addr.NotAnInteger;
124847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	daddr.sin_port			= ( self->private_port.NotAnInteger ) ? self->private_port.NotAnInteger : PrivateDNSPort.NotAnInteger;
124947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
125047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	self->tlssd = socket( AF_INET, SOCK_STREAM, 0 );
125147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( dnssd_SocketValid(self->tlssd), exit, err = mStatus_UnknownErr; LogErr( "SetupSockets", "socket" ) );
125247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
125347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(SO_REUSEADDR)
125447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = setsockopt(self->tlssd, SOL_SOCKET, SO_REUSEADDR, &kOn, sizeof(kOn));
125547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "SO_REUSEADDR self->tlssd" ) );
125647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
125747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
125847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = bind( self->tlssd, ( struct sockaddr* ) &daddr, sizeof( daddr ) );
125947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "bind self->tlssd" ) );
126047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
126147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = listen( self->tlssd, LISTENQ );
126247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "SetupSockets", "listen" ) );
126347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
126447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Do we have any private zones?
126547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
126647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for ( zone = self->zones; zone; zone = zone->next )
126747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
126847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( zone->type == kDNSZonePrivate )
126947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
127047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			private = mDNStrue;
127147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			break;
127247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
127347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
127447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
127547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( private )
127647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
127747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = mDNSPlatformTLSSetupCerts();
127847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, LogErr( "SetupSockets", "mDNSPlatformTLSSetupCerts" ) );
127947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
128047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
128147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
128247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
128347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
128447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
128547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
128647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
128747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// periodic table updates
128847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
128947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
129047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Delete a resource record from the nameserver via a dynamic update
129147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// sd is a socket already connected to the server
129247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DeleteOneRecord(DaemonInfo *d, CacheRecord *rr, domainname *zname, TCPSocket *sock)
129347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
129447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSZone	*	zone;
129547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg pkt;
129647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *ptr = pkt.msg.data;
129747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *end = (mDNSu8 *)&pkt.msg + sizeof(DNSMessage);
129847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buf[MaxMsg];
129947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool closed;
130047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg *reply = NULL;
130147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
130247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Expiring record %s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, buf));
130347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
130447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&pkt.msg.h, zeroID, UpdateReqFlags);
130547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
130647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putZone(&pkt.msg, ptr, end, zname, mDNSOpaque16fromIntVal(rr->resrec.rrclass));
130747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) goto end;
130847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDeletionRecord(&pkt.msg, ptr, &rr->resrec);
130947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) goto end;
131047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
131147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(&pkt);
131247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
131347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	zone = FindZone( d, zname );
131447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
131547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( zone && zone->updateKeys)
131647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
131747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DNSDigest_SignMessage(&pkt.msg, &ptr, zone->updateKeys, 0 );
131847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) goto end;
131947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
132047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
132147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt.len = ptr - (mDNSu8 *)&pkt.msg;
132247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt.src.sin_addr.s_addr = zerov4Addr.NotAnInteger; // address field set solely for verbose logging in subroutines
132347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt.src.sin_family = AF_INET;
132447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SendPacket( sock, &pkt)) { Log("DeleteOneRecord: SendPacket failed"); }
132547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply = RecvPacket( sock, NULL, &closed );
132647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (reply) HdrNToH(reply);
132747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( reply, end, Log( "DeleteOneRecord: RecvPacket returned NULL" ) );
132847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
132947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!SuccessfulUpdateTransaction(&pkt, reply))
133047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		Log("Expiration update failed with rcode %d", reply ? reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask : -1);
133147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
133247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end:
133347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { Log("DeleteOneRecord: Error constructing lease expiration update"); }
133447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (reply) free(reply);
133547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
133647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
133747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// iterate over table, deleting expired records (or all records if DeleteAll is true)
133847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DeleteRecords(DaemonInfo *d, mDNSBool DeleteAll)
133947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
134047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval now;
134147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
134247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPSocket *sock = ConnectToServer(d);
134347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!sock) { Log("DeleteRecords: ConnectToServer failed"); return; }
134447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (gettimeofday(&now, NULL)) { LogErr("DeleteRecords ", "gettimeofday"); return; }
134547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (pthread_mutex_lock(&d->tablelock)) { LogErr("DeleteRecords", "pthread_mutex_lock"); return; }
134647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
134747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < d->nbuckets; i++)
134847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
134947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		RRTableElem **ptr = &d->table[i];
135047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (*ptr)
135147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
135247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (DeleteAll || (*ptr)->expire - now.tv_sec < 0)
135347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
135447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				RRTableElem *fptr;
135547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// delete record from server
135647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				DeleteOneRecord(d, &(*ptr)->rr, &(*ptr)->zone, sock);
135747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				fptr = *ptr;
135847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr = (*ptr)->next;
135947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				free(fptr);
136047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				d->nelems--;
136147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
136247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else ptr = &(*ptr)->next;
136347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
136447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
136547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pthread_mutex_unlock(&d->tablelock);
136647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformTCPCloseConnection( sock );
136747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
136847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
136947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
137047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// main update request handling
137147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
137247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
137347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Add, delete, or refresh records in table based on contents of a successfully completed dynamic update
137447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void UpdateLeaseTable(PktMsg *pkt, DaemonInfo *d, mDNSs32 lease)
137547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
137647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	RRTableElem **rptr, *tmp;
137747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i, allocsize, bucket;
137847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LargeCacheRecord lcr;
137947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ResourceRecord *rr = &lcr.r.resrec;
138047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr, *end;
138147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval tv;
138247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSQuestion zone;
138347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buf[MaxMsg];
138447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
138547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (pthread_mutex_lock(&d->tablelock)) { LogErr("UpdateLeaseTable", "pthread_mutex_lock"); return; }
138647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrNToH(pkt);
138747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = pkt->msg.data;
138847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = (mDNSu8 *)&pkt->msg + pkt->len;
138947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = getQuestion(&pkt->msg, ptr, end, 0, &zone);
139047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { Log("UpdateLeaseTable: cannot read zone");  goto cleanup; }
139147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = LocateAuthorities(&pkt->msg, end);
139247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { Log("UpdateLeaseTable: Format error");  goto cleanup; }
139347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
139447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < pkt->msg.h.mDNS_numUpdates; i++)
139547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
139647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool DeleteAllRRSets = mDNSfalse, DeleteOneRRSet = mDNSfalse, DeleteOneRR = mDNSfalse;
139747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
139847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
139947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr || lcr.r.resrec.RecordType == kDNSRecordTypePacketNegative) { Log("UpdateLeaseTable: GetLargeResourceRecord failed"); goto cleanup; }
140047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		bucket = rr->namehash % d->nbuckets;
140147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rptr = &d->table[bucket];
140247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
140347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// handle deletions
140447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (rr->rrtype == kDNSQType_ANY && !rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
140547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			DeleteAllRRSets = mDNStrue; // delete all rrsets for a name
140647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if (!rr->rroriginalttl && rr->rrclass == kDNSQClass_ANY && !rr->rdlength)
140747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			DeleteOneRRSet = mDNStrue;
140847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if (!rr->rroriginalttl && rr->rrclass == kDNSClass_NONE)
140947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			DeleteOneRR = mDNStrue;
141047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
141147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (DeleteAllRRSets || DeleteOneRRSet || DeleteOneRR)
141247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
141347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			while (*rptr)
141447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			  {
141547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			  if (SameDomainName((*rptr)->rr.resrec.name, rr->name) &&
141647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				 (DeleteAllRRSets ||
141747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				 (DeleteOneRRSet && (*rptr)->rr.resrec.rrtype == rr->rrtype) ||
141847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  (DeleteOneRR && IdenticalResourceRecord(&(*rptr)->rr.resrec, rr))))
141947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  {
142047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  tmp = *rptr;
142147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  VLog("Received deletion update for %s", GetRRDisplayString_rdb(&tmp->rr.resrec, &tmp->rr.resrec.rdata->u, buf));
142247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  *rptr = (*rptr)->next;
142347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  free(tmp);
142447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  d->nelems--;
142547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				  }
142647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			  else rptr = &(*rptr)->next;
142747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			  }
142847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
142947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if (lease > 0)
143047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
143147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// see if add or refresh
143247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			while (*rptr && !IdenticalResourceRecord(&(*rptr)->rr.resrec, rr)) rptr = &(*rptr)->next;
143347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (*rptr)
143447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
143547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// refresh
143647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
143747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				(*rptr)->expire = tv.tv_sec + (unsigned)lease;
143847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				VLog("Refreshing lease for %s", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
143947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
144047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
144147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
144247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// New record - add to table
144347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (d->nelems > d->nbuckets)
144447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
144547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					RehashTable(d);
144647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					bucket = rr->namehash % d->nbuckets;
144747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					rptr = &d->table[bucket];
144847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
144947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (gettimeofday(&tv, NULL)) { LogErr("UpdateLeaseTable", "gettimeofday"); goto cleanup; }
145047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				allocsize = sizeof(RRTableElem);
145147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (rr->rdlength > InlineCacheRDSize) allocsize += (rr->rdlength - InlineCacheRDSize);
145247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				tmp = malloc(allocsize);
145347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (!tmp) { LogErr("UpdateLeaseTable", "malloc"); goto cleanup; }
145447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				memcpy(&tmp->rr, &lcr.r, sizeof(CacheRecord) + rr->rdlength - InlineCacheRDSize);
145547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				tmp->rr.resrec.rdata = (RData *)&tmp->rr.smallrdatastorage;
145647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				AssignDomainName(&tmp->name, rr->name);
145747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				tmp->rr.resrec.name = &tmp->name;
145847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				tmp->expire = tv.tv_sec + (unsigned)lease;
145947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				tmp->cli.sin_addr = pkt->src.sin_addr;
146047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				AssignDomainName(&tmp->zone, &zone.qname);
146147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				tmp->next = d->table[bucket];
146247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				d->table[bucket] = tmp;
146347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				d->nelems++;
146447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				VLog("Adding update for %s to lease table", GetRRDisplayString_rdb(&lcr.r.resrec, &lcr.r.resrec.rdata->u, buf));
146547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
146647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
146747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
146847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
146947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	cleanup:
147047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pthread_mutex_unlock(&d->tablelock);
147147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(pkt);
147247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
147347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
147447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Given a successful reply from a server, create a new reply that contains lease information
147547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Replies are currently not signed !!!KRS change this
147647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal PktMsg *FormatLeaseReply(DaemonInfo *d, PktMsg *orig, mDNSu32 lease)
147747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
147847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg *reply;
147947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *ptr, *end;
148047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSOpaque16 flags;
148147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
148247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(void)d;  //unused
148347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply = malloc(sizeof(*reply));
148447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!reply) { LogErr("FormatLeaseReply", "malloc"); return NULL; }
148547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	flags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_Update;
148647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	flags.b[1] = 0;
148747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
148847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&reply->msg.h, orig->msg.h.id, flags);
148947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply->src.sin_addr.s_addr = zerov4Addr.NotAnInteger;            // unused except for log messages
149047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply->src.sin_family = AF_INET;
149147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = reply->msg.data;
149247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = (mDNSu8 *)&reply->msg + sizeof(DNSMessage);
149347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putUpdateLease(&reply->msg, ptr, lease);
149447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { Log("FormatLeaseReply: putUpdateLease failed"); free(reply); return NULL; }
149547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply->len = ptr - (mDNSu8 *)&reply->msg;
149647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(reply);
149747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return reply;
149847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
149947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
150047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
150147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// pkt is thread-local, not requiring locking
150247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
150347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal PktMsg*
150447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltHandleRequest
150547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
150647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo	*	self,
150747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	request
150847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
150947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
151047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	reply = NULL;
151147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	leaseReply;
151247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg	 		buf;
151347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char			addrbuf[32];
151447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPSocket *	sock = NULL;
151547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err;
151647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSs32		lease = 0;
151747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((request->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) == kDNSFlag0_OP_Update)
151847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
151947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int i, adds = 0, dels = 0;
152047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ptr, *end = (mDNSu8 *)&request->msg + request->len;
152147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		HdrNToH(request);
152247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		lease = GetPktLease(&mDNSStorage, &request->msg, end);
152347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = LocateAuthorities(&request->msg, end);
152447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (i = 0; i < request->msg.h.mDNS_numUpdates; i++)
152547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
152647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LargeCacheRecord lcr;
152747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			ptr = GetLargeResourceRecord(NULL, &request->msg, ptr, end, 0, kDNSRecordTypePacketAns, &lcr);
152847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rroriginalttl) adds++; else dels++;
152947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
153047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		HdrHToN(request);
153147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (adds && !lease)
153247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
153347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			static const mDNSOpaque16 UpdateRefused = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update, kDNSFlag1_RC_Refused } };
153447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("Rejecting Update Request with %d additions but no lease", adds);
153547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply = malloc(sizeof(*reply));
153647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSPlatformMemZero(&reply->src, sizeof(reply->src));
153747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply->len = sizeof(DNSMessageHeader);
153847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply->zone = NULL;
153947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply->isZonePublic = 0;
154047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			InitializeDNSMessage(&reply->msg.h, request->msg.h.id, UpdateRefused);
154147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return(reply);
154247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
154347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (lease > 7200)	// Don't allow lease greater than two hours; typically 90-minute renewal period
154447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			lease = 7200;
154547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
154647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Send msg to server, read reply
154747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
154847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( request->len <= 512 )
154947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
155047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool trunc;
155147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
155247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( UDPServerTransaction( self, request, &buf, &trunc) < 0 )
155347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
155447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("HandleRequest - UDPServerTransaction failed.  Trying TCP");
155547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
155647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if ( trunc )
155747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
155847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			VLog("HandleRequest - answer truncated.  Using TCP");
155947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
156047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
156147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
156247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply = &buf; // success
156347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
156447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
156547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
156647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( !reply )
156747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
156847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool closed;
156947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int res;
157047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
157147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		sock = ConnectToServer( self );
157247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		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 ) ) );
157347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
157447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		res = SendPacket( sock, request );
157547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		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 ) ) );
157647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
157747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		reply = RecvPacket( sock, &buf, &closed );
157847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
157947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
158047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// IMPORTANT: reply is in network byte order at this point in the code
158147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// We keep it this way because we send it back to the client in the same form
158247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
158347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Is it an update?
158447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
158547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( reply && ( ( reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask ) == ( kDNSFlag0_OP_Update | kDNSFlag0_QR_Response ) ) )
158647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
158747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char 		pingmsg[4];
158847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool	ok = SuccessfulUpdateTransaction( request, reply );
158947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		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 ) ) );
159047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
159147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		UpdateLeaseTable( request, self, lease );
159247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
159347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( lease > 0 )
159447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
159547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			leaseReply = FormatLeaseReply( self, reply, lease );
159647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
159747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ( !leaseReply )
159847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
159947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				Log("HandleRequest - unable to format lease reply");
160047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
160147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
160247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// %%% Looks like a potential memory leak -- who frees the original reply?
160347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply = leaseReply;
160447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
160547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
160647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// tell the main thread there was an update so it can send LLQs
160747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
160847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( send( self->LLQEventNotifySock, pingmsg, sizeof( pingmsg ), 0 ) != sizeof( pingmsg ) )
160947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
161047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogErr("HandleRequest", "send");
161147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
161247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
161347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
161447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
161547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
161647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( sock )
161747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
161847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformTCPCloseConnection( sock );
161947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
162047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
162147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( reply == &buf )
162247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
162347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		reply = malloc( sizeof( *reply ) );
162447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
162547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( reply )
162647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
162747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply->len = buf.len;
162847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			memcpy(&reply->msg, &buf.msg, buf.len);
162947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
163047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
163147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
163247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogErr("HandleRequest", "malloc");
163347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
163447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
163547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
163647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return reply;
163747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
163847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
163947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
164047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
164147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// LLQ Support Routines
164247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
164347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
164447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Set fields of an LLQ OPT Resource Record
164547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void FormatLLQOpt(AuthRecord *opt, int opcode, const mDNSOpaque64 *const id, mDNSs32 lease)
164647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
164747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(opt, sizeof(*opt));
164847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_SetupResourceRecord(opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
164947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rrclass = NormalMaxDNSMessageData;
165047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
165147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdestimate = sizeof(rdataOPT);
165247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdata->u.opt[0].opt = kDNSOpt_LLQ;
165347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdata->u.opt[0].u.llq.vers  = kLLQ_Vers;
165447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdata->u.opt[0].u.llq.llqOp = opcode;
165547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdata->u.opt[0].u.llq.err   = LLQErr_NoError;
165647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdata->u.opt[0].u.llq.id    = *id;
165747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	opt->resrec.rdata->u.opt[0].u.llq.llqlease = lease;
165847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
165947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
166047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Calculate effective remaining lease of an LLQ
166147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 LLQLease(LLQEntry *e)
166247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
166347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval t;
166447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
166547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gettimeofday(&t, NULL);
166647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e->expire < t.tv_sec) return 0;
166747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else return e->expire - t.tv_sec;
166847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
166947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
167047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DeleteLLQ(DaemonInfo *d, LLQEntry *e)
167147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
167247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int  bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
167347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LLQEntry **ptr = &d->LLQTable[bucket];
167447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AnswerListElem *a = e->AnswerList;
167547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char addr[32];
167647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
167747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
167847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Deleting LLQ table entry for %##s client %s", e->qname.c, addr);
167947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
168047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (a && !(--a->refcount) && d->AnswerTableCount >= LLQ_TABLESIZE)
168147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
168247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// currently, generating initial answers blocks the main thread, so we keep the answer list
168347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// even if the ref count drops to zero.  To prevent unbounded table growth, we free shared answers
168447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// if the ref count drops to zero AND there are more table elements than buckets
168547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// !!!KRS update this when we make the table dynamically growable
168647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
168747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		CacheRecord *cr = a->KnownAnswers, *tmp;
168847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AnswerListElem **tbl = &d->AnswerTable[bucket];
168947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
169047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (cr)
169147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
169247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			tmp = cr;
169347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			cr = cr->next;
169447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			free(tmp);
169547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
169647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
169747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (*tbl && *tbl != a) tbl = &(*tbl)->next;
169847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (*tbl) { *tbl = (*tbl)->next; free(a); d->AnswerTableCount--; }
169947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else Log("Error: DeleteLLQ - AnswerList not found in table");
170047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
170147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
170247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// remove LLQ from table, free memory
170347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while(*ptr && *ptr != e) ptr = &(*ptr)->next;
170447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!*ptr) { Log("Error: DeleteLLQ - LLQ not in table"); return; }
170547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr = (*ptr)->next;
170647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	free(e);
170747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
170847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
170947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int SendLLQ(DaemonInfo *d, PktMsg *pkt, struct sockaddr_in dst, TCPSocket *sock)
171047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
171147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char addr[32];
171247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int err = -1;
171347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
171447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(pkt);
171547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
171647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( sock )
171747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
171847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( SendPacket( sock, pkt ) != 0 )
171947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
172047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogErr("DaemonInfo", "MySend");
172147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
172247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
172347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
172447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
172547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
172647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (sendto(d->llq_udpsd, &pkt->msg, pkt->len, 0, (struct sockaddr *)&dst, sizeof(dst)) != (int)pkt->len)
172747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
172847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogErr("DaemonInfo", "sendto");
172947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("Could not send response to client %s", inet_ntop(AF_INET, &dst.sin_addr, addr, 32));
173047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
173147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
173247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
173347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = 0;
173447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrNToH(pkt);
173547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
173647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
173747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
173847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal CacheRecord *AnswerQuestion(DaemonInfo *d, AnswerListElem *e)
173947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
174047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg q;
174147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
174247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPSocket *sock = NULL;
174347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ansptr;
174447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *end = q.msg.data;
174547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg buf, *reply = NULL;
174647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LargeCacheRecord lcr;
174747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CacheRecord *AnswerList = NULL;
174847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 rcode;
174947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
175047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Querying server for %##s type %d", e->name.c, e->type);
175147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
175247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&q.msg.h, zeroID, uQueryFlags);
175347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
175447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = putQuestion(&q.msg, end, end + AbsoluteMaxDNSMessageData, &e->name, e->type, kDNSClass_IN);
175547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: AnswerQuestion - putQuestion returned NULL"); goto end; }
175647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q.len = (int)(end - (mDNSu8 *)&q.msg);
175747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
175847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(&q);
175947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
176047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!e->UseTCP)
176147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
176247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool trunc;
176347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
176447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (UDPServerTransaction(d, &q, &buf, &trunc) < 0)
176547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("AnswerQuestion %##s - UDPServerTransaction failed.  Trying TCP", e->name.c);
176647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if (trunc)
176747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{ VLog("AnswerQuestion %##s - answer truncated.  Using TCP", e->name.c); e->UseTCP = mDNStrue; }
176847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else reply = &buf;  // success
176947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
177047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
177147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!reply)
177247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
177347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool closed;
177447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
177547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		sock = ConnectToServer(d);
177647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!sock) { Log("AnswerQuestion: ConnectToServer failed"); goto end; }
177747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (SendPacket( sock, &q)) { Log("AnswerQuestion: SendPacket failed"); mDNSPlatformTCPCloseConnection( sock ); goto end; }
177847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		reply = RecvPacket( sock, NULL, &closed );
177947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformTCPCloseConnection( sock );
178047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( reply, end, Log( "AnswerQuestion: RecvPacket returned NULL" ) );
178147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
178247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
178347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrNToH(&q);
178447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (reply) HdrNToH(reply);
178547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
178647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((reply->msg.h.flags.b[0] & kDNSFlag0_QROP_Mask) != (kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery))
178747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ Log("AnswerQuestion: %##s type %d - Invalid response flags from server"); goto end; }
178847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rcode = (mDNSu8)(reply->msg.h.flags.b[1] & kDNSFlag1_RC_Mask);
178947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	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; }
179047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
179147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = (mDNSu8 *)&reply->msg + reply->len;
179247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ansptr = LocateAnswers(&reply->msg, end);
179347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ansptr) { Log("Error: AnswerQuestion - LocateAnswers returned NULL"); goto end; }
179447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
179547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < reply->msg.h.numAnswers; i++)
179647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
179747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ansptr = GetLargeResourceRecord(NULL, &reply->msg, ansptr, end, 0, kDNSRecordTypePacketAns, &lcr);
179847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ansptr) { Log("AnswerQuestions: GetLargeResourceRecord returned NULL"); goto end; }
179947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative)
180047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
180147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (lcr.r.resrec.rrtype != e->type || lcr.r.resrec.rrclass != kDNSClass_IN || !SameDomainName(lcr.r.resrec.name, &e->name))
180247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
180347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				Log("AnswerQuestion: response %##s type #d does not answer question %##s type #d.  Discarding",
180447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					  lcr.r.resrec.name->c, lcr.r.resrec.rrtype, e->name.c, e->type);
180547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
180647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
180747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
180847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				CacheRecord *cr = CopyCacheRecord(&lcr.r, &e->name);
180947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (!cr) { Log("Error: AnswerQuestion - CopyCacheRecord returned NULL"); goto end; }
181047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				cr->next = AnswerList;
181147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				AnswerList = cr;
181247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
181347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
181447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
181547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
181647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end:
181747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (reply && reply != &buf) free(reply);
181847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return AnswerList;
181947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
182047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
182147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Routine forks a thread to set EventList to contain Add/Remove events, and deletes any removes from the KnownAnswer list
182247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void *UpdateAnswerList(void *args)
182347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
182447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CacheRecord *cr, *NewAnswers, **na, **ka; // "new answer", "known answer"
182547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo *d = ((UpdateAnswerListArgs *)args)->d;
182647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AnswerListElem *a = ((UpdateAnswerListArgs *)args)->a;
182747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
182847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	free(args);
182947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	args = NULL;
183047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
183147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// get up to date answers
183247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	NewAnswers = AnswerQuestion(d, a);
183347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
183447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// first pass - mark all answers for deletion
183547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
183647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		(*ka)->resrec.rroriginalttl = (unsigned)-1; // -1 means delete
183747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
183847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// second pass - mark answers pre-existent
183947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
184047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
184147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (na = &NewAnswers; *na; na = &(*na)->next)
184247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
184347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec))
184447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ (*ka)->resrec.rroriginalttl = 0; break; } // 0 means no change
184547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
184647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
184747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
184847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// third pass - add new records to Event list
184947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	na = &NewAnswers;
185047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*na)
185147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
185247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (ka = &a->KnownAnswers; *ka; ka = &(*ka)->next)
185347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (IdenticalResourceRecord(&(*ka)->resrec, &(*na)->resrec)) break;
185447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!*ka)
185547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
185647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// answer is not in list - splice from NewAnswers list, add to Event list
185747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			cr = *na;
185847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			*na = (*na)->next;        // splice from list
185947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			cr->next = a->EventList;  // add spliced record to event list
186047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			a->EventList = cr;
186147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			cr->resrec.rroriginalttl = 1; // 1 means add
186247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
186347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else na = &(*na)->next;
186447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
186547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
186647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// move all the removes from the answer list to the event list
186747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ka = &a->KnownAnswers;
186847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*ka)
186947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
187047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ((*ka)->resrec.rroriginalttl == (unsigned)-1)
187147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
187247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			cr = *ka;
187347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			*ka = (*ka)->next;
187447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			cr->next = a->EventList;
187547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			a->EventList = cr;
187647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
187747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else ka = &(*ka)->next;
187847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
187947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
188047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// lastly, free the remaining records (known answers) in NewAnswers list
188147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (NewAnswers)
188247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
188347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		cr = NewAnswers;
188447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		NewAnswers = NewAnswers->next;
188547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free(cr);
188647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
188747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
188847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return NULL;
188947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
189047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
189147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendEvents(DaemonInfo *d, LLQEntry *e)
189247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
189347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg  response;
189447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CacheRecord *cr;
189547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *end = (mDNSu8 *)&response.msg.data;
189647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSOpaque16 msgID;
189747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char rrbuf[MaxMsg], addrbuf[32];
189847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord opt;
189947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
190047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Should this really be random?  Do we use the msgID on the receiving end?
190147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msgID.NotAnInteger = random();
190247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
190347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&response.msg.h, msgID, ResponseFlags);
190447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = putQuestion(&response.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
190547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: SendEvents - putQuestion returned NULL"); return; }
190647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
190747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// put adds/removes in packet
190847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (cr = e->AnswerList->EventList; cr; cr = cr->next)
190947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
191047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (verbose) GetRRDisplayString_rdb(&cr->resrec, &cr->resrec.rdata->u, rrbuf);
191147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		VLog("%s (%s): %s", addrbuf, (mDNSs32)cr->resrec.rroriginalttl < 0 ? "Remove": "Add", rrbuf);
191247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAnswers, &cr->resrec, cr->resrec.rroriginalttl);
191347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo returned NULL"); return; }
191447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
191547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
191647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FormatLLQOpt(&opt, kLLQOp_Event, &e->id, LLQLease(e));
191747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = PutResourceRecordTTLJumbo(&response.msg, end, &response.msg.h.numAdditionals, &opt.resrec, 0);
191847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: SendEvents - PutResourceRecordTTLJumbo"); return; }
191947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
192047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	response.len = (int)(end - (mDNSu8 *)&response.msg);
192147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SendLLQ(d, &response, e->cli, NULL ) < 0) LogMsg("Error: SendEvents - SendLLQ");
192247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
192347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
192447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void PrintLLQAnswers(DaemonInfo *d)
192547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
192647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
192747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char rrbuf[MaxMsg];
192847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
192947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	Log("Printing LLQ Answer Table contents");
193047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
193147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < LLQ_TABLESIZE; i++)
193247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
193347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AnswerListElem *a = d->AnswerTable[i];
193447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while(a)
193547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
193647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			int ancount = 0;
193747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			const CacheRecord *rr = a->KnownAnswers;
193847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			while (rr) { ancount++; rr = rr->next; }
193947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("%p : Question %##s;  type %d;  referenced by %d LLQs; %d answers:", a, a->name.c, a->type, a->refcount, ancount);
194047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			for (rr = a->KnownAnswers; rr; rr = rr->next) Log("\t%s", GetRRDisplayString_rdb(&rr->resrec, &rr->resrec.rdata->u, rrbuf));
194147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			a = a->next;
194247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
194347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
194447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
194547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
194647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void PrintLLQTable(DaemonInfo *d)
194747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
194847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LLQEntry *e;
194947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char addr[32];
195047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
195147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
195247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	Log("Printing LLQ table contents");
195347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
195447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < LLQ_TABLESIZE; i++)
195547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
195647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		e = d->LLQTable[i];
195747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while(e)
195847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
195947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			char *state;
196047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
196147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			switch (e->state)
196247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
196347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case RequestReceived: state = "RequestReceived"; break;
196447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case ChallengeSent:   state = "ChallengeSent";   break;
196547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case Established:     state = "Established";     break;
196647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				default:              state = "unknown";
196747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
196847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
196947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
197047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("LLQ from %s in state %s; %##s; type %d; orig lease %d; remaining lease %d; AnswerList %p)",
197147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				addr, state, e->qname.c, e->qtype, e->lease, LLQLease(e), e->AnswerList);
197247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			e = e->next;
197347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
197447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
197547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
197647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
197747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Send events to clients as a result of a change in the zone
197847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void GenLLQEvents(DaemonInfo *d)
197947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
198047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LLQEntry **e;
198147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
198247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval t;
198347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	UpdateAnswerListArgs *args;
198447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
198547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Generating LLQ Events");
198647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
198747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gettimeofday(&t, NULL);
198847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
198947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// get all answers up to date
199047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < LLQ_TABLESIZE; i++)
199147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
199247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AnswerListElem *a = d->AnswerTable[i];
199347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while(a)
199447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
199547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			args = malloc(sizeof(*args));
199647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!args) { LogErr("GenLLQEvents", "malloc"); return; }
199747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			args->d = d;
199847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			args->a = a;
199947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (pthread_create(&a->tid, NULL, UpdateAnswerList, args) < 0) { LogErr("GenLLQEvents", "pthread_create"); return; }
200047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			usleep(1);
200147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			a = a->next;
200247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
200347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
200447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
200547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < LLQ_TABLESIZE; i++)
200647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
200747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AnswerListElem *a = d->AnswerTable[i];
200847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while(a)
200947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
201047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (pthread_join(a->tid, NULL)) LogErr("GenLLQEvents", "pthread_join");
201147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			a = a->next;
201247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
201347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
201447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
201547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    // for each established LLQ, send events
201647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < LLQ_TABLESIZE; i++)
201747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
201847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		e = &d->LLQTable[i];
201947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while(*e)
202047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
202147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ((*e)->expire < t.tv_sec) DeleteLLQ(d, *e);
202247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
202347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
202447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if ((*e)->state == Established && (*e)->AnswerList->EventList) SendEvents(d, *e);
202547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				e = &(*e)->next;
202647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
202747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
202847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
202947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
203047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// now that all LLQs are updated, we move Add events from the Event list to the Known Answer list, and free Removes
203147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < LLQ_TABLESIZE; i++)
203247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
203347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AnswerListElem *a = d->AnswerTable[i];
203447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while(a)
203547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
203647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (a->EventList)
203747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
203847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				CacheRecord *cr = a->EventList, *tmp;
203947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				while (cr)
204047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
204147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					tmp = cr;
204247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					cr = cr->next;
204347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if ((signed)tmp->resrec.rroriginalttl < 0) free(tmp);
204447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					else
204547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						{
204647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						tmp->next = a->KnownAnswers;
204747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						a->KnownAnswers = tmp;
204847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						tmp->resrec.rroriginalttl = 0;
204947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						}
205047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
205147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				a->EventList = NULL;
205247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
205347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			a = a->next;
205447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
205547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
205647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
205747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
205847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SetAnswerList(DaemonInfo *d, LLQEntry *e)
205947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
206047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int bucket = DomainNameHashValue(&e->qname) % LLQ_TABLESIZE;
206147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AnswerListElem *a = d->AnswerTable[bucket];
206247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (a && (a->type != e->qtype ||!SameDomainName(&a->name, &e->qname))) a = a->next;
206347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!a)
206447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
206547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a = malloc(sizeof(*a));
206647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!a) { LogErr("SetAnswerList", "malloc"); return; }
206747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AssignDomainName(&a->name, &e->qname);
206847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a->type = e->qtype;
206947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a->refcount = 0;
207047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a->EventList = NULL;
207147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a->UseTCP = mDNSfalse;
207247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a->next = d->AnswerTable[bucket];
207347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		d->AnswerTable[bucket] = a;
207447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		d->AnswerTableCount++;
207547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a->KnownAnswers = AnswerQuestion(d, a);
207647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
207747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
207847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->AnswerList = a;
207947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	a->refcount ++;
208047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
208147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
208247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt // Allocate LLQ entry, insert into table
208347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal LLQEntry *NewLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, mDNSu32 lease )
208447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
208547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char addr[32];
208647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval t;
208747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
208847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt   	LLQEntry *e;
208947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
209047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e = malloc(sizeof(*e));
209147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!e) { LogErr("NewLLQ", "malloc"); return NULL; }
209247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
209347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	inet_ntop(AF_INET, &cli.sin_addr, addr, 32);
209447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Allocating LLQ entry for client %s question %##s type %d", addr, qname->c, qtype);
209547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
209647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// initialize structure
209747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->cli = cli;
209847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AssignDomainName(&e->qname, qname);
209947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->qtype = qtype;
210047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->id    = zeroOpaque64;
210147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->state = RequestReceived;
210247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->AnswerList = NULL;
210347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
210447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (lease < LLQ_MIN_LEASE) lease = LLQ_MIN_LEASE;
210547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (lease > LLQ_MAX_LEASE) lease = LLQ_MAX_LEASE;
210647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
210747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gettimeofday(&t, NULL);
210847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->expire = t.tv_sec + (int)lease;
210947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->lease = lease;
211047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
211147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// add to table
211247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->next = d->LLQTable[bucket];
211347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->LLQTable[bucket] = e;
211447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
211547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return e;
211647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
211747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
211847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Handle a refresh request from client
211947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void LLQRefresh(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
212047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
212147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord opt;
212247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg ack;
212347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
212447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char addr[32];
212547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
212647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
212747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("%s LLQ for %##s from %s", llq->llqlease ? "Refreshing" : "Deleting", e->qname.c, addr);
212847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
212947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (llq->llqlease)
213047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
213147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		struct timeval t;
213247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (llq->llqlease < LLQ_MIN_LEASE) llq->llqlease = LLQ_MIN_LEASE;
213347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if (llq->llqlease > LLQ_MAX_LEASE) llq->llqlease = LLQ_MIN_LEASE;
213447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		gettimeofday(&t, NULL);
213547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		e->expire = t.tv_sec + llq->llqlease;
213647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
213747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
213847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ack.src.sin_addr.s_addr = 0; // unused
213947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
214047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
214147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: putQuestion"); return; }
214247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
214347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FormatLLQOpt(&opt, kLLQOp_Refresh, &e->id, llq->llqlease ? LLQLease(e) : 0);
214447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
214547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
214647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
214747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ack.len = (int)(end - (mDNSu8 *)&ack.msg);
214847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQRefresh");
214947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
215047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (llq->llqlease) e->state = Established;
215147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else DeleteLLQ(d, e);
215247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
215347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
215447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Complete handshake with Ack an initial answers
215547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void LLQCompleteHandshake(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock)
215647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
215747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char addr[32];
215847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CacheRecord *ptr;
215947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord opt;
216047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg ack;
216147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *end = (mDNSu8 *)&ack.msg.data;
216247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char rrbuf[MaxMsg], addrbuf[32];
216347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
216447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	inet_ntop(AF_INET, &e->cli.sin_addr, addr, 32);
216547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
216647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!mDNSSameOpaque64(&llq->id, &e->id) ||
216747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		llq->vers  != kLLQ_Vers             ||
216847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		llq->llqOp != kLLQOp_Setup          ||
216947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		llq->err   != LLQErr_NoError        ||
217047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		llq->llqlease > e->lease + LLQ_LEASE_FUDGE ||
217147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		llq->llqlease < e->lease - LLQ_LEASE_FUDGE)
217247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
217347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Log("Incorrect challenge response from %s", addr);
217447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return;
217547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
217647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
217747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e->state == Established) VLog("Retransmitting LLQ ack + answers for %##s", e->qname.c);
217847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else                         VLog("Delivering LLQ ack + answers for %##s", e->qname.c);
217947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
218047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// format ack + answers
218147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ack.src.sin_addr.s_addr = 0; // unused
218247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&ack.msg.h, msgID, ResponseFlags);
218347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = putQuestion(&ack.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
218447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: putQuestion"); return; }
218547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
218647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e->state != Established) { SetAnswerList(d, e); e->state = Established; }
218747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
218847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (verbose) inet_ntop(AF_INET, &e->cli.sin_addr, addrbuf, 32);
218947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (ptr = e->AnswerList->KnownAnswers; ptr; ptr = ptr->next)
219047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
219147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (verbose) GetRRDisplayString_rdb(&ptr->resrec, &ptr->resrec.rdata->u, rrbuf);
219247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		VLog("%s Intitial Answer - %s", addr, rrbuf);
219347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAnswers, &ptr->resrec, 1);
219447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
219547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
219647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
219747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
219847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = PutResourceRecordTTLJumbo(&ack.msg, end, &ack.msg.h.numAdditionals, &opt.resrec, 0);
219947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
220047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
220147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ack.len = (int)(end - (mDNSu8 *)&ack.msg);
220247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SendLLQ(d, &ack, e->cli, sock)) Log("Error: LLQCompleteHandshake");
220347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
220447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
220547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void LLQSetupChallenge(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID)
220647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
220747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval t;
220847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg challenge;
220947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *end = challenge.msg.data;
221047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord opt;
221147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
221247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e->state == ChallengeSent) VLog("Retransmitting LLQ setup challenge for %##s", e->qname.c);
221347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else                           VLog("Sending LLQ setup challenge for %##s", e->qname.c);
221447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
221547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!mDNSOpaque64IsZero(&llq->id)) { Log("Error: LLQSetupChallenge - nonzero ID"); return; } // server bug
221647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (llq->llqOp != kLLQOp_Setup) { Log("LLQSetupChallenge - incorrrect operation from client"); return; } // client error
221747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
221847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (mDNSOpaque64IsZero(&e->id)) // don't regenerate random ID for retransmissions
221947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
222047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// construct ID <time><random>
222147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		gettimeofday(&t, NULL);
222247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		e->id.l[0] = t.tv_sec;
222347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		e->id.l[1] = random();
222447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
222547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
222647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// format response (query + LLQ opt rr)
222747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	challenge.src.sin_addr.s_addr = 0; // unused
222847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&challenge.msg.h, msgID, ResponseFlags);
222947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = putQuestion(&challenge.msg, end, end + AbsoluteMaxDNSMessageData, &e->qname, e->qtype, kDNSClass_IN);
223047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: putQuestion"); return; }
223147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FormatLLQOpt(&opt, kLLQOp_Setup, &e->id, LLQLease(e));
223247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = PutResourceRecordTTLJumbo(&challenge.msg, end, &challenge.msg.h.numAdditionals, &opt.resrec, 0);
223347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { Log("Error: PutResourceRecordTTLJumbo"); return; }
223447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	challenge.len = (int)(end - (mDNSu8 *)&challenge.msg);
223547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SendLLQ(d, &challenge, e->cli, NULL)) { Log("Error: LLQSetupChallenge"); return; }
223647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	e->state = ChallengeSent;
223747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
223847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
223947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Take action on an LLQ message from client.  Entry must be initialized and in table
224047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void UpdateLLQ(DaemonInfo *d, LLQEntry *e, LLQOptData *llq, mDNSOpaque16 msgID, TCPSocket *sock )
224147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
224247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch(e->state)
224347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
224447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case RequestReceived:
224547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ( sock )
224647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
224747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				struct timeval t;
224847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				gettimeofday(&t, NULL);
224947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				e->id.l[0] = t.tv_sec;	// construct ID <time><random>
225047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				e->id.l[1] = random();
225147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				llq->id = e->id;
225247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				LLQCompleteHandshake( d, e, llq, msgID, sock );
225347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
225447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// Set the state to established because we've just set the LLQ up using TCP
225547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				e->state = Established;
225647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
225747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
225847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
225947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				LLQSetupChallenge(d, e, llq, msgID);
226047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
226147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return;
226247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case ChallengeSent:
226347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (mDNSOpaque64IsZero(&llq->id)) LLQSetupChallenge(d, e, llq, msgID); // challenge sent and lost
226447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else LLQCompleteHandshake(d, e, llq, msgID, sock );
226547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return;
226647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case Established:
226747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (mDNSOpaque64IsZero(&llq->id))
226847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
226947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// client started over.  reset state.
227047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				LLQEntry *newe = NewLLQ(d, e->cli, &e->qname, e->qtype, llq->llqlease );
227147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (!newe) return;
227247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				DeleteLLQ(d, e);
227347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				LLQSetupChallenge(d, newe, llq, msgID);
227447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				return;
227547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
227647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else if (llq->llqOp == kLLQOp_Setup)
227747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ LLQCompleteHandshake(d, e, llq, msgID, sock); return; } // Ack lost
227847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else if (llq->llqOp == kLLQOp_Refresh)
227947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ LLQRefresh(d, e, llq, msgID, sock); return; }
228047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else { Log("Unhandled message for established LLQ"); return; }
228147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
228247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
228347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
228447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal LLQEntry *LookupLLQ(DaemonInfo *d, struct sockaddr_in cli, domainname *qname, mDNSu16 qtype, const mDNSOpaque64 *const id)
228547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
228647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int bucket = bucket = DomainNameHashValue(qname) % LLQ_TABLESIZE;
228747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LLQEntry *ptr = d->LLQTable[bucket];
228847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
228947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while(ptr)
229047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
229147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (((ptr->state == ChallengeSent && mDNSOpaque64IsZero(id) && (cli.sin_port == ptr->cli.sin_port)) || // zero-id due to packet loss OK in state ChallengeSent
229247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			 mDNSSameOpaque64(id, &ptr->id)) &&                        // id match
229347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			(cli.sin_addr.s_addr == ptr->cli.sin_addr.s_addr) && (qtype == ptr->qtype) && SameDomainName(&ptr->qname, qname)) // same source, type, qname
229447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return ptr;
229547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = ptr->next;
229647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
229747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return NULL;
229847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
229947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
230047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int
230147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltRecvNotify
230247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
230347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo	*	d,
230447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	pkt
230547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
230647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
230747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int	res;
230847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int	err = 0;
230947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
231047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->msg.h.flags.b[0] |= kDNSFlag0_QR_Response;
231147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
231247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	res = sendto( d->udpsd, &pkt->msg, pkt->len, 0, ( struct sockaddr* ) &pkt->src, sizeof( pkt->src ) );
231347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( res == ( int ) pkt->len, exit, err = mStatus_UnknownErr; LogErr( "RecvNotify", "sendto" ) );
231447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
231547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
231647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
231747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
231847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
231947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
232047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
232147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
232247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
232347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSQuestion q;
232447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LargeCacheRecord opt;
232547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i, err = -1;
232647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char addr[32];
232747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *qptr = pkt->msg.data;
232847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
232947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *aptr;
233047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LLQOptData *llq = NULL;
233147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LLQEntry *e = NULL;
233247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
233347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrNToH(pkt);
233447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	aptr = LocateAdditionals(&pkt->msg, end);	// Can't do this until after HdrNToH(pkt);
233547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	inet_ntop(AF_INET, &pkt->src.sin_addr, addr, 32);
233647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
233747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	VLog("Received LLQ msg from %s", addr);
233847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// sanity-check packet
233947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!pkt->msg.h.numQuestions || !pkt->msg.h.numAdditionals)
234047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
234147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		Log("Malformatted LLQ from %s with %d questions, %d additionals", addr, pkt->msg.h.numQuestions, pkt->msg.h.numAdditionals);
234247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		goto end;
234347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
234447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
234547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Locate the OPT record.
234647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
234747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
234847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// but not necessarily the *last* entry in the Additional Section.
234947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < pkt->msg.h.numAdditionals; i++)
235047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
235147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		aptr = GetLargeResourceRecord(NULL, &pkt->msg, aptr, end, 0, kDNSRecordTypePacketAdd, &opt);
235247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %d", addr, i); goto end; }
235347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
235447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
235547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
235647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// validate OPT
235747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (opt.r.resrec.rrtype != kDNSType_OPT) { Log("Malformatted LLQ from %s: last Additional not an OPT RR", addr); goto end; }
235847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	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); }
235947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
236047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// dispatch each question
236147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < pkt->msg.h.numQuestions; i++)
236247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
236347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		qptr = getQuestion(&pkt->msg, qptr, end, 0, &q);
236447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %d", addr, i); goto end; }
236547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		llq = (LLQOptData *)&opt.r.resrec.rdata->u.opt[0].u.llq + i; // point into OptData at index i
236647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (llq->vers != kLLQ_Vers) { Log("LLQ from %s contains bad version %d (expected %d)", addr, llq->vers, kLLQ_Vers); goto end; }
236747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
236847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		e = LookupLLQ(d, pkt->src, &q.qname, q.qtype, &llq->id);
236947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!e)
237047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
237147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// no entry - if zero ID, create new
237247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			e = NewLLQ(d, pkt->src, &q.qname, q.qtype, llq->llqlease );
237347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!e) goto end;
237447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
237547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		UpdateLLQ(d, e, llq, pkt->msg.h.id, sock);
237647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
237747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = 0;
237847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
237947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end:
238047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(pkt);
238147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
238247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
238347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
238447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
238547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool IsAuthorized( DaemonInfo * d, PktMsg * pkt, DomainAuthInfo ** key, mDNSu16 * rcode, mDNSu16 * tcode )
238647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
238747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 	*	lastPtr = NULL;
238847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 	*	ptr = NULL;
238947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DomainAuthInfo	*	keys;
239047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 			*	end	= ( mDNSu8* ) &pkt->msg + pkt->len;
239147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LargeCacheRecord	lcr;
239247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			hasTSIG = mDNSfalse;
239347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			strip = mDNSfalse;
239447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			ok = mDNSfalse;
239547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int					i;
239647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
239747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Unused parameters
239847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
239947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	( void ) d;
240047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
240147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrNToH(pkt);
240247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
240347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*key = NULL;
240447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
240547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( pkt->msg.h.numAdditionals )
240647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
240747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = LocateAdditionals(&pkt->msg, end);
240847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr)
240947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
241047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			for (i = 0; i < pkt->msg.h.numAdditionals; i++)
241147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
241247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				lastPtr = ptr;
241347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				ptr = GetLargeResourceRecord(NULL, &pkt->msg, ptr, end, 0, kDNSRecordTypePacketAdd, &lcr);
241447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (!ptr)
241547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
241647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					Log("Unable to read additional record");
241747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					lastPtr = NULL;
241847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					break;
241947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
242047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
242147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
242247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				hasTSIG = ( ptr && lcr.r.resrec.RecordType != kDNSRecordTypePacketNegative && lcr.r.resrec.rrtype == kDNSType_TSIG );
242347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
242447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
242547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
242647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogMsg( "IsAuthorized: unable to find Additional section" );
242747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
242847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
242947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
243047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If we don't know what zone this is, then it's authorized.
243147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
243247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( !pkt->zone )
243347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
243447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ok = mDNStrue;
243547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		strip = mDNSfalse;
243647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		goto exit;
243747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
243847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
243947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( IsQuery( pkt ) )
244047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
244147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		keys = pkt->zone->queryKeys;
244247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		strip = mDNStrue;
244347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
244447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if ( IsUpdate( pkt ) )
244547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
244647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		keys = pkt->zone->updateKeys;
244747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		strip = mDNSfalse;
244847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
244947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
245047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
245147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ok = mDNStrue;
245247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		strip = mDNSfalse;
245347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		goto exit;
245447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
245547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
245647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( pkt->isZonePublic )
245747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
245847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ok = mDNStrue;
245947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		goto exit;
246047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
246147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
246247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If there are no keys, then we're authorized
246347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
246447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( ( hasTSIG && !keys ) || ( !hasTSIG && keys ) )
246547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
246647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		Log( "Invalid TSIG spec %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
246747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*rcode = kDNSFlag1_RC_NotAuth;
246847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*tcode = TSIG_ErrBadKey;
246947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		strip = mDNStrue;
247047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ok = mDNSfalse;
247147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		goto exit;
247247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
247347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
247447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Find the right key
247547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
247647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for ( *key = keys; *key; *key = (*key)->next )
247747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
247847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( SameDomainName( lcr.r.resrec.name, &(*key)->keyname ) )
247947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
248047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			break;
248147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
248247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
248347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
248447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( !(*key) )
248547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
248647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		Log( "Invalid TSIG name %##s for zone %##s", lcr.r.resrec.name->c, pkt->zone->name.c );
248747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*rcode = kDNSFlag1_RC_NotAuth;
248847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*tcode = TSIG_ErrBadKey;
248947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		strip = mDNStrue;
249047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ok = mDNSfalse;
249147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		goto exit;
249247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
249347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
249447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Okay, we have the correct key and a TSIG record.  DNSDigest_VerifyMessage does the heavy
249547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// lifting of message verification
249647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
249747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->msg.h.numAdditionals--;
249847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
249947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN( pkt );
250047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
250147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ok = DNSDigest_VerifyMessage( &pkt->msg, ( mDNSu8* ) lastPtr, &lcr, (*key), rcode, tcode );
250247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
250347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrNToH( pkt );
250447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
250547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt->msg.h.numAdditionals++;
250647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
250747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
250847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
250947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( hasTSIG && strip )
251047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
251147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Strip the TSIG from the message
251247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
251347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt->msg.h.numAdditionals--;
251447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pkt->len = lastPtr - ( mDNSu8* ) ( &pkt->msg );
251547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
251647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
251747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HdrHToN(pkt);
251847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
251947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ok;
252047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
252147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
252247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// request handler wrappers for TCP and UDP requests
252347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (read message off socket, fork thread that invokes main processing routine and handles cleanup)
252447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
252547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void*
252647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltUDPMessageHandler
252747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
252847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	void * vptr
252947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
253047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
253147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	UDPContext	*	context	= ( UDPContext* ) vptr;
253247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	reply	= NULL;
253347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				res;
253447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err;
253547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
253647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// !!!KRS strictly speaking, we shouldn't use TCP for a UDP request because the server
253747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// may give us a long answer that would require truncation for UDP delivery to client
253847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
253947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply = HandleRequest( context->d, &context->pkt );
254047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( reply, exit, err = mStatus_UnknownErr );
254147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
254247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	res = sendto( context->sd, &reply->msg, reply->len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
254347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( res == ( int ) reply->len, exit, LogErr( "UDPMessageHandler", "sendto" ) );
254447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
254547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
254647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
254747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( reply )
254847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
254947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free( reply );
255047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
255147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
255247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	free( context );
255347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
255447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pthread_exit( NULL );
255547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
255647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return NULL;
255747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
255847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
255947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
256047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int
256147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltRecvUDPMessage
256247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
256347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo	*	self,
256447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				sd
256547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
256647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
256747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	UDPContext		*	context = NULL;
256847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pthread_t			tid;
256947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16				rcode;
257047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16				tcode;
257147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DomainAuthInfo	*	key;
257247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned int		clisize = sizeof( context->cliaddr );
257347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int					res;
257447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus				err = mStatus_NoError;
257547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
257647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context = malloc( sizeof( UDPContext ) );
257747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( context, exit, err = mStatus_NoMemoryErr ; LogErr( "RecvUDPMessage", "malloc" ) );
257847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
257947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero( context, sizeof( *context ) );
258047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context->d = self;
258147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context->sd = sd;
258247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
258347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	res = recvfrom(sd, &context->pkt.msg, sizeof(context->pkt.msg), 0, (struct sockaddr *)&context->cliaddr, &clisize);
258447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
258547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( res >= 0, exit, err = mStatus_UnknownErr ; LogErr( "RecvUDPMessage", "recvfrom" ) );
258647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context->pkt.len = res;
258747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( clisize == sizeof( context->cliaddr ), exit, err = mStatus_UnknownErr ; Log( "Client address of unknown size %d", clisize ) );
258847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context->pkt.src = context->cliaddr;
258947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
259047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Set the zone in the packet
259147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
259247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SetZone( context->d, &context->pkt );
259347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
259447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Notify messages handled by main thread
259547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
259647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( IsNotify( &context->pkt ) )
259747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
259847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int e = RecvNotify( self, &context->pkt );
259947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free(context);
260047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return e;
260147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
260247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
260347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
260447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( IsLLQRequest( &context->pkt ) )
260547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
260647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// LLQ messages handled by main thread
260747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			int e = RecvLLQ( self, &context->pkt, NULL );
260847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			free(context);
260947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return e;
261047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
261147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
261247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( IsLLQAck(&context->pkt ) )
261347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
261447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// !!!KRS need to do acks + retrans
261547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
261647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			free(context);
261747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return 0;
261847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
261947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
262047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = pthread_create( &tid, NULL, UDPMessageHandler, context );
262147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action( !err, exit, LogErr( "RecvUDPMessage", "pthread_create" ) );
262247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
262347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		pthread_detach(tid);
262447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
262547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
262647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
262747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		PktMsg reply;
262847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int    e;
262947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
263047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
263147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
263247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		reply.msg.h.flags.b[0]  =  kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
263347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		reply.msg.h.flags.b[1]  =  kDNSFlag1_RA | kDNSFlag1_RC_NXDomain;
263447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
263547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		e = sendto( sd, &reply.msg, reply.len, 0, ( struct sockaddr* ) &context->pkt.src, sizeof( context->pkt.src ) );
263647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		require_action_quiet( e == ( int ) reply.len, exit, LogErr( "RecvUDPMessage", "sendto" ) );
263747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
263847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		err = mStatus_NoAuth;
263947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
264047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
264147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
264247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
264347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( err && context )
264447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
264547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free( context );
264647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
264747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
264847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
264947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
265047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
265147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
265247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void
265347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltFreeTCPContext
265447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
265547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPContext * context
265647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
265747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
265847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( context )
265947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
266047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( context->sock )
266147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
266247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSPlatformTCPCloseConnection( context->sock );
266347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
266447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
266547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free( context );
266647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
266747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
266847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
266947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
267047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void*
267147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltTCPMessageHandler
267247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
267347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	void * vptr
267447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
267547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
267647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPContext	*	context	= ( TCPContext* ) vptr;
267747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg		*	reply = NULL;
267847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				res;
267947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char 			buf[32];
268047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
268147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    //!!!KRS if this read blocks indefinitely, we can run out of threads
268247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// read the request
268347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
268447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	reply = HandleRequest( context->d, &context->pkt );
268547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action_quiet( reply, exit, LogMsg( "TCPMessageHandler: No reply for client %s", inet_ntop( AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
268647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
268747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// deliver reply to client
268847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
268947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	res = SendPacket( context->sock, reply );
269047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( res >= 0, exit, LogMsg("TCPMessageHandler: Unable to send reply to client %s", inet_ntop(AF_INET, &context->cliaddr.sin_addr, buf, 32 ) ) );
269147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
269247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
269347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
269447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FreeTCPContext( context );
269547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
269647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( reply )
269747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
269847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free( reply );
269947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
270047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
270147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pthread_exit(NULL);
270247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
270347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
270447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
270547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void
270647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltRecvTCPMessage
270747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
270847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	void * param
270947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
271047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
271147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPContext		*	context = ( TCPContext* ) param;
271247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16				rcode;
271347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16				tcode;
271447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pthread_t			tid;
271547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DomainAuthInfo	*	key;
271647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	PktMsg			*	pkt;
271747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			closed;
271847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool			freeContext = mDNStrue;
271947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus				err = mStatus_NoError;
272047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
272147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Receive a packet.  It's okay if we don't actually read a packet, as long as the closed flag is
272247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// set to false.  This is because SSL/TLS layer might gobble up the first packet that we read off the
272347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// wire.  We'll let it do that, and wait for the next packet which will be ours.
272447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
272547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pkt = RecvPacket( context->sock, &context->pkt, &closed );
272647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (pkt) HdrNToH(pkt);
272747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( pkt || !closed, exit, err = mStatus_UnknownErr; LogMsg( "client disconnected" ) );
272847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
272947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( pkt )
273047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
273147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Always do this, regardless of what kind of packet it is.  If we wanted LLQ events to be sent over TCP,
273247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// we would change this line of code.  As it is now, we will reply to an LLQ via TCP, but then events
273347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// are sent over UDP
273447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
273547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		RemoveSourceFromEventLoop( context->d, context->sock );
273647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
273747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Set's the DNS Zone that is associated with this message
273847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
273947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		SetZone( context->d, &context->pkt );
274047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
274147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// IsAuthorized will make sure the message is authorized for the designated zone.
274247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// After verifying the signature, it will strip the TSIG from the message
274347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
274447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ( IsAuthorized( context->d, &context->pkt, &key, &rcode, &tcode ) )
274547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
274647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ( IsLLQRequest( &context->pkt ) )
274747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
274847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// LLQ messages handled by main thread
274947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				RecvLLQ( context->d, &context->pkt, context->sock);
275047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
275147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
275247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
275347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				err = pthread_create( &tid, NULL, TCPMessageHandler, context );
275447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
275547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if ( err )
275647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
275747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					LogErr( "RecvTCPMessage", "pthread_create" );
275847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					err = mStatus_NoError;
275947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					goto exit;
276047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
276147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
276247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// Let the thread free the context
276347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
276447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				freeContext = mDNSfalse;
276547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
276647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				pthread_detach(tid);
276747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
276847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
276947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
277047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
277147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			PktMsg reply;
277247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
277347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogMsg( "Client %s Not authorized for zone %##s", inet_ntoa( context->pkt.src.sin_addr ), pkt->zone->name.c );
277447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
277547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			memcpy( &reply, &context->pkt, sizeof( PktMsg ) );
277647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
277747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply.msg.h.flags.b[0]  =  kDNSFlag0_QR_Response | kDNSFlag0_AA | kDNSFlag0_RD;
277847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			reply.msg.h.flags.b[1]  =  kDNSFlag1_RA | kDNSFlag1_RC_Refused;
277947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
278047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			SendPacket( context->sock, &reply );
278147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
278247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
278347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
278447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
278547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		freeContext = mDNSfalse;
278647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
278747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
278847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
278947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
279047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( err )
279147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
279247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		RemoveSourceFromEventLoop( context->d, context->sock );
279347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
279447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
279547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( freeContext )
279647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
279747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FreeTCPContext( context );
279847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
279947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
280047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
280147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
280247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int
280347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltAcceptTCPConnection
280447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
280547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo		*	self,
280647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int					sd,
280747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPSocketFlags	flags
280847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
280947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
281047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TCPContext *	context = NULL;
281147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned int	clilen = sizeof( context->cliaddr);
281247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int				newSock;
281347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err = mStatus_NoError;
281447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
281547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context = ( TCPContext* ) malloc( sizeof( TCPContext ) );
281647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( context, exit, err = mStatus_NoMemoryErr; LogErr( "AcceptTCPConnection", "malloc" ) );
281747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero( context, sizeof( sizeof( TCPContext ) ) );
281847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context->d		 = self;
281947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	newSock = accept( sd, ( struct sockaddr* ) &context->cliaddr, &clilen );
282047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( newSock != -1, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "accept" ) );
282147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
282247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	context->sock = mDNSPlatformTCPAccept( flags, newSock );
282347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( context->sock, exit, err = mStatus_UnknownErr; LogErr( "AcceptTCPConnection", "mDNSPlatformTCPAccept" ) );
282447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
282547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	err = AddSourceToEventLoop( self, context->sock, RecvTCPMessage, context );
282647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( !err, exit, LogErr( "AcceptTCPConnection", "AddSourceToEventLoop" ) );
282747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
282847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
282947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
283047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( err && context )
283147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
283247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		free( context );
283347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		context = NULL;
283447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
283547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
283647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
283747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
283847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
283947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
284047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// main event loop
284147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// listen for incoming requests, periodically check table for expired records, respond to signals
284247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int Run(DaemonInfo *d)
284347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
284447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int staticMaxFD, nfds;
284547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fd_set rset;
284647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval timenow, timeout, EventTS, tablecheck = { 0, 0 };
284747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool EventsPending = mDNSfalse;
284847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
284947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt   	VLog("Listening for requests...");
285047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
285147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	staticMaxFD = 0;
285247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
285347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( d->tcpsd + 1  > staticMaxFD )				staticMaxFD = d->tcpsd + 1;
285447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( d->udpsd + 1  > staticMaxFD )				staticMaxFD = d->udpsd + 1;
285547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( d->tlssd + 1  > staticMaxFD )				staticMaxFD = d->tlssd + 1;
285647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( d->llq_tcpsd + 1 > staticMaxFD )			staticMaxFD = d->llq_tcpsd + 1;
285747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( d->llq_udpsd + 1 > staticMaxFD )			staticMaxFD = d->llq_udpsd + 1;
285847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ( d->LLQEventListenSock + 1 > staticMaxFD )	staticMaxFD = d->LLQEventListenSock + 1;
285947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
286047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while(1)
286147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
286247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		EventSource	* source;
286347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int           maxFD;
286447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
286547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// set timeout
286647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		timeout.tv_sec = timeout.tv_usec = 0;
286747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (gettimeofday(&timenow, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
286847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
286947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (EventsPending)
287047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
287147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (timenow.tv_sec - EventTS.tv_sec >= 5)           // if we've been waiting 5 seconds for a "quiet" period to send
287247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ GenLLQEvents(d); EventsPending = mDNSfalse; } // events, we go ahead and do it now
287347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else timeout.tv_usec = 500000;                      // else do events after 1/2 second with no new events or LLQs
287447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
287547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!EventsPending)
287647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
287747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// if no pending events, timeout when we need to check for expired records
287847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (tablecheck.tv_sec && timenow.tv_sec - tablecheck.tv_sec >= 0)
287947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; } // table check overdue
288047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!tablecheck.tv_sec) tablecheck.tv_sec = timenow.tv_sec + EXPIRATION_INTERVAL;
288147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			timeout.tv_sec = tablecheck.tv_sec - timenow.tv_sec;
288247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
288347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
288447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_ZERO(&rset);
288547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET( d->tcpsd, &rset );
288647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET( d->udpsd, &rset );
288747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET( d->tlssd, &rset );
288847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET( d->llq_tcpsd, &rset );
288947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET( d->llq_udpsd, &rset );
289047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		FD_SET( d->LLQEventListenSock, &rset );
289147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
289247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		maxFD = staticMaxFD;
289347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
289447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
289547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
289647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			FD_SET( source->fd, &rset );
289747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
289847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if ( source->fd > maxFD )
289947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
290047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				maxFD = source->fd;
290147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
290247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
290347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
290447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		nfds = select( maxFD + 1, &rset, NULL, NULL, &timeout);
290547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (nfds < 0)
290647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
290747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (errno == EINTR)
290847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
290947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (terminate)
291047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
291147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					// close sockets to prevent clients from making new requests during shutdown
291247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					close( d->tcpsd );
291347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					close( d->udpsd );
291447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					close( d->tlssd );
291547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					close( d->llq_tcpsd );
291647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					close( d->llq_udpsd );
291747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					d->tcpsd = d->udpsd = d->tlssd = d->llq_tcpsd = d->llq_udpsd = -1;
291847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					DeleteRecords(d, mDNStrue);
291947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					return 0;
292047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
292147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else if (dumptable)
292247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
292347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					Log( "Received SIGINFO" );
292447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
292547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					PrintLeaseTable(d);
292647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					PrintLLQTable(d);
292747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					PrintLLQAnswers(d);
292847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					dumptable = 0;
292947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
293047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else if (hangup)
293147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
293247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					int err;
293347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
293447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					Log( "Received SIGHUP" );
293547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
293647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					err = ParseConfig( d, cfgfile );
293747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
293847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if ( err )
293947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						{
294047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						LogErr( "Run", "ParseConfig" );
294147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						return -1;
294247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						}
294347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
294447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					hangup = 0;
294547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
294647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else
294747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
294847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					Log("Received unhandled signal - continuing");
294947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
295047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
295147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
295247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
295347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				LogErr("Run", "select"); return -1;
295447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
295547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
295647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if (nfds)
295747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
295847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (FD_ISSET(d->udpsd, &rset))		RecvUDPMessage( d, d->udpsd );
295947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (FD_ISSET(d->llq_udpsd, &rset))	RecvUDPMessage( d, d->llq_udpsd );
296047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (FD_ISSET(d->tcpsd, &rset))		AcceptTCPConnection( d, d->tcpsd, 0 );
296147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (FD_ISSET(d->llq_tcpsd, &rset))	AcceptTCPConnection( d, d->llq_tcpsd, 0 );
296247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (FD_ISSET(d->tlssd, &rset))  	AcceptTCPConnection( d, d->tlssd, TCP_SOCKET_FLAGS );
296347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (FD_ISSET(d->LLQEventListenSock, &rset))
296447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
296547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// clear signalling data off socket
296647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				char buf[256];
296747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				recv(d->LLQEventListenSock, buf, 256, 0);
296847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (!EventsPending)
296947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
297047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					EventsPending = mDNStrue;
297147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (gettimeofday(&EventTS, NULL)) { LogErr("Run", "gettimeofday"); return -1; }
297247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
297347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
297447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
297547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			for ( source = ( EventSource* ) d->eventSources.Head; source; source = source->next )
297647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
297747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if ( FD_ISSET( source->fd, &rset ) )
297847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
297947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					source->callback( source->context );
298047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					break;  // in case we removed this guy from the event loop
298147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
298247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
298347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
298447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
298547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
298647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// timeout
298747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (EventsPending) { GenLLQEvents(d); EventsPending = mDNSfalse; }
298847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else { DeleteRecords(d, mDNSfalse); tablecheck.tv_sec = 0; }
298947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
299047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
299147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return 0;
299247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
299347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
299447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// signal handler sets global variables, which are inspected by main event loop
299547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (select automatically returns due to the handled signal)
299647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void HndlSignal(int sig)
299747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
299847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (sig == SIGTERM || sig == SIGINT ) { terminate = 1; return; }
299947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (sig == INFO_SIGNAL)               { dumptable = 1; return; }
300047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (sig == SIGHUP)                    { hangup    = 1; return; }
300147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
300247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
300347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus
300447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltSetPublicSRV
300547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(
300647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo	*	d,
300747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const char	*	name
300847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	)
300947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
301047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNameListElem * elem;
301147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus			err = mStatus_NoError;
301247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
301347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	elem = ( DNameListElem* ) malloc( sizeof( DNameListElem ) );
301447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	require_action( elem, exit, err = mStatus_NoMemoryErr );
301547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	MakeDomainNameFromDNSNameString( &elem->name, name );
301647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	elem->next = d->public_names;
301747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d->public_names = elem;
301847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
301947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltexit:
302047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
302147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return err;
302247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
302347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
302447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
302547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltint main(int argc, char *argv[])
302647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
302747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int started_via_launchd = 0;
302847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DaemonInfo *d;
302947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct rlimit rlim;
303047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
303147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	Log("dnsextd starting");
303247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
303347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d = malloc(sizeof(*d));
303447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!d) { LogErr("main", "malloc"); exit(1); }
303547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(d, sizeof(DaemonInfo));
303647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
303747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Setup the public SRV record names
303847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
303947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SetPublicSRV(d, "_dns-update._udp.");
304047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SetPublicSRV(d, "_dns-llq._udp.");
304147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SetPublicSRV(d, "_dns-update-tls._tcp.");
304247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SetPublicSRV(d, "_dns-query-tls._tcp.");
304347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SetPublicSRV(d, "_dns-llq-tls._tcp.");
304447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
304547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Setup signal handling
304647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
304747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (signal(SIGHUP,      HndlSignal) == SIG_ERR) perror("Can't catch SIGHUP");
304847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (signal(SIGTERM,     HndlSignal) == SIG_ERR) perror("Can't catch SIGTERM");
304947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (signal(INFO_SIGNAL, HndlSignal) == SIG_ERR) perror("Can't catch SIGINFO");
305047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (signal(SIGINT,      HndlSignal) == SIG_ERR) perror("Can't catch SIGINT");
305147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (signal(SIGPIPE,     SIG_IGN  )  == SIG_ERR) perror("Can't ignore SIGPIPE");
305247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
305347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// remove open file limit
305447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rlim.rlim_max = RLIM_INFINITY;
305547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rlim.rlim_cur = RLIM_INFINITY;
305647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
305747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
305847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogErr("main", "setrlimit");
305947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		Log("Using default file descriptor resource limit");
306047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
306147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
306247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (argc > 1 && !strcasecmp(argv[1], "-launchd"))
306347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
306447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		Log("started_via_launchd");
306547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		started_via_launchd = 1;
306647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		argv++;
306747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		argc--;
306847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
306947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ProcessArgs(argc, argv, d) < 0) { LogErr("main", "ProcessArgs"); exit(1); }
307047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
307147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!foreground && !started_via_launchd)
307247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
307347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (daemon(0,0))
307447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
307547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogErr("main", "daemon");
307647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			foreground = 1;
307747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
307847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
307947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
308047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (InitLeaseTable(d) < 0) { LogErr("main", "InitLeaseTable"); exit(1); }
308147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SetupSockets(d) < 0) { LogErr("main", "SetupSockets"); exit(1); }
308247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SetUpdateSRV(d) < 0) { LogErr("main", "SetUpdateSRV"); exit(1); }
308347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
308447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	Run(d);
308547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
308647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	Log("dnsextd stopping");
308747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
308847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ClearUpdateSRV(d) < 0) { LogErr("main", "ClearUpdateSRV"); exit(1); }  // clear update srv's even if Run or pthread_create returns an error
308947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	free(d);
309047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	exit(0);
309147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
309247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
309347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
309447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// These are stubbed out implementations of up-call routines that the various platform support layers
309547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// call.  These routines are fully implemented in both mDNS.c and uDNS.c, but dnsextd doesn't
309647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// link this code in.
309747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
309847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// It's an error for these routines to actually be called, so perhaps we should log any call
309947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// to them.
310047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNSCoreInitComplete( mDNS * const m, mStatus result) { ( void ) m; ( void ) result; }
310147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNS_ConfigChanged(mDNS *const m)  { ( void ) m; }
310247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNSCoreMachineSleep(mDNS * const m, mDNSBool wake) { ( void ) m; ( void ) wake; }
310347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
310447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
310547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                const mDNSAddr *const dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID iid)
310647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) msg; ( void ) end; ( void ) srcaddr; ( void ) srcport; ( void ) dstaddr; ( void ) dstport; ( void ) iid; }
310747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltDNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout)
310847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) d; ( void ) interface; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; return(NULL); }
310947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
311047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
311147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
311247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSs32 mDNS_Execute   (mDNS *const m) { ( void ) m; return 0; }
311347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSs32 mDNS_TimeNow(const mDNS *const m) { ( void ) m; return 0; }
311447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
311547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
311647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) set; ( void ) flapping; }
311747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltconst char * const  mDNS_DomainTypeNames[1] = {};
311847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
311947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt                                const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context)
312047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) question; ( void ) DomainType; ( void ) dom; ( void ) InterfaceID; ( void ) Callback; ( void ) Context; return 0; }
312147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmStatus mDNS_Register(mDNS *const m, AuthRecord *const rr) { ( void ) m; ( void ) rr; return 0; }
312247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping)
312347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) set; ( void ) flapping; return 0; }
312447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn) { ( void ) m; ( void ) fqdn; }
312547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNS_SetFQDN(mDNS * const m) { ( void ) m; }
312647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router)
312747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) v4addr; ( void ) v6addr; ( void ) router; }
312847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmStatus uDNS_SetupDNSConfig( mDNS *const m ) { ( void ) m; return 0; }
312947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
313047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, const char *autoTunnelPrefix)
313147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{ ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; ( void ) autoTunnelPrefix; return 0; }
313247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
313347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid TriggerEventCompletion(void);
313447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid TriggerEventCompletion() {}
313547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNS mDNSStorage;
313647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
313747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
313847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For convenience when using the "strings" command, this is the last thing in the file
313947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The "@(#) " pattern is a special prefix the "what" command looks for
314047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltconst char mDNSResponderVersionString_SCCS[] = "@(#) dnsextd " STRINGIFY(mDNSResponderVersion) " (" __DATE__ " " __TIME__ ")";
314147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
314247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if _BUILDING_XCODE_PROJECT_
314347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If the process crashes, then this string will be magically included in the automatically-generated crash log
314447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltconst char *__crashreporter_info__ = mDNSResponderVersionString_SCCS + 5;
314547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltasm(".desc ___crashreporter_info__, 0x10");
314647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
3147