147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* -*- Mode: C; tab-width: 4 -*-
247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Copyright (c) 2002-2003 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// Set mDNS_InstantiateInlines to tell mDNSEmbeddedAPI.h to instantiate inline functions, if necessary
1947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define mDNS_InstantiateInlines 1
2047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "DNSCommon.h"
2147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
2247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Disable certain benign warnings with Microsoft compilers
2347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if (defined(_MSC_VER))
2447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Disable "conditional expression is constant" warning for debug macros.
2547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Otherwise, this generates warnings for the perfectly natural construct "while(1)"
2647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If someone knows a variant way of writing "while(1)" that doesn't generate warning messages, please let us know
2747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	#pragma warning(disable:4127)
2847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Disable "array is too small to include a terminating null character" warning
2947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// -- domain labels have an initial length byte, not a terminating null character
3047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	#pragma warning(disable:4295)
3147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
3247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
3347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
3447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
3547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Program Constants
3647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
3747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
3847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSInterfaceID mDNSInterface_Any       = 0;
3947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSInterfaceID mDNSInterfaceMark       = (mDNSInterfaceID)-1;
4047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
4147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSInterfaceID mDNSInterface_Unicast   = (mDNSInterfaceID)-3;
4247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSInterfaceID mDNSInterface_P2P       = (mDNSInterfaceID)-4;
4347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: Microsoft's proposed "Link Local Multicast Name Resolution Protocol" (LLMNR) is essentially a limited version of
4547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Multicast DNS, using the same packet formats, naming syntax, and record types as Multicast DNS, but on a different UDP
4647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// port and multicast address, which means it won't interoperate with the existing installed base of Multicast DNS responders.
4747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// LLMNR uses IPv4 multicast address 224.0.0.252, IPv6 multicast address FF02::0001:0003, and UDP port 5355.
4847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Uncomment the appropriate lines below to build a special Multicast DNS responder for testing interoperability
4947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// with Microsoft's LLMNR client code.
5047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
5147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   DiscardPortAsNumber               9
5247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   SSHPortAsNumber                  22
5347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   UnicastDNSPortAsNumber           53
5447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   SSDPPortAsNumber               1900
5547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   IPSECPortAsNumber              4500
5647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   NSIPCPortAsNumber              5030		// Port used for dnsextd to talk to local nameserver bound to loopback
5747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   NATPMPAnnouncementPortAsNumber 5350
5847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   NATPMPPortAsNumber             5351
5947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   DNSEXTPortAsNumber             5352		// Port used for end-to-end DNS operations like LLQ, Updates with Leases, etc.
6047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   MulticastDNSPortAsNumber       5353
6147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   LoopbackIPCPortAsNumber        5354
6247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//#define MulticastDNSPortAsNumber       5355		// LLMNR
6347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define   PrivateDNSPortAsNumber         5533
6447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
6547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort DiscardPort            = { { DiscardPortAsNumber            >> 8, DiscardPortAsNumber            & 0xFF } };
6647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort SSHPort                = { { SSHPortAsNumber                >> 8, SSHPortAsNumber                & 0xFF } };
6747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort UnicastDNSPort         = { { UnicastDNSPortAsNumber         >> 8, UnicastDNSPortAsNumber         & 0xFF } };
6847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort SSDPPort               = { { SSDPPortAsNumber               >> 8, SSDPPortAsNumber               & 0xFF } };
6947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort IPSECPort              = { { IPSECPortAsNumber              >> 8, IPSECPortAsNumber              & 0xFF } };
7047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort NSIPCPort              = { { NSIPCPortAsNumber              >> 8, NSIPCPortAsNumber              & 0xFF } };
7147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort NATPMPAnnouncementPort = { { NATPMPAnnouncementPortAsNumber >> 8, NATPMPAnnouncementPortAsNumber & 0xFF } };
7247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort NATPMPPort             = { { NATPMPPortAsNumber             >> 8, NATPMPPortAsNumber             & 0xFF } };
7347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort DNSEXTPort             = { { DNSEXTPortAsNumber             >> 8, DNSEXTPortAsNumber             & 0xFF } };
7447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort MulticastDNSPort       = { { MulticastDNSPortAsNumber       >> 8, MulticastDNSPortAsNumber       & 0xFF } };
7547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort LoopbackIPCPort        = { { LoopbackIPCPortAsNumber        >> 8, LoopbackIPCPortAsNumber        & 0xFF } };
7647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort PrivateDNSPort         = { { PrivateDNSPortAsNumber         >> 8, PrivateDNSPortAsNumber         & 0xFF } };
7747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const OwnerOptData    zeroOwner         = { 0, 0, { { 0 } }, { { 0 } }, { { 0 } } };
7947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
8047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSIPPort      zeroIPPort        = { { 0 } };
8147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv4Addr      zerov4Addr        = { { 0 } };
8247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv6Addr      zerov6Addr        = { { 0 } };
8347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSEthAddr     zeroEthAddr       = { { 0 } };
8447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv4Addr      onesIPv4Addr      = { { 255, 255, 255, 255 } };
8547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv6Addr      onesIPv6Addr      = { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } };
8647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSEthAddr     onesEthAddr       = { { 255, 255, 255, 255, 255, 255 } };
8747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSAddr        zeroAddr          = { mDNSAddrType_None, {{{ 0 }}} };
8847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
8947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv4Addr  AllDNSAdminGroup   = { { 239, 255, 255, 251 } };
9047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv4Addr  AllHosts_v4        = { { 224,   0,   0,   1 } }; // For NAT-PMP Annoucements
9147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv6Addr  AllHosts_v6        = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01 } };
9247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSv6Addr  NDP_prefix         = { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x01, 0xFF,0x00,0x00,0xFB } }; // FF02:0:0:0:0:1:FF00::/104
9347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSEthAddr AllHosts_v6_Eth    = { { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } };
9447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSAddr    AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 251 } } } };
9547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//mDNSexport const mDNSAddr  AllDNSLinkGroup_v4 = { mDNSAddrType_IPv4, { { { 224,   0,   0, 252 } } } }; // LLMNR
9647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSAddr    AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0xFB } } } };
9747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//mDNSexport const mDNSAddr  AllDNSLinkGroup_v6 = { mDNSAddrType_IPv6, { { { 0xFF,0x02,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x01,0x00,0x03 } } } }; // LLMNR
9847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque16 zeroID          = { { 0, 0 } };
10047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque16 onesID          = { { 255, 255 } };
10147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque16 QueryFlags      = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery,                0 } };
10247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque16 uQueryFlags     = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery | kDNSFlag0_RD, 0 } };
10347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque16 ResponseFlags   = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA, 0 } };
10447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque16 UpdateReqFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Update,                  0 } };
10547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque16 UpdateRespFlags = { { kDNSFlag0_QR_Response | kDNSFlag0_OP_Update,                  0 } };
10647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
10747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSOpaque64 zeroOpaque64    = { { 0 } };
10847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
10947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
11047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
11147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
11247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - General Utility Functions
11347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
11447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// return true for RFC1918 private addresses
11647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr)
11747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
11847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ((addr->b[0] == 10) ||                                 // 10/8 prefix
11947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			(addr->b[0] == 172 && (addr->b[1] & 0xF0) == 16) ||   // 172.16/12
12047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			(addr->b[0] == 192 && addr->b[1] == 168));            // 192.168/16
12147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
12247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport NetworkInterfaceInfo *GetFirstActiveInterface(NetworkInterfaceInfo *intf)
12447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
12547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (intf && !intf->InterfaceActive) intf = intf->next;
12647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(intf);
12747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
12847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSInterfaceID GetNextActiveInterfaceID(const NetworkInterfaceInfo *intf)
13047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
13147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const NetworkInterfaceInfo *next = GetFirstActiveInterface(intf->next);
13247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (next) return(next->InterfaceID); else return(mDNSNULL);
13347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
13447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
13547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id)
13647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
13747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 slot, used = 0;
13847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CacheGroup *cg;
13947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const CacheRecord *rr;
14047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FORALL_CACHERECORDS(slot, cg, rr)
14147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (rr->resrec.InterfaceID == id) used++;
14247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(used);
14347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
14447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
14547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport char *DNSTypeName(mDNSu16 rrtype)
14647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
14747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch (rrtype)
14847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
14947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_A:    return("Addr");
15047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:   return("NS");
15147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:return("CNAME");
15247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SOA:  return("SOA");
15347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NULL: return("NULL");
15447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:  return("PTR");
15547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_HINFO:return("HINFO");
15647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TXT:  return("TXT");
15747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AAAA: return("AAAA");
15847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:  return("SRV");
15947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:  return("OPT");
16047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC: return("NSEC");
16147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TSIG: return("TSIG");
16247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSQType_ANY: return("ANY");
16347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			{
16447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							static char buffer[16];
16547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNS_snprintf(buffer, sizeof(buffer), "(%d)", rrtype);
16647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(buffer);
16747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
16847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
16947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
17047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
17147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note slight bug: this code uses the rdlength from the ResourceRecord object, to display
17247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// the rdata from the RDataBody object. Sometimes this could be the wrong length -- but as
17347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// long as this routine is only used for debugging messages, it probably isn't a big problem.
17447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer)
17547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
17647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const RDataBody2 *const rd = (RDataBody2 *)rd1;
17747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	#define RemSpc (MaxMsg-1-length)
17847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char *ptr = buffer;
17947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 length = mDNS_snprintf(buffer, MaxMsg-1, "%4d %##s %s ", rr->rdlength, rr->name->c, DNSTypeName(rr->rrtype));
18047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->RecordType == kDNSRecordTypePacketNegative) return(buffer);
18147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!rr->rdlength) { mDNS_snprintf(buffer+length, RemSpc, "<< ZERO RDATA LENGTH >>"); return(buffer); }
18247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch (rr->rrtype)
18447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
18547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_A:	mDNS_snprintf(buffer+length, RemSpc, "%.4a", &rd->ipv4);          break;
18647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:	// Same as PTR
18847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:// Same as PTR
18947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:	mDNS_snprintf(buffer+length, RemSpc, "%##s", rd->name.c);       break;
19047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
19147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SOA:  mDNS_snprintf(buffer+length, RemSpc, "%##s %##s %d %d %d %d %d",
19247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								rd->soa.mname.c, rd->soa.rname.c,
19347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								rd->soa.serial, rd->soa.refresh, rd->soa.retry, rd->soa.expire, rd->soa.min);
19447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
19547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
19647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_HINFO:// Display this the same as TXT (show all constituent strings)
19747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TXT:  {
19847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							const mDNSu8 *t = rd->txt.c;
19947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							while (t < rd->txt.c + rr->rdlength)
20047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
20147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								length += mDNS_snprintf(buffer+length, RemSpc, "%s%#s", t > rd->txt.c ? "¦" : "", t);
20247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								t += 1 + t[0];
20347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
20447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							} break;
20547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AAAA:	mDNS_snprintf(buffer+length, RemSpc, "%.16a", &rd->ipv6);       break;
20747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	mDNS_snprintf(buffer+length, RemSpc, "%u %u %u %##s",
20847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								rd->srv.priority, rd->srv.weight, mDNSVal16(rd->srv.port), rd->srv.target.c); break;
20947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
21047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:  {
21147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							const rdataOPT *opt;
21247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							const rdataOPT *const end = (const rdataOPT *)&rd->data[rr->rdlength];
21347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							length += mDNS_snprintf(buffer+length, RemSpc, "Max %d", rr->rrclass);
21447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (opt = &rd->opt[0]; opt < end; opt++)
21547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
21647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								switch(opt->opt)
21747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
21847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_LLQ:
21947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d",     opt->u.llq.vers);
22047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Op %d",       opt->u.llq.llqOp);
22147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Err/Port %d", opt->u.llq.err);
22247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " ID %08X%08X", opt->u.llq.id.l[0], opt->u.llq.id.l[1]);
22347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d",    opt->u.llq.llqlease);
22447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
22547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_Lease:
22647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Lease %d",    opt->u.updatelease);
22747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
22847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_Owner:
22947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Vers %d",     opt->u.owner.vers);
23047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Seq %3d", (mDNSu8)opt->u.owner.seq);	// Display as unsigned
23147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " MAC %.6a",    opt->u.owner.HMAC.b);
23247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
23347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											{
23447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											length += mDNS_snprintf(buffer+length, RemSpc, " I-MAC %.6a", opt->u.owner.IMAC.b);
23547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
23647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												length += mDNS_snprintf(buffer+length, RemSpc, " Password %.6a", opt->u.owner.password.b);
23747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											}
23847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
23947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									default:
24047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										length += mDNS_snprintf(buffer+length, RemSpc, " Unknown %d",  opt->opt);
24147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
24247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
24347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
24447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
24547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
24647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
24747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC: {
24847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSu16 i;
24947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (i=0; i<255; i++)
25047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (rd->nsec.bitmap[i>>3] & (128 >> (i&7)))
25147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									length += mDNS_snprintf(buffer+length, RemSpc, "%s ", DNSTypeName(i));
25247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
25347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
25447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
25547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			mDNS_snprintf(buffer+length, RemSpc, "RDLen %d: %s", rr->rdlength, rd->data);
25647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// Really should scan buffer to check if text is valid UTF-8 and only replace with dots if not
25747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (ptr = buffer; *ptr; ptr++) if (*ptr < ' ') *ptr = '.';
25847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
25947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
26047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(buffer);
26147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
26247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// See comments in mDNSEmbeddedAPI.h
26447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if _PLATFORM_HAS_STRONG_PRNG_
26547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define mDNSRandomNumber mDNSPlatformRandomNumber
26647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#else
26747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 mDNSRandomFromSeed(mDNSu32 seed)
26847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
26947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return seed * 21 + 1;
27047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
27147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
27247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 mDNSMixRandomSeed(mDNSu32 seed, mDNSu8 iteration)
27347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
27447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return iteration ? mDNSMixRandomSeed(mDNSRandomFromSeed(seed), --iteration) : seed;
27547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
27647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
27747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 mDNSRandomNumber()
27847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
27947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static mDNSBool seeded = mDNSfalse;
28047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static mDNSu32 seed = 0;
28147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!seeded)
28247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
28347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		seed = mDNSMixRandomSeed(mDNSPlatformRandomSeed(), 100);
28447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		seeded = mDNStrue;
28547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
28647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return (seed = mDNSRandomFromSeed(seed));
28747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
28847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif // ! _PLATFORM_HAS_STRONG_PRNG_
28947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
29047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 mDNSRandom(mDNSu32 max)		// Returns pseudo-random result from zero to max inclusive
29147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
29247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 ret = 0;
29347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 mask = 1;
29447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
29547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (mask < max) mask = (mask << 1) | 1;
29647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
29747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	do ret = mDNSRandomNumber() & mask;
29847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (ret > max);
29947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
30047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ret;
30147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
30247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
30347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2)
30447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
30547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ip1->type == ip2->type)
30647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
30747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		switch (ip1->type)
30847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
30947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case mDNSAddrType_None : return(mDNStrue); // Empty addresses have no data and are therefore always equal
31047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case mDNSAddrType_IPv4 : return(mDNSBool)(mDNSSameIPv4Address(ip1->ip.v4, ip2->ip.v4));
31147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case mDNSAddrType_IPv6 : return(mDNSBool)(mDNSSameIPv6Address(ip1->ip.v6, ip2->ip.v6));
31247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
31347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
31447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSfalse);
31547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
31647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
31747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip)
31847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
31947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch(ip->type)
32047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
32147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mDNSAddrType_IPv4: return(mDNSBool)(mDNSSameIPv4Address(ip->ip.v4, AllDNSLinkGroup_v4.ip.v4));
32247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case mDNSAddrType_IPv6: return(mDNSBool)(mDNSSameIPv6Address(ip->ip.v6, AllDNSLinkGroup_v6.ip.v6));
32347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default: return(mDNSfalse);
32447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
32547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
32647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
32747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
32847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
32947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
33047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Domain Name Utility Functions
33147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
33247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
33447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
33547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
33647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const int len = *a++;
33747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len > MAX_DOMAIN_LABEL)
33947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ debugf("Malformed label (too long)"); return(mDNSfalse); }
34047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
34147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len != *b++) return(mDNSfalse);
34247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<len; i++)
34347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
34447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 ac = *a++;
34547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 bc = *b++;
34647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (mDNSIsUpperCase(ac)) ac += 'a' - 'A';
34747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (mDNSIsUpperCase(bc)) bc += 'a' - 'A';
34847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ac != bc) return(mDNSfalse);
34947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
35047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNStrue);
35147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
35247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2)
35447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
35547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *      a   = d1->c;
35647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *      b   = d2->c;
35747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const max = d1->c + MAX_DOMAIN_NAME;			// Maximum that's valid
35847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*a || *b)
36047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
36147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (a + 1 + *a >= max)
36247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{ debugf("Malformed domain name (more than 256 characters)"); return(mDNSfalse); }
36347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!SameDomainLabel(a, b)) return(mDNSfalse);
36447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		a += 1 + *a;
36547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		b += 1 + *b;
36647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
36747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
36847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNStrue);
36947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
37047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
37147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2)
37247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
37347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 l1 = DomainNameLength(d1);
37447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 l2 = DomainNameLength(d2);
37547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(l1 <= MAX_DOMAIN_NAME && l1 == l2 && mDNSPlatformMemSame(d1, d2, l1));
37647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
37747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
37847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool IsLocalDomain(const domainname *d)
37947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
38047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Domains that are defined to be resolved via link-local multicast are:
38147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// local., 254.169.in-addr.arpa., and {8,9,A,B}.E.F.ip6.arpa.
38247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const domainname *nL = (const domainname*)"\x5" "local";
38347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const domainname *nR = (const domainname*)"\x3" "254" "\x3" "169"         "\x7" "in-addr" "\x4" "arpa";
38447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const domainname *n8 = (const domainname*)"\x1" "8"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
38547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const domainname *n9 = (const domainname*)"\x1" "9"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
38647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const domainname *nA = (const domainname*)"\x1" "a"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
38747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const domainname *nB = (const domainname*)"\x1" "b"   "\x1" "e" "\x1" "f" "\x3" "ip6"     "\x4" "arpa";
38847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainname *d1, *d2, *d3, *d4, *d5;	// Top-level domain, second-level domain, etc.
39047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	d1 = d2 = d3 = d4 = d5 = mDNSNULL;
39147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (d->c[0])
39247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
39347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		d5 = d4; d4 = d3; d3 = d2; d2 = d1; d1 = d;
39447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		d = (const domainname*)(d->c + 1 + d->c[0]);
39547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
39647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (d1 && SameDomainName(d1, nL)) return(mDNStrue);
39847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (d4 && SameDomainName(d4, nR)) return(mDNStrue);
39947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (d5 && SameDomainName(d5, n8)) return(mDNStrue);
40047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (d5 && SameDomainName(d5, n9)) return(mDNStrue);
40147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (d5 && SameDomainName(d5, nA)) return(mDNStrue);
40247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (d5 && SameDomainName(d5, nB)) return(mDNStrue);
40347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSfalse);
40447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
40547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
40647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *LastLabel(const domainname *d)
40747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
40847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *p = d->c;
40947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (d->c[0])
41047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
41147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		p = d->c;
41247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		d = (const domainname*)(d->c + 1 + d->c[0]);
41347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
41447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(p);
41547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
41647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
41747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns length of a domain name INCLUDING the byte for the final null label
41847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// e.g. for the root label "." it returns one
41947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// For the FQDN "com." it returns 5 (length byte, three data bytes, final zero)
42047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Legal results are 1 (just root label) to 256 (MAX_DOMAIN_NAME)
42147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If the given domainname is invalid, result is 257 (MAX_DOMAIN_NAME+1)
42247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit)
42347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
42447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *src = name->c;
42547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (src < limit && *src <= MAX_DOMAIN_LABEL)
42647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
42747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (*src == 0) return((mDNSu16)(src - name->c + 1));
42847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		src += 1 + *src;
42947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
43047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(MAX_DOMAIN_NAME+1);
43147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
43247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
43347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CompressedDomainNameLength returns the length of a domain name INCLUDING the byte
43447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for the final null label, e.g. for the root label "." it returns one.
43547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// E.g. for the FQDN "foo.com." it returns 9
43647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (length, three data bytes, length, three more data bytes, final zero).
43747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In the case where a parent domain name is provided, and the given name is a child
43847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// of that parent, CompressedDomainNameLength returns the length of the prefix portion
43947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// of the child name, plus TWO bytes for the compression pointer.
44047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// E.g. for the name "foo.com." with parent "com.", it returns 6
44147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (length, three data bytes, two-byte compression pointer).
44247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu16 CompressedDomainNameLength(const domainname *const name, const domainname *parent)
44347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
44447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *src = name->c;
44547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (parent && parent->c[0] == 0) parent = mDNSNULL;
44647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*src)
44747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
44847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (*src > MAX_DOMAIN_LABEL) return(MAX_DOMAIN_NAME+1);
44947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (parent && SameDomainName((const domainname *)src, parent)) return((mDNSu16)(src - name->c + 2));
45047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		src += 1 + *src;
45147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (src - name->c >= MAX_DOMAIN_NAME) return(MAX_DOMAIN_NAME+1);
45247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
45347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return((mDNSu16)(src - name->c + 1));
45447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
45547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
45647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// CountLabels() returns number of labels in name, excluding final root label
45747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// (e.g. for "apple.com." CountLabels returns 2.)
45847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport int CountLabels(const domainname *d)
45947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
46047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int count = 0;
46147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr;
46247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (ptr = d->c; *ptr; ptr = ptr + ptr[0] + 1) count++;
46347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return count;
46447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
46547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
46647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// SkipLeadingLabels skips over the first 'skip' labels in the domainname,
46747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// returning a pointer to the suffix with 'skip' labels removed.
46847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const domainname *SkipLeadingLabels(const domainname *d, int skip)
46947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
47047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (skip > 0 && d->c[0]) { d = (const domainname *)(d->c + 1 + d->c[0]); skip--; }
47147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(d);
47247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
47347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AppendLiteralLabelString appends a single label to an existing (possibly empty) domainname.
47547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The C string contains the label as-is, with no escaping, etc.
47647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Any dots in the name are literal dots, not label separators
47747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If successful, AppendLiteralLabelString returns a pointer to the next unused byte
47847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// in the domainname bufer (i.e. the next byte after the terminating zero).
47947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
48047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AppendLiteralLabelString returns mDNSNULL.
48147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr)
48247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
48347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8       *      ptr  = name->c + DomainNameLength(name) - 1;	// Find end of current name
48447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const lim1 = name->c + MAX_DOMAIN_NAME - 1;			// Limit of how much we can add (not counting final zero)
48547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const lim2 = ptr + 1 + MAX_DOMAIN_LABEL;
48647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const lim  = (lim1 < lim2) ? lim1 : lim2;
48747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8       *lengthbyte = ptr++;									// Record where the length is going to go
48847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
48947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*cstr && ptr < lim) *ptr++ = (mDNSu8)*cstr++;	// Copy the data
49047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*lengthbyte = (mDNSu8)(ptr - lengthbyte - 1);			// Fill in the length byte
49147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = 0;												// Put the null root label on the end
49247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (*cstr) return(mDNSNULL);							// Failure: We didn't successfully consume all input
49347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else return(ptr);										// Success: return new value of ptr
49447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
49547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AppendDNSNameString appends zero or more labels to an existing (possibly empty) domainname.
49747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The C string is in conventional DNS syntax:
49847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
49947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If successful, AppendDNSNameString returns a pointer to the next unused byte
50047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// in the domainname bufer (i.e. the next byte after the terminating zero).
50147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
50247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AppendDNSNameString returns mDNSNULL.
50347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstring)
50447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
50547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const char   *cstr      = cstring;
50647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8       *      ptr = name->c + DomainNameLength(name) - 1;	// Find end of current name
50747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1;		// Limit of how much we can add (not counting final zero)
50847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*cstr && ptr < lim)										// While more characters, and space to put them...
50947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
51047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *lengthbyte = ptr++;									// Record where the length is going to go
51147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (*cstr == '.') { LogMsg("AppendDNSNameString: Illegal empty label in name \"%s\"", cstring); return(mDNSNULL); }
51247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (*cstr && *cstr != '.' && ptr < lim)					// While we have characters in the label...
51347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
51447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSu8 c = (mDNSu8)*cstr++;								// Read the character
51547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (c == '\\')											// If escape character, check next character
51647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
51747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				c = (mDNSu8)*cstr++;								// Assume we'll just take the next character
51847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (mDNSIsDigit(cstr[-1]) && mDNSIsDigit(cstr[0]) && mDNSIsDigit(cstr[1]))
51947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{												// If three decimal digits,
52047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					int v0 = cstr[-1] - '0';						// then interpret as three-digit decimal
52147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					int v1 = cstr[ 0] - '0';
52247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					int v2 = cstr[ 1] - '0';
52347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					int val = v0 * 100 + v1 * 10 + v2;
52447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (val <= 255) { c = (mDNSu8)val; cstr += 2; }	// If valid three-digit decimal value, use it
52547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
52647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
52747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			*ptr++ = c;												// Write the character
52847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
52947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (*cstr) cstr++;											// Skip over the trailing dot (if present)
53047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr - lengthbyte - 1 > MAX_DOMAIN_LABEL)				// If illegal label, abort
53147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return(mDNSNULL);
53247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*lengthbyte = (mDNSu8)(ptr - lengthbyte - 1);				// Fill in the length byte
53347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
53447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
53547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = 0;														// Put the null root label on the end
53647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (*cstr) return(mDNSNULL);									// Failure: We didn't successfully consume all input
53747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else return(ptr);												// Success: return new value of ptr
53847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
53947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
54047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AppendDomainLabel appends a single label to a name.
54147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If successful, AppendDomainLabel returns a pointer to the next unused byte
54247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// in the domainname bufer (i.e. the next byte after the terminating zero).
54347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
54447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// AppendDomainLabel returns mDNSNULL.
54547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label)
54647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
54747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
54847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *ptr = name->c + DomainNameLength(name) - 1;
54947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
55047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Check label is legal
55147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (label->c[0] > MAX_DOMAIN_LABEL) return(mDNSNULL);
55247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
55347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Check that ptr + length byte + data bytes + final zero does not exceed our limit
55447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr + 1 + label->c[0] + 1 > name->c + MAX_DOMAIN_NAME) return(mDNSNULL);
55547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
55647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=label->c[0]; i++) *ptr++ = label->c[i];	// Copy the label data
55747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = 0;								// Put the null root label on the end
55847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);
55947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
56047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
56147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append)
56247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
56347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8       *      ptr = name->c + DomainNameLength(name) - 1;	// Find end of current name
56447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const lim = name->c + MAX_DOMAIN_NAME - 1;		// Limit of how much we can add (not counting final zero)
56547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *      src = append->c;
56647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (src[0])
56747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
56847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int i;
56947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr + 1 + src[0] > lim) return(mDNSNULL);
57047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (i=0; i<=src[0]; i++) *ptr++ = src[i];
57147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*ptr = 0;	// Put the null root label on the end
57247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		src += i;
57347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
57447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);
57547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
57647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
57747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// MakeDomainLabelFromLiteralString makes a single domain label from a single literal C string (with no escaping).
57847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If successful, MakeDomainLabelFromLiteralString returns mDNStrue.
57947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If unable to convert the whole string to a legal domain label (i.e. because length is more than 63 bytes) then
58047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// MakeDomainLabelFromLiteralString makes a legal domain label from the first 63 bytes of the string and returns mDNSfalse.
58147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In some cases silently truncated oversized names to 63 bytes is acceptable, so the return result may be ignored.
58247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In other cases silent truncation may not be acceptable, so in those cases the calling function needs to check the return result.
58347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr)
58447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
58547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8       *      ptr   = label->c + 1;						// Where we're putting it
58647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const limit = label->c + 1 + MAX_DOMAIN_LABEL;	// The maximum we can put
58747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*cstr && ptr < limit) *ptr++ = (mDNSu8)*cstr++;			// Copy the label
58847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	label->c[0] = (mDNSu8)(ptr - label->c - 1);						// Set the length byte
58947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(*cstr == 0);												// Return mDNStrue if we successfully consumed all input
59047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
59147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
59247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// MakeDomainNameFromDNSNameString makes a native DNS-format domainname from a C string.
59347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The C string is in conventional DNS syntax:
59447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Textual labels, escaped as necessary using the usual DNS '\' notation, separated by dots.
59547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If successful, MakeDomainNameFromDNSNameString returns a pointer to the next unused byte
59647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// in the domainname bufer (i.e. the next byte after the terminating zero).
59747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// If unable to construct a legal domain name (i.e. label more than 63 bytes, or total more than 256 bytes)
59847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// MakeDomainNameFromDNSNameString returns mDNSNULL.
59947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr)
60047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
60147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	name->c[0] = 0;									// Make an empty domain name
60247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(AppendDNSNameString(name, cstr));		// And then add this string to it
60347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
60447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
60547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport char *ConvertDomainLabelToCString_withescape(const domainlabel *const label, char *ptr, char esc)
60647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
60747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *      src = label->c;							// Domain label we're reading
60847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8        len = *src++;							// Read length of this (non-null) label
60947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const end = src + len;						// Work out where the label ends
61047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len > MAX_DOMAIN_LABEL) return(mDNSNULL);				// If illegal label, abort
61147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (src < end)											// While we have characters in the label
61247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
61347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 c = *src++;
61447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (esc)
61547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
61647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (c == '.' || c == esc)							// If character is a dot or the escape character
61747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr++ = esc;									// Output escape character
61847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else if (c <= ' ')									// If non-printing ascii,
61947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{												// Output decimal escape sequence
62047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr++ = esc;
62147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr++ = (char)  ('0' + (c / 100)     );
62247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr++ = (char)  ('0' + (c /  10) % 10);
62347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				c      = (mDNSu8)('0' + (c      ) % 10);
62447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
62547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
62647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*ptr++ = (char)c;										// Copy the character
62747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
62847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr = 0;													// Null-terminate the string
62947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);												// and return
63047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
63147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
63247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: To guarantee that there will be no possible overrun, cstr must be at least MAX_ESCAPED_DOMAIN_NAME (1009 bytes)
63347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport char *ConvertDomainNameToCString_withescape(const domainname *const name, char *ptr, char esc)
63447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
63547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *src         = name->c;							// Domain name we're reading
63647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const max   = name->c + MAX_DOMAIN_NAME;			// Maximum that's valid
63747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
63847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (*src == 0) *ptr++ = '.';									// Special case: For root, just write a dot
63947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*src)													// While more characters in the domain name
64147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
64247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (src + 1 + *src >= max) return(mDNSNULL);
64347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = ConvertDomainLabelToCString_withescape((const domainlabel *)src, ptr, esc);
64447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) return(mDNSNULL);
64547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		src += 1 + *src;
64647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*ptr++ = '.';												// Write the dot after the label
64747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
64847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
64947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = 0;														// Null-terminate the string
65047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);													// and return
65147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
65247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// RFC 1034 rules:
65447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Host names must start with a letter, end with a letter or digit,
65547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and have as interior characters only letters, digits, and hyphen.
65647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This was subsequently modified in RFC 1123 to allow the first character to be either a letter or a digit
65747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel)
65947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
66047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *      src  = &UTF8Name[1];
66147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const end  = &UTF8Name[1] + UTF8Name[0];
66247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	      mDNSu8 *      ptr  = &hostlabel->c[1];
66347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const lim  = &hostlabel->c[1] + MAX_DOMAIN_LABEL;
66447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (src < end)
66547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
66647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Delete apostrophes from source name
66747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (src[0] == '\'') { src++; continue; }		// Standard straight single quote
66847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (src + 2 < end && src[0] == 0xE2 && src[1] == 0x80 && src[2] == 0x99)
66947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{ src += 3; continue; }	// Unicode curly apostrophe
67047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr < lim)
67147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
67247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (mDNSValidHostChar(*src, (ptr > &hostlabel->c[1]), (src < end-1))) *ptr++ = *src;
67347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else if (ptr > &hostlabel->c[1] && ptr[-1] != '-') *ptr++ = '-';
67447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
67547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		src++;
67647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
67747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (ptr > &hostlabel->c[1] && ptr[-1] == '-') ptr--;	// Truncate trailing '-' marks
67847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	hostlabel->c[0] = (mDNSu8)(ptr - &hostlabel->c[1]);
67947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
68047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define ValidTransportProtocol(X) ( (X)[0] == 4 && (X)[1] == '_' && \
68247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	((((X)[2] | 0x20) == 'u' && ((X)[3] | 0x20) == 'd') || (((X)[2] | 0x20) == 't' && ((X)[3] | 0x20) == 'c')) && \
68347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	((X)[4] | 0x20) == 'p')
68447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
68647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainlabel *name, const domainname *type, const domainname *const domain)
68747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
68847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i, len;
68947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *dst = fqdn->c;
69047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *src;
69147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const char *errormsg;
69247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder
69347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool	loggedUnderscore = mDNSfalse;
69447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static char typeBuf[MAX_ESCAPED_DOMAIN_NAME];
69547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
69647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
69747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// In the case where there is no name (and ONLY in that case),
69847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// a single-label subtype is allowed as the first label of a three-part "type"
69947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!name && type)
70047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
70147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *s0 = type->c;
70247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (s0[0] && s0[0] < 0x40)		// If legal first label (at least one character, and no more than 63)
70347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
70447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			const mDNSu8 * s1 = s0 + 1 + s0[0];
70547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (s1[0] && s1[0] < 0x40)	// and legal second label (at least one character, and no more than 63)
70647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
70747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				const mDNSu8 *s2 = s1 + 1 + s1[0];
70847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (s2[0] && s2[0] < 0x40 && s2[1+s2[0]] == 0)	// and we have three and only three labels
70947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{
71047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					static const mDNSu8 SubTypeLabel[5] = "\x04_sub";
71147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					src = s0;									// Copy the first label
71247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					len = *src;
71347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					for (i=0; i <= len;                      i++) *dst++ = *src++;
71447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					for (i=0; i < (int)sizeof(SubTypeLabel); i++) *dst++ = SubTypeLabel[i];
71547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					type = (const domainname *)s1;
71647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
71747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					// Special support to enable the DNSServiceBrowse call made by Bonjour Browser
71847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					// For these queries, we retract the "._sub" we just added between the subtype and the main type
71947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					// Remove after Bonjour Browser is updated to use DNSServiceQueryRecord instead of DNSServiceBrowse
72047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (SameDomainName((domainname*)s0, (const domainname*)"\x09_services\x07_dns-sd\x04_udp"))
72147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						dst -= sizeof(SubTypeLabel);
72247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					}
72347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
72447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
72547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
72647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
72747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (name && name->c[0])
72847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
72947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		src = name->c;									// Put the service name into the domain name
73047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		len = *src;
73147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (len >= 0x40) { errormsg = "Service instance name too long"; goto fail; }
73247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (i=0; i<=len; i++) *dst++ = *src++;
73347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
73447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
73547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		name = (domainlabel*)"";	// Set this up to be non-null, to avoid errors if we have to call LogMsg() below
73647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	src = type->c;										// Put the service type into the domain name
73847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
73947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len < 2 || len > 16)
74047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
74147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Bad service type in %#s.%##s%##s Application protocol name must be underscore plus 1-15 characters. "
74247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			"See <http://www.dns-sd.org/ServiceTypes.html>", name->c, type->c, domain->c);
74347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder
74447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(type, typeBuf);
74547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSASLLog(mDNSNULL, "serviceType.nameTooLong", "noop", typeBuf, "");
74647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
74747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
74847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len < 2 || len >= 0x40 || (len > 16 && !SameDomainName(domain, &localdomain))) return(mDNSNULL);
74947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (src[1] != '_') { errormsg = "Application protocol name must begin with underscore"; goto fail; }
75047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=2; i<=len; i++)
75147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
75247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Letters and digits are allowed anywhere
75347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (mDNSIsLetter(src[i]) || mDNSIsDigit(src[i])) continue;
75447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Hyphens are only allowed as interior characters
75547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Underscores are not supposed to be allowed at all, but for backwards compatibility with some old products we do allow them,
75647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// with the same rule as hyphens
75747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if ((src[i] == '-' || src[i] == '_') && i > 2 && i < len)
75847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
75947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder
76047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (src[i] == '_' && loggedUnderscore == mDNSfalse)
76147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
76247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				ConvertDomainNameToCString(type, typeBuf);
76347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				mDNSASLLog(mDNSNULL, "serviceType.nameWithUnderscore", "noop", typeBuf, "");
76447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				loggedUnderscore = mDNStrue;
76547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
76647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
76747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			continue;
76847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
76947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		errormsg = "Application protocol name must contain only letters, digits, and hyphens";
77047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if APPLE_OSX_mDNSResponder
77147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
77247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ConvertDomainNameToCString(type, typeBuf);
77347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSASLLog(mDNSNULL, "serviceType.nameWithIllegalCharacters", "noop", typeBuf, "");
77447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
77547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
77647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		 goto fail;
77747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
77847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=len; i++) *dst++ = *src++;
77947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
78047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
78147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ValidTransportProtocol(src)) { errormsg = "Transport protocol name must be _udp or _tcp"; goto fail; }
78247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=len; i++) *dst++ = *src++;
78347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
78447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (*src) { errormsg = "Service type must have only two labels"; goto fail; }
78547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
78647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*dst = 0;
78747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!domain->c[0]) { errormsg = "Service domain must be non-empty"; goto fail; }
78847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (SameDomainName(domain, (const domainname*)"\x05" "local" "\x04" "arpa"))
78947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ errormsg = "Illegal domain \"local.arpa.\" Use \"local.\" (or empty string)"; goto fail; }
79047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	dst = AppendDomainName(fqdn, domain);
79147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!dst) { errormsg = "Service domain too long"; goto fail; }
79247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(dst);
79347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
79447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltfail:
79547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LogMsg("ConstructServiceName: %s: %#s.%##s%##s", errormsg, name->c, type->c, domain->c);
79647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSNULL);
79747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
79847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
79947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// A service name has the form: instance.application-protocol.transport-protocol.domain
80047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// DeconstructServiceName is currently fairly forgiving: It doesn't try to enforce character
80147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// set or length limits for the protocol names, and the final domain is allowed to be empty.
80247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// However, if the given FQDN doesn't contain at least three labels,
80347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// DeconstructServiceName will reject it and return mDNSfalse.
80447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool DeconstructServiceName(const domainname *const fqdn,
80547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainlabel *const name, domainname *const type, domainname *const domain)
80647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
80747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i, len;
80847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *src = fqdn->c;
80947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *max = fqdn->c + MAX_DOMAIN_NAME;
81047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *dst;
81147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
81247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	dst = name->c;										// Extract the service name
81347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
81447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!len)         { debugf("DeconstructServiceName: FQDN empty!");                             return(mDNSfalse); }
81547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len >= 0x40)  { debugf("DeconstructServiceName: Instance name too long");                  return(mDNSfalse); }
81647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=len; i++) *dst++ = *src++;
81747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
81847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	dst = type->c;										// Extract the service type
81947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
82047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!len)         { debugf("DeconstructServiceName: FQDN contains only one label!");           return(mDNSfalse); }
82147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len >= 0x40)  { debugf("DeconstructServiceName: Application protocol name too long");      return(mDNSfalse); }
82247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (src[1] != '_'){ debugf("DeconstructServiceName: No _ at start of application protocol");   return(mDNSfalse); }
82347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=len; i++) *dst++ = *src++;
82447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
82547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
82647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!len)         { debugf("DeconstructServiceName: FQDN contains only two labels!");          return(mDNSfalse); }
82747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ValidTransportProtocol(src))
82847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	                  { debugf("DeconstructServiceName: Transport protocol must be _udp or _tcp"); return(mDNSfalse); }
82947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=len; i++) *dst++ = *src++;
83047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*dst++ = 0;											// Put terminator on the end of service type
83147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
83247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	dst = domain->c;									// Extract the service domain
83347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*src)
83447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
83547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		len = *src;
83647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (len >= 0x40)
83747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{ debugf("DeconstructServiceName: Label in service domain too long"); return(mDNSfalse); }
83847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (src + 1 + len + 1 >= max)
83947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{ debugf("DeconstructServiceName: Total service domain too long"); return(mDNSfalse); }
84047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (i=0; i<=len; i++) *dst++ = *src++;
84147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
84247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*dst++ = 0;		// Put the null root label on the end
84347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
84447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNStrue);
84547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
84647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
84747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Notes on UTF-8:
84847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
84947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 10xxxxxx is a continuation byte of a multi-byte character
85047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 110xxxxx is the first byte of a 2-byte character (11 effective bits; values 0x     80 - 0x     800-1)
85147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1110xxxx is the first byte of a 3-byte character (16 effective bits; values 0x    800 - 0x   10000-1)
85247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 11110xxx is the first byte of a 4-byte character (21 effective bits; values 0x  10000 - 0x  200000-1)
85347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 111110xx is the first byte of a 5-byte character (26 effective bits; values 0x 200000 - 0x 4000000-1)
85447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// 1111110x is the first byte of a 6-byte character (31 effective bits; values 0x4000000 - 0x80000000-1)
85547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
85647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// UTF-16 surrogate pairs are used in UTF-16 to encode values larger than 0xFFFF.
85747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Although UTF-16 surrogate pairs are not supposed to appear in legal UTF-8, we want to be defensive
85847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// about that too. (See <http://www.unicode.org/faq/utf_bom.html#34>, "What are surrogates?")
85947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The first of pair is a UTF-16 value in the range 0xD800-0xDBFF (11101101 1010xxxx 10xxxxxx in UTF-8),
86047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// and the second    is a UTF-16 value in the range 0xDC00-0xDFFF (11101101 1011xxxx 10xxxxxx in UTF-8).
86147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
86247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 TruncateUTF8ToLength(mDNSu8 *string, mDNSu32 length, mDNSu32 max)
86347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
86447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (length > max)
86547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
86647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 c1 = string[max];										// First byte after cut point
86747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 c2 = (max+1 < length) ? string[max+1] : (mDNSu8)0xB0;	// Second byte after cut point
86847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		length = max;	// Trim length down
86947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (length > 0)
87047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
87147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// Check if the byte right after the chop point is a UTF-8 continuation byte,
87247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// or if the character right after the chop point is the second of a UTF-16 surrogate pair.
87347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// If so, then we continue to chop more bytes until we get to a legal chop point.
87447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSBool continuation    = ((c1 & 0xC0) == 0x80);
87547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSBool secondsurrogate = (c1 == 0xED && (c2 & 0xF0) == 0xB0);
87647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!continuation && !secondsurrogate) break;
87747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			c2 = c1;
87847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			c1 = string[--length];
87947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
88047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Having truncated characters off the end of our string, also cut off any residual white space
88147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (length > 0 && string[length-1] <= ' ') length--;
88247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
88347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(length);
88447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
88547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
88647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Returns true if a rich text label ends in " (nnn)", or if an RFC 1034
88747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// name ends in "-nnn", where n is some decimal number.
88847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool LabelContainsSuffix(const domainlabel *const name, const mDNSBool RichText)
88947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
89047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 l = name->c[0];
89147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
89247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RichText)
89347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
89447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (l < 4) return mDNSfalse;							// Need at least " (2)"
89547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (name->c[l--] != ')') return mDNSfalse;				// Last char must be ')'
89647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!mDNSIsDigit(name->c[l])) return mDNSfalse;			// Preceeded by a digit
89747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		l--;
89847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (l > 2 && mDNSIsDigit(name->c[l])) l--;			// Strip off digits
89947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return (name->c[l] == '(' && name->c[l - 1] == ' ');
90047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
90147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
90247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
90347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (l < 2) return mDNSfalse;							// Need at least "-2"
90447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!mDNSIsDigit(name->c[l])) return mDNSfalse;			// Last char must be a digit
90547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		l--;
90647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		while (l > 2 && mDNSIsDigit(name->c[l])) l--;			// Strip off digits
90747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return (name->c[l] == '-');
90847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
90947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
91047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
91147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// removes an auto-generated suffix (appended on a name collision) from a label.  caller is
91247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// responsible for ensuring that the label does indeed contain a suffix.  returns the number
91347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// from the suffix that was removed.
91447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 RemoveLabelSuffix(domainlabel *name, mDNSBool RichText)
91547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
91647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 val = 0, multiplier = 1;
91747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
91847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Chop closing parentheses from RichText suffix
91947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RichText && name->c[0] >= 1 && name->c[name->c[0]] == ')') name->c[0]--;
92047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
92147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Get any existing numerical suffix off the name
92247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (mDNSIsDigit(name->c[name->c[0]]))
92347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ val += (name->c[name->c[0]] - '0') * multiplier; multiplier *= 10; name->c[0]--; }
92447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
92547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Chop opening parentheses or dash from suffix
92647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RichText)
92747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
92847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (name->c[0] >= 2 && name->c[name->c[0]] == '(' && name->c[name->c[0]-1] == ' ') name->c[0] -= 2;
92947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
93047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
93147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
93247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (name->c[0] >= 1 && name->c[name->c[0]] == '-') name->c[0] -= 1;
93347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
93447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
93547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(val);
93647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
93747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
93847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// appends a numerical suffix to a label, with the number following a whitespace and enclosed
93947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// in parentheses (rich text) or following two consecutive hyphens (RFC 1034 domain label).
94047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBool RichText)
94147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
94247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 divisor = 1, chars = 2;	// Shortest possible RFC1034 name suffix is 2 characters ("-2")
94347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RichText) chars = 4;		// Shortest possible RichText suffix is 4 characters (" (2)")
94447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
94547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Truncate trailing spaces from RichText names
94647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RichText) while (name->c[name->c[0]] == ' ') name->c[0]--;
94747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
94847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (divisor < 0xFFFFFFFFUL/10 && val >= divisor * 10) { divisor *= 10; chars++; }
94947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
95047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	name->c[0] = (mDNSu8) TruncateUTF8ToLength(name->c+1, name->c[0], MAX_DOMAIN_LABEL - chars);
95147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
95247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RichText) { name->c[++name->c[0]] = ' '; name->c[++name->c[0]] = '('; }
95347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else          { name->c[++name->c[0]] = '-'; }
95447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
95547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (divisor)
95647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
95747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		name->c[++name->c[0]] = (mDNSu8)('0' + val / divisor);
95847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		val     %= divisor;
95947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		divisor /= 10;
96047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
96147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
96247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RichText) name->c[++name->c[0]] = ')';
96347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
96447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
96547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText)
96647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
96747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 val = 0;
96847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
96947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (LabelContainsSuffix(name, RichText))
97047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		val = RemoveLabelSuffix(name, RichText);
97147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
97247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If no existing suffix, start by renaming "Foo" as "Foo (2)" or "Foo-2" as appropriate.
97347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If existing suffix in the range 2-9, increment it.
97447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If we've had ten conflicts already, there are probably too many hosts trying to use the same name,
97547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// so add a random increment to improve the chances of finding an available name next time.
97647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if      (val == 0) val = 2;
97747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (val < 10) val++;
97847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else               val += 1 + mDNSRandom(99);
97947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AppendLabelSuffix(name, val, RichText);
98147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
98247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
98447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
98547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
98647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Resource Record Utility Functions
98747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
98847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Set up a AuthRecord with sensible default values.
99047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// These defaults may be overwritten with new values before mDNS_Register is called
99147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
99247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context)
99347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
99447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
99547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// LocalOnly auth record can be created with LocalOnly InterfaceID or a valid InterfaceID.
99647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Most of the applications normally create with LocalOnly InterfaceID and we store them as
99747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// such, so that we can deliver the response to questions that specify LocalOnly InterfaceID.
99847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// LocalOnly resource records can also be created with valid InterfaceID which happens today
99947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// when we create LocalOnly records for /etc/hosts.
100047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
100147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (InterfaceID == mDNSInterface_LocalOnly && artype != AuthRecordLocalOnly)
100247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
100347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch LocalOnly record InterfaceID %p called with artype %d", InterfaceID, artype);
100447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return;
100547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
100647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (InterfaceID == mDNSInterface_P2P && artype != AuthRecordP2P)
100747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
100847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch P2P record InterfaceID %p called with artype %d", InterfaceID, artype);
100947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return;
101047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
101147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (!InterfaceID && (artype == AuthRecordP2P || artype == AuthRecordLocalOnly))
101247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
101347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("mDNS_SetupResourceRecord: ERROR!! Mismatch InterfaceAny record InterfaceID %p called with artype %d", InterfaceID, artype);
101447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return;
101547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
101647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
101747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Don't try to store a TTL bigger than we can represent in platform time units
101847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ttl > 0x7FFFFFFFUL / mDNSPlatformOneSecond)
101947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ttl = 0x7FFFFFFFUL / mDNSPlatformOneSecond;
102047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (ttl == 0)		// And Zero TTL is illegal
102147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ttl = DefaultTTLforRRType(rrtype);
102247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
102347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Field Group 1: The actual information pertaining to this resource record
102447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.RecordType        = RecordType;
102547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.InterfaceID       = InterfaceID;
102647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.name              = &rr->namestorage;
102747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rrtype            = rrtype;
102847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rrclass           = kDNSClass_IN;
102947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rroriginalttl     = ttl;
103047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rDNSServer		 = mDNSNULL;
103147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//	rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
103247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//	rr->resrec.rdestimate        = set in mDNS_Register_internal
103347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//	rr->resrec.rdata             = MUST be set by client
103447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
103547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RDataStorage)
103647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->resrec.rdata = RDataStorage;
103747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
103847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
103947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->resrec.rdata = &rr->rdatastorage;
104047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->resrec.rdata->MaxRDLength = sizeof(RDataBody);
104147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
104247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
104347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Field Group 2: Persistent metadata for Authoritative Records
104447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->Additional1       = mDNSNULL;
104547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->Additional2       = mDNSNULL;
104647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->DependentOn       = mDNSNULL;
104747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->RRSet             = mDNSNULL;
104847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->RecordCallback    = Callback;
104947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->RecordContext     = Context;
105047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
105147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->AutoTarget        = Target_Manual;
105247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->AllowRemoteQuery  = mDNSfalse;
105347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->ForceMCast        = mDNSfalse;
105447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
105547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->WakeUp            = zeroOwner;
105647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->AddressProxy      = zeroAddr;
105747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->TimeRcvd          = 0;
105847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->TimeExpire        = 0;
105947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->ARType            = artype;
106047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
106147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Field Group 3: Transient state for Authoritative Records (set in mDNS_Register_internal)
106247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Field Group 4: Transient uDNS state for Authoritative Records (set in mDNS_Register_internal)
106347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
106447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// For now, until the uDNS code is fully integrated, it's helpful to zero the uDNS state fields here too, just in case
106547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// (e.g. uDNS_RegisterService short-circuits the usual mDNS_Register_internal record registration calls, so a bunch
106647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// of fields don't get set up properly. In particular, if we don't zero rr->QueuedRData then the uDNS code crashes.)
106747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->state             = regState_Zero;
106847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->uselease          = 0;
106947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->expire            = 0;
107047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->Private           = 0;
107147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->updateid          = zeroID;
107247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->zone              = rr->resrec.name;
107347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->nta               = mDNSNULL;
107447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->tcp               = mDNSNULL;
107547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->OrigRData         = 0;
107647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->OrigRDLen         = 0;
107747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->InFlightRData     = 0;
107847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->InFlightRDLen     = 0;
107947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->QueuedRData       = 0;
108047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->QueuedRDLen       = 0;
108147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(&rr->NATinfo, sizeof(rr->NATinfo));
108247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->SRVChanged = mDNSfalse;
108347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->mState = mergeState_Zero;
108447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
108547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->namestorage.c[0]  = 0;		// MUST be set by client before calling mDNS_Register()
108647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
108747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
108847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name,
108947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt               const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context)
109047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
109147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->InterfaceID         = InterfaceID;
109247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->Target              = zeroAddr;
109347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AssignDomainName(&q->qname, name);
109447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->qtype               = qtype;
109547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->qclass              = kDNSClass_IN;
109647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->LongLived           = (qtype == kDNSType_PTR);
109747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->ExpectUnique        = (qtype != kDNSType_PTR);
109847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->ForceMCast          = mDNSfalse;
109947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->ReturnIntermed      = mDNSfalse;
110047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->SuppressUnusable    = mDNSfalse;
110147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->SearchListIndex     = 0;
110247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->AppendSearchDomains = 0;
110347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->RetryWithSearchDomains = mDNSfalse;
110447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->TimeoutQuestion     = 0;
110547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->WakeOnResolve       = 0;
110647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->qnameOrig           = mDNSNULL;
110747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->QuestionCallback    = callback;
110847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	q->QuestionContext     = context;
110947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
111047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
111147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
111247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
111347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int len = rr->rdlength;
111447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
111547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch(rr->rrtype)
111647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
111747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:
111847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:
111947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:
112047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DNAME: return DomainNameHashValue(&rdb->name);
112147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
112247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SOA:   return rdb->soa.serial  +
112347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									rdb->soa.refresh +
112447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									rdb->soa.retry   +
112547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									rdb->soa.expire  +
112647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									rdb->soa.min     +
112747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									DomainNameHashValue(&rdb->soa.mname) +
112847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									DomainNameHashValue(&rdb->soa.rname);
112947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
113047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MX:
113147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AFSDB:
113247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RT:
113347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_KX:	 return DomainNameHashValue(&rdb->mx.exchange);
113447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
113547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RP:	 return DomainNameHashValue(&rdb->rp.mbox)   + DomainNameHashValue(&rdb->rp.txt);
113647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
113747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PX:	 return DomainNameHashValue(&rdb->px.map822) + DomainNameHashValue(&rdb->px.mapx400);
113847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
113947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	 return DomainNameHashValue(&rdb->srv.target);
114047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
114147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:	 return 0;	// OPT is a pseudo-RR container structure; makes no sense to compare
114247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
114347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC:	 len = sizeof(rdataNSEC);	// Use in-memory length of 32, and fall through default checksum computation below
114447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
114547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:
114647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
114747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSu32 sum = 0;
114847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			int i;
114947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			for (i=0; i+1 < len; i+=2)
115047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
115147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				sum += (((mDNSu32)(rdb->data[i])) << 8) | rdb->data[i+1];
115247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				sum = (sum<<3) | (sum>>29);
115347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
115447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (i < len)
115547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
115647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				sum += ((mDNSu32)(rdb->data[i])) << 8;
115747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
115847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return(sum);
115947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
116047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
116147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
116247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
116347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// r1 has to be a full ResourceRecord including rrtype and rdlength
116447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// r2 is just a bare RDataBody, which MUST be the same rrtype and rdlength as r1
116547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename)
116647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
116747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const RDataBody2 *const b1 = (RDataBody2 *)r1->rdata->u.data;
116847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const RDataBody2 *const b2 = (RDataBody2 *)r2;
116947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch(r1->rrtype)
117047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
117147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:
117247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:
117347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:
117447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DNAME:return(SameDomainName(&b1->name, &b2->name));
117547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
117647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SOA:	return(mDNSBool)(  	b1->soa.serial   == b2->soa.serial             &&
117747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												b1->soa.refresh  == b2->soa.refresh            &&
117847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												b1->soa.retry    == b2->soa.retry              &&
117947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												b1->soa.expire   == b2->soa.expire             &&
118047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												b1->soa.min      == b2->soa.min                &&
118147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												samename(&b1->soa.mname, &b2->soa.mname) &&
118247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												samename(&b1->soa.rname, &b2->soa.rname));
118347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
118447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MX:
118547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AFSDB:
118647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RT:
118747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_KX:	return(mDNSBool)(  	b1->mx.preference == b2->mx.preference &&
118847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												samename(&b1->mx.exchange, &b2->mx.exchange));
118947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
119047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RP:	return(mDNSBool)(  	samename(&b1->rp.mbox, &b2->rp.mbox) &&
119147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												samename(&b1->rp.txt,  &b2->rp.txt));
119247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
119347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PX:	return(mDNSBool)(  	b1->px.preference == b2->px.preference          &&
119447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												samename(&b1->px.map822,  &b2->px.map822) &&
119547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												samename(&b1->px.mapx400, &b2->px.mapx400));
119647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
119747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	return(mDNSBool)(  	b1->srv.priority == b2->srv.priority       &&
119847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												b1->srv.weight   == b2->srv.weight         &&
119947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												mDNSSameIPPort(b1->srv.port, b2->srv.port) &&
120047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												samename(&b1->srv.target, &b2->srv.target));
120147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
120247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:	return mDNSfalse;	// OPT is a pseudo-RR container structure; makes no sense to compare
120347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
120447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC: return(mDNSPlatformMemSame(b1->data, b2->data, sizeof(rdataNSEC)));
120547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
120647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			return(mDNSPlatformMemSame(b1->data, b2->data, r1->rdlength));
120747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
120847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
120947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
121047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ResourceRecordAnswersQuestion returns mDNStrue if the given resource record is a valid answer to the given question.
121147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// SameNameRecordAnswersQuestion is the same, except it skips the expensive SameDomainName() call.
121247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// SameDomainName() is generally cheap when the names don't match, but expensive when they do match,
121347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// because it has to check all the way to the end of the names to be sure.
121447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// In cases where we know in advance that the names match it's especially advantageous to skip the
121547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// SameDomainName() call because that's precisely the time when it's most expensive and least useful.
121647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
121747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
121847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
121947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
122047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// are handled in LocalOnlyRecordAnswersQuestion
122147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
122247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
122347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
122447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return mDNSfalse;
122547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
122647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID &&
122747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
122847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
122947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
123047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Resource record received via unicast, the DNSServer entries should match ?
123147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
123247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
123347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
123447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
123547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
123647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
123747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
123847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
123947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
124047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNStrue);
124147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
124247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
124347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
124447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
124547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
124647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// are handled in LocalOnlyRecordAnswersQuestion
124747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
124847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
124947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("ResourceRecordAnswersQuestion: ERROR!! called with LocalOnly/P2P ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
125047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return mDNSfalse;
125147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
125247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
125347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID &&
125447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
125547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
125647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
125747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Resource record received via unicast, the DNSServer entries should match ?
125847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
125947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
126047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
126147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
126247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
126347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
126447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
126547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
126647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
126747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
126847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
126947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
127047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We have a separate function to handle LocalOnly AuthRecords because they can be created with
127147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike
127247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// multicast resource records (which has a valid InterfaceID) which can't be used to answer
127347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// unicast questions. ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion can't tell whether
127447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// a resource record is multicast or LocalOnly by just looking at the ResourceRecord because
127547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// LocalOnly records are truly identified by ARType in the AuthRecord.  As P2P and LocalOnly record
127647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// are kept in the same hash table, we use the same function to make it easy for the callers when
127747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// they walk the hash table to answer LocalOnly/P2P questions
127847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
127947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const DNSQuestion *const q)
128047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
128147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ResourceRecord *rr = &ar->resrec;
128247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
128347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// mDNSInterface_Any questions can be answered with LocalOnly/P2P records in this function. AuthRecord_Any
128447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// records are handled in ResourceRecordAnswersQuestion/SameNameRecordAnswersQuestion
128547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (RRAny(ar))
128647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
128747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("LocalOnlyRecordAnswersQuestion: ERROR!! called with regular AuthRecordAny %##s", rr->name->c);
128847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return mDNSfalse;
128947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
129047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
129147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Questions with mDNSInterface_LocalOnly InterfaceID should be answered with all resource records that are
129247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly,
129347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against
129447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// the InterfaceID in the resource record.
129547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
129647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// mDNSInterface_Unicast does not indicate any scope and hence treat them like mDNSInterface_Any.
129747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
129847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID &&
129947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && q->InterfaceID != mDNSInterface_Unicast &&
130047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
130147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
130247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records
130347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set
130447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// to mDNSInterface_Any, mDNSInterface_LocalOnly or a real InterfaceID (scoped).
130547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
130647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// 1) Question: Any, LocalOnly Record: no scope. This question should be answered with this record.
130747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
130847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// 2) Question: Any, LocalOnly Record: scoped.  This question should be answered with the record because
130947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//    traditionally applications never specify scope e.g., getaddrinfo, but need to be able
131047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//    to get to /etc/hosts entries.
131147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
131247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// 3) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: no scope. This is the inverse of (2).
131347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//    If we register a LocalOnly record, we need to answer a LocalOnly question. If the /etc/hosts has a
131447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//    non scoped entry, it may not make sense to answer a scoped question. But we can't tell these two
131547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//    cases apart. As we currently answer LocalOnly question with LocalOnly record, we continue to do so.
131647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
131747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// 4) Question: Scoped (LocalOnly or InterfaceID), LocalOnly Record: scoped. LocalOnly questions should be
131847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//    answered with any resource record where as if it has a valid InterfaceID, the scope should match.
131947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
132047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// (1) and (2) is bypassed because we check for a non-NULL InterfaceID above. For (3), the InterfaceID is NULL
132147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// and hence bypassed above. For (4) we bypassed LocalOnly questions and checked the scope of the record
132247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// against the question.
132347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
132447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// For P2P, InterfaceIDs of the question and the record should match.
132547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
132647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
132747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// LocalOnly authoritative answers are exempt. LocalOnly authoritative answers are used for /etc/host entries.
132847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// We don't want a local process to be able to create a fake LocalOnly address record for "www.bigbank.com" which would then
132947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// cause other applications (e.g. Safari) to connect to the wrong address. The rpc to register records filters out records
133047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// with names that don't end in local and have mDNSInterface_LocalOnly set.
133147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//
133247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Note: The check is bypassed for LocalOnly and for P2P it is not needed as only .local records are registered and for
133347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// a question to match its names, it also has to end in .local and that question can't be a unicast question (See
133447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Question_uDNS macro and its usage). As P2P does not enforce .local only registrations we still make this check
133547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// and also makes it future proof.
133647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
133747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ar->ARType != AuthRecordLocalOnly && rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
133847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
133947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
134047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
134147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
134247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
134347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
134447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
134547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
134647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
134747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
134847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
134947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// are handled in LocalOnlyRecordAnswersQuestion
135047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if ((rr->InterfaceID == mDNSInterface_LocalOnly) || (rr->InterfaceID == mDNSInterface_P2P))
135147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
135247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("AnyTypeRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
135347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return mDNSfalse;
135447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
135547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID &&
135647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		q ->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly &&
135747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
135847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
135947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Resource record received via unicast, the DNSServer entries should match ?
136047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Note that Auth Records are normally setup with NULL InterfaceID and
136147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// both the DNSServers are assumed to be NULL in that case
136247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!rr->InterfaceID && rr->rDNSServer != q->qDNSServer) return(mDNSfalse);
136347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
136447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
136547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
136647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
136747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
136847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
136947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
137047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
137147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
137247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// This is called with both unicast resource record and multicast resource record. The question that
137347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// received the unicast response could be the regular unicast response from a DNS server or a response
137447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// to a mDNS QU query. The main reason we need this function is that we can't compare DNSServers between the
137547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// question and the resource record because the resource record is not completely initialized in
137647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// mDNSCoreReceiveResponse when this function is called.
137747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q)
137847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
137947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// For resource records created using multicast, the InterfaceIDs have to match
138047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID &&
138147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		q->InterfaceID && rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
138247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
138347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question.
138447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->InterfaceID && !mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
138547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
138647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// RR type CNAME matches any query type. QTYPE ANY matches any RR type. QCLASS ANY matches any RR class.
138747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
138847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
138947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
139047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
139147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
139247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
139347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
139447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate)
139547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
139647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const RDataBody2 *const rd = (RDataBody2 *)rr->rdata->u.data;
139747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const domainname *const name = estimate ? rr->name : mDNSNULL;
139847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->rrclass == kDNSQClass_ANY) return(rr->rdlength);	// Used in update packets to mean "Delete An RRset" (RFC 2136)
139947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else switch (rr->rrtype)
140047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
140147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_A:	return(sizeof(rd->ipv4));
140247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
140347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:
140447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:
140547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:
140647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DNAME:return(CompressedDomainNameLength(&rd->name, name));
140747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
140847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SOA:  return(mDNSu16)(CompressedDomainNameLength(&rd->soa.mname, name) +
140947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											CompressedDomainNameLength(&rd->soa.rname, name) +
141047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											5 * sizeof(mDNSOpaque32));
141147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
141247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NULL:
141347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TSIG:
141447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TXT:
141547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_X25:
141647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_ISDN:
141747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_LOC:
141847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DHCID:return(rr->rdlength); // Not self-describing, so have to just trust rdlength
141947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
142047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_HINFO:return(mDNSu16)(2 + (int)rd->data[0] + (int)rd->data[1 + (int)rd->data[0]]);
142147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
142247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MX:
142347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AFSDB:
142447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RT:
142547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_KX:	return(mDNSu16)(2 + CompressedDomainNameLength(&rd->mx.exchange, name));
142647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
142747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RP:	return(mDNSu16)(CompressedDomainNameLength(&rd->rp.mbox, name) +
142847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											CompressedDomainNameLength(&rd->rp.txt, name));
142947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
143047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PX:	return(mDNSu16)(2 + CompressedDomainNameLength(&rd->px.map822, name) +
143147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												CompressedDomainNameLength(&rd->px.mapx400, name));
143247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
143347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AAAA:	return(sizeof(rd->ipv6));
143447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
143547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	return(mDNSu16)(6 + CompressedDomainNameLength(&rd->srv.target, name));
143647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
143747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:  return(rr->rdlength);
143847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
143947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC: {
144047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							int i;
144147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (i=sizeof(rdataNSEC); i>0; i--) if (rd->nsec.bitmap[i-1]) break;
144247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// For our simplified use of NSEC synthetic records:
144347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// nextname is always the record's own name,
144447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// and if we have at least one record type that exists,
144547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							//  - the block number is always 0,
144647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							//  - the count byte is a value in the range 1-32,
144747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							//  - followed by the 1-32 data bytes
144847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(mDNSu16)((estimate ? 2 : DomainNameLength(rr->name)) + (i ? (2 + i) : 0));
144947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
145047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
145147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			debugf("Warning! Don't know how to get length of resource type %d", rr->rrtype);
145247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(rr->rdlength);
145347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
145447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
145547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
145647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// When a local client registers (or updates) a record, we use this routine to do some simple validation checks
145747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// to help reduce the risk of bogus malformed data on the network
145847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool ValidateRData(const mDNSu16 rrtype, const mDNSu16 rdlength, const RData *const rd)
145947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
146047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 len;
146147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
146247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch(rrtype)
146347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
146447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_A:	return(rdlength == sizeof(mDNSv4Addr));
146547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
146647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:	// Same as PTR
146747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MD:	// Same as PTR
146847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MF:	// Same as PTR
146947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:// Same as PTR
147047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		//case kDNSType_SOA not checked
147147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MB:	// Same as PTR
147247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MG:	// Same as PTR
147347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MR:	// Same as PTR
147447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		//case kDNSType_NULL not checked (no specified format, so always valid)
147547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		//case kDNSType_WKS not checked
147647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:	len = DomainNameLengthLimit(&rd->u.name, rd->u.data + rdlength);
147747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(len <= MAX_DOMAIN_NAME && rdlength == len);
147847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
147947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_HINFO:// Same as TXT (roughly)
148047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MINFO:// Same as TXT (roughly)
148147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TXT:  if (!rdlength) return(mDNSfalse); // TXT record has to be at least one byte (RFC 1035)
148247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							{
148347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							const mDNSu8 *ptr = rd->u.txt.c;
148447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							const mDNSu8 *end = rd->u.txt.c + rdlength;
148547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							while (ptr < end) ptr += 1 + ptr[0];
148647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return (ptr == end);
148747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
148847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
148947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AAAA:	return(rdlength == sizeof(mDNSv6Addr));
149047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
149147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MX:   // Must be at least two-byte preference, plus domainname
149247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// Call to DomainNameLengthLimit() implicitly enforces both requirements for us
149347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							len = DomainNameLengthLimit(&rd->u.mx.exchange, rd->u.data + rdlength);
149447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(len <= MAX_DOMAIN_NAME && rdlength == 2+len);
149547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
149647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	// Must be at least priority+weight+port, plus domainname
149747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// Call to DomainNameLengthLimit() implicitly enforces both requirements for us
149847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							len = DomainNameLengthLimit(&rd->u.srv.target, rd->u.data + rdlength);
149947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(len <= MAX_DOMAIN_NAME && rdlength == 6+len);
150047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
150147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		//case kDNSType_NSEC not checked
150247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
150347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			return(mDNStrue);	// Allow all other types without checking
150447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
150547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
150647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
150747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
150847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
150947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
151047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - DNS Message Creation Functions
151147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
151247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
151347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void InitializeDNSMessage(DNSMessageHeader *h, mDNSOpaque16 id, mDNSOpaque16 flags)
151447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
151547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	h->id             = id;
151647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	h->flags          = flags;
151747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	h->numQuestions   = 0;
151847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	h->numAnswers     = 0;
151947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	h->numAuthorities = 0;
152047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	h->numAdditionals = 0;
152147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
152247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
152347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *FindCompressionPointer(const mDNSu8 *const base, const mDNSu8 *const end, const mDNSu8 *const domname)
152447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
152547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *result = end - *domname - 1;
152647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
152747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (*domname == 0) return(mDNSNULL);	// There's no point trying to match just the root label
152847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
152947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// This loop examines each possible starting position in packet, starting end of the packet and working backwards
153047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (result >= base)
153147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
153247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// If the length byte and first character of the label match, then check further to see
153347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// if this location in the packet will yield a useful name compression pointer.
153447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (result[0] == domname[0] && result[1] == domname[1])
153547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
153647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			const mDNSu8 *name = domname;
153747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			const mDNSu8 *targ = result;
153847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			while (targ + *name < end)
153947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
154047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// First see if this label matches
154147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				int i;
154247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				const mDNSu8 *pointertarget;
154347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				for (i=0; i <= *name; i++) if (targ[i] != name[i]) break;
154447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (i <= *name) break;							// If label did not match, bail out
154547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				targ += 1 + *name;								// Else, did match, so advance target pointer
154647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				name += 1 + *name;								// and proceed to check next label
154747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (*name == 0 && *targ == 0) return(result);	// If no more labels, we found a match!
154847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (*name == 0) break;							// If no more labels to match, we failed, so bail out
154947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
155047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// The label matched, so now follow the pointer (if appropriate) and then see if the next label matches
155147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (targ[0] < 0x40) continue;					// If length value, continue to check next label
155247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (targ[0] < 0xC0) break;						// If 40-BF, not valid
155347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (targ+1 >= end) break;						// Second byte not present!
155447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				pointertarget = base + (((mDNSu16)(targ[0] & 0x3F)) << 8) + targ[1];
155547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (targ < pointertarget) break;				// Pointertarget must point *backwards* in the packet
155647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (pointertarget[0] >= 0x40) break;			// Pointertarget must point to a valid length byte
155747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				targ = pointertarget;
155847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
155947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
156047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		result--;	// We failed to match at this search position, so back up the tentative result pointer and try again
156147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
156247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSNULL);
156347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
156447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
156547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Put a string of dot-separated labels as length-prefixed labels
156647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// domainname is a fully-qualified name (i.e. assumed to be ending in a dot, even if it doesn't)
156747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
156847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// end points to the end of the message so far
156947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ptr points to where we want to put the name
157047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// limit points to one byte past the end of the buffer that we must not overrun
157147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// domainname is the name to put
157247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putDomainNameAsLabels(const DNSMessage *const msg,
157347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name)
157447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
157547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const base        = (const mDNSu8 *)msg;
157647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *      np          = name->c;
157747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const max         = name->c + MAX_DOMAIN_NAME;	// Maximum that's valid
157847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *      pointer     = mDNSNULL;
157947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const searchlimit = ptr;
158047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
158147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { LogMsg("putDomainNameAsLabels %##s ptr is null", name->c); return(mDNSNULL); }
158247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
158347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!*np)		// If just writing one-byte root label, make sure we have space for that
158447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
158547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr >= limit) return(mDNSNULL);
158647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
158747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else			// else, loop through writing labels and/or a compression offset
158847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
158947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		do	{
159047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (*np > MAX_DOMAIN_LABEL)
159147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ LogMsg("Malformed domain name %##s (label more than 63 bytes)", name->c); return(mDNSNULL); }
159247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
159347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// This check correctly allows for the final trailing root label:
159447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// e.g.
159547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// Suppose our domain name is exactly 256 bytes long, including the final trailing root label.
159647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// Suppose np is now at name->c[249], and we're about to write our last non-null label ("local").
159747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// We know that max will be at name->c[256]
159847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// That means that np + 1 + 5 == max - 1, so we (just) pass the "if" test below, write our
159947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// six bytes, then exit the loop, write the final terminating root label, and the domain
160047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// name we've written is exactly 256 bytes long, exactly at the correct legal limit.
160147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// If the name is one byte longer, then we fail the "if" test below, and correctly bail out.
160247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (np + 1 + *np >= max)
160347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ LogMsg("Malformed domain name %##s (more than 256 bytes)", name->c); return(mDNSNULL); }
160447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
160547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (base) pointer = FindCompressionPointer(base, searchlimit, np);
160647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (pointer)					// Use a compression pointer if we can
160747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
160847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				const mDNSu16 offset = (mDNSu16)(pointer - base);
160947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (ptr+2 > limit) return(mDNSNULL);	// If we don't have two bytes of space left, give up
161047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr++ = (mDNSu8)(0xC0 | (offset >> 8));
161147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr++ = (mDNSu8)(        offset &  0xFF);
161247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				return(ptr);
161347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
161447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else							// Else copy one label and try again
161547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
161647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				int i;
161747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				mDNSu8 len = *np++;
161847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				// If we don't at least have enough space for this label *plus* a terminating zero on the end, give up
161947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (ptr + 1 + len >= limit) return(mDNSNULL);
162047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*ptr++ = len;
162147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				for (i=0; i<len; i++) *ptr++ = *np++;
162247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
162347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			} while (*np);					// While we've got characters remaining in the name, continue
162447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
162547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
162647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = 0;		// Put the final root label
162747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);
162847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
162947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
163047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu8 *putVal16(mDNSu8 *ptr, mDNSu16 val)
163147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
163247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)((val >> 8 ) & 0xFF);
163347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)((val      ) & 0xFF);
163447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr + sizeof(mDNSOpaque16);
163547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
163647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
163747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu8 *putVal32(mDNSu8 *ptr, mDNSu32 val)
163847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
163947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)((val >> 24) & 0xFF);
164047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)((val >> 16) & 0xFF);
164147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[2] = (mDNSu8)((val >>  8) & 0xFF);
164247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[3] = (mDNSu8)((val      ) & 0xFF);
164347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr + sizeof(mDNSu32);
164447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
164547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
164647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// msg points to the message we're building (pass mDNSNULL if we don't want to use compression pointers)
164747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putRData(const DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const ResourceRecord *const rr)
164847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
164947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const RDataBody2 *const rdb = (RDataBody2 *)rr->rdata->u.data;
165047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch (rr->rrtype)
165147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
165247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_A:	if (rr->rdlength != 4)
165347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{ debugf("putRData: Illegal length %d for kDNSType_A", rr->rdlength); return(mDNSNULL); }
165447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr + 4 > limit) return(mDNSNULL);
165547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = rdb->ipv4.b[0];
165647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = rdb->ipv4.b[1];
165747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = rdb->ipv4.b[2];
165847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = rdb->ipv4.b[3];
165947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(ptr);
166047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
166147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:
166247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:
166347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:
166447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DNAME:return(putDomainNameAsLabels(msg, ptr, limit, &rdb->name));
166547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
166647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SOA:  ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.mname);
166747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr) return(mDNSNULL);
166847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->soa.rname);
166947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr || ptr + 20 > limit) return(mDNSNULL);
167047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putVal32(ptr, rdb->soa.serial);
167147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putVal32(ptr, rdb->soa.refresh);
167247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putVal32(ptr, rdb->soa.retry);
167347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putVal32(ptr, rdb->soa.expire);
167447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putVal32(ptr, rdb->soa.min);
167547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			                return(ptr);
167647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
167747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NULL:
167847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_HINFO:
167947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TSIG:
168047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TXT:
168147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_X25:
168247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_ISDN:
168347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_LOC:
168447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DHCID:if (ptr + rr->rdlength > limit) return(mDNSNULL);
168547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
168647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(ptr + rr->rdlength);
168747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
168847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MX:
168947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AFSDB:
169047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RT:
169147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_KX:	if (ptr + 3 > limit) return(mDNSNULL);
169247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putVal16(ptr, rdb->mx.preference);
169347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(putDomainNameAsLabels(msg, ptr, limit, &rdb->mx.exchange));
169447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
169547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RP:	ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.mbox);
169647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr) return(mDNSNULL);
169747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->rp.txt);
169847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			                return(ptr);
169947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
170047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PX:	if (ptr + 5 > limit) return(mDNSNULL);
170147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putVal16(ptr, rdb->px.preference);
170247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.map822);
170347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr) return(mDNSNULL);
170447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putDomainNameAsLabels(msg, ptr, limit, &rdb->px.mapx400);
170547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			                return(ptr);
170647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
170747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AAAA:	if (rr->rdlength != sizeof(rdb->ipv6))
170847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{ debugf("putRData: Illegal length %d for kDNSType_AAAA", rr->rdlength); return(mDNSNULL); }
170947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr + sizeof(rdb->ipv6) > limit) return(mDNSNULL);
171047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSPlatformMemCopy(ptr, &rdb->ipv6, sizeof(rdb->ipv6));
171147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(ptr + sizeof(rdb->ipv6));
171247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
171347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	if (ptr + 7 > limit) return(mDNSNULL);
171447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = (mDNSu8)(rdb->srv.priority >> 8);
171547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = (mDNSu8)(rdb->srv.priority &  0xFF);
171647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = (mDNSu8)(rdb->srv.weight   >> 8);
171747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = (mDNSu8)(rdb->srv.weight   &  0xFF);
171847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = rdb->srv.port.b[0];
171947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*ptr++ = rdb->srv.port.b[1];
172047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(putDomainNameAsLabels(msg, ptr, limit, &rdb->srv.target));
172147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
172247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:	{
172347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							int len = 0;
172447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							const rdataOPT *opt;
172547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							const rdataOPT *const end = (const rdataOPT *)&rr->rdata->u.data[rr->rdlength];
172647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (opt = &rr->rdata->u.opt[0]; opt < end; opt++) len += DNSOpt_Data_Space(opt);
172747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr + len > limit) { LogMsg("ERROR: putOptRData - out of space"); return mDNSNULL; }
172847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
172947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (opt = &rr->rdata->u.opt[0]; opt < end; opt++)
173047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
173147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								const int space = DNSOpt_Data_Space(opt);
173247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								ptr = putVal16(ptr, opt->opt);
173347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								ptr = putVal16(ptr, (mDNSu16)space - 4);
173447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								switch (opt->opt)
173547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
173647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_LLQ:
173747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										ptr = putVal16(ptr, opt->u.llq.vers);
173847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										ptr = putVal16(ptr, opt->u.llq.llqOp);
173947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										ptr = putVal16(ptr, opt->u.llq.err);
174047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										mDNSPlatformMemCopy(ptr, opt->u.llq.id.b, 8);  // 8-byte id
174147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										ptr += 8;
174247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										ptr = putVal32(ptr, opt->u.llq.llqlease);
174347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
174447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_Lease:
174547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										ptr = putVal32(ptr, opt->u.updatelease);
174647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
174747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_Owner:
174847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										*ptr++ = opt->u.owner.vers;
174947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										*ptr++ = opt->u.owner.seq;
175047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										mDNSPlatformMemCopy(ptr, opt->u.owner.HMAC.b, 6);  // 6-byte Host identifier
175147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										ptr += 6;
175247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										if (space >= DNSOpt_OwnerData_ID_Wake_Space)
175347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											{
175447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											mDNSPlatformMemCopy(ptr, opt->u.owner.IMAC.b, 6);	// 6-byte interface MAC
175547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											ptr += 6;
175647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (space > DNSOpt_OwnerData_ID_Wake_Space)
175747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												{
175847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												mDNSPlatformMemCopy(ptr, opt->u.owner.password.b, space - DNSOpt_OwnerData_ID_Wake_Space);
175947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												ptr += space - DNSOpt_OwnerData_ID_Wake_Space;
176047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												}
176147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											}
176247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
176347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
176447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
176547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return ptr;
176647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
176747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
176847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC: {
176947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// For our simplified use of NSEC synthetic records:
177047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// nextname is always the record's own name,
177147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// the block number is always 0,
177247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// the count byte is a value in the range 1-32,
177347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// followed by the 1-32 data bytes
177447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							int i, j;
177547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (i=sizeof(rdataNSEC); i>0; i--) if (rdb->nsec.bitmap[i-1]) break;
177647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
177747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr) return(mDNSNULL);
177847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (i)		// Only put a block if at least one type exists for this name
177947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
178047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (ptr + 2 + i > limit) return(mDNSNULL);
178147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								*ptr++ = 0;
178247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								*ptr++ = (mDNSu8)i;
178347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								for (j=0; j<i; j++) *ptr++ = rdb->nsec.bitmap[j];
178447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
178547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return ptr;
178647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
178747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
178847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			debugf("putRData: Warning! Writing unknown resource type %d as raw data", rr->rrtype);
178947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr + rr->rdlength > limit) return(mDNSNULL);
179047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSPlatformMemCopy(ptr, rdb->data, rr->rdlength);
179147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							return(ptr + rr->rdlength);
179247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
179347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
179447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
179547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define IsUnicastUpdate(X) (!mDNSOpaque16IsZero((X)->h.id) && ((X)->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update)
179647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
179747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *PutResourceRecordTTLWithLimit(DNSMessage *const msg, mDNSu8 *ptr, mDNSu16 *count, ResourceRecord *rr, mDNSu32 ttl, const mDNSu8 *limit)
179847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
179947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *endofrdata;
180047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 actualLength;
180147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// When sending SRV to conventional DNS server (i.e. in DNS update requests) we should not do name compression on the rdata (RFC 2782)
180247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const DNSMessage *const rdatacompressionbase = (IsUnicastUpdate(msg) && rr->rrtype == kDNSType_SRV) ? mDNSNULL : msg;
180347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
180447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->RecordType == kDNSRecordTypeUnregistered)
180547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
180647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("PutResourceRecord ERROR! Attempt to put kDNSRecordTypeUnregistered %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
180747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return(ptr);
180847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
180947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
181047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { LogMsg("PutResourceRecordTTLWithLimit ptr is null"); return(mDNSNULL); }
181147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
181247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDomainNameAsLabels(msg, ptr, limit, rr->name);
181347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr || ptr + 10 >= limit) return(mDNSNULL);	// If we're out-of-space, return mDNSNULL
181447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)(rr->rrtype  >> 8);
181547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)(rr->rrtype  &  0xFF);
181647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[2] = (mDNSu8)(rr->rrclass >> 8);
181747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[3] = (mDNSu8)(rr->rrclass &  0xFF);
181847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[4] = (mDNSu8)((ttl >> 24) &  0xFF);
181947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[5] = (mDNSu8)((ttl >> 16) &  0xFF);
182047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[6] = (mDNSu8)((ttl >>  8) &  0xFF);
182147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[7] = (mDNSu8)( ttl        &  0xFF);
182247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// ptr[8] and ptr[9] filled in *after* we find out how much space the rdata takes
182347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
182447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	endofrdata = putRData(rdatacompressionbase, ptr+10, limit, rr);
182547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!endofrdata) { verbosedebugf("Ran out of space in PutResourceRecord for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype)); return(mDNSNULL); }
182647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
182747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Go back and fill in the actual number of data bytes we wrote
182847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// (actualLength can be less than rdlength when domain name compression is used)
182947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	actualLength = (mDNSu16)(endofrdata - ptr - 10);
183047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[8] = (mDNSu8)(actualLength >> 8);
183147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[9] = (mDNSu8)(actualLength &  0xFF);
183247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
183347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (count) (*count)++;
183447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else LogMsg("PutResourceRecordTTL: ERROR: No target count to update for %##s (%s)", rr->name->c, DNSTypeName(rr->rrtype));
183547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(endofrdata);
183647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
183747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
183847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu8 *putEmptyResourceRecord(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, mDNSu16 *count, const AuthRecord *rr)
183947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
184047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDomainNameAsLabels(msg, ptr, limit, rr->resrec.name);
184147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr || ptr + 10 > limit) return(mDNSNULL);		// If we're out-of-space, return mDNSNULL
184247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)(rr->resrec.rrtype  >> 8);				// Put type
184347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)(rr->resrec.rrtype  &  0xFF);
184447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[2] = (mDNSu8)(rr->resrec.rrclass >> 8);				// Put class
184547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[3] = (mDNSu8)(rr->resrec.rrclass &  0xFF);
184647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0;				// TTL is zero
184747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[8] = ptr[9] = 0;								// RDATA length is zero
184847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(*count)++;
184947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr + 10);
185047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
185147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
185247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putQuestion(DNSMessage *const msg, mDNSu8 *ptr, const mDNSu8 *const limit, const domainname *const name, mDNSu16 rrtype, mDNSu16 rrclass)
185347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
185447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDomainNameAsLabels(msg, ptr, limit, name);
185547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr || ptr+4 >= limit) return(mDNSNULL);			// If we're out-of-space, return mDNSNULL
185647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)(rrtype  >> 8);
185747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)(rrtype  &  0xFF);
185847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[2] = (mDNSu8)(rrclass >> 8);
185947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[3] = (mDNSu8)(rrclass &  0xFF);
186047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.numQuestions++;
186147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr+4);
186247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
186347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
186447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for dynamic updates
186547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putZone(DNSMessage *const msg, mDNSu8 *ptr, mDNSu8 *limit, const domainname *zone, mDNSOpaque16 zoneClass)
186647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
186747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDomainNameAsLabels(msg, ptr, limit, zone);
186847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr || ptr + 4 > limit) return mDNSNULL;		// If we're out-of-space, return NULL
186947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(kDNSType_SOA  >> 8);
187047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = (mDNSu8)(kDNSType_SOA  &  0xFF);
187147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = zoneClass.b[0];
187247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*ptr++ = zoneClass.b[1];
187347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.mDNS_numZones++;
187447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr;
187547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
187647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
187747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for dynamic updates
187847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putPrereqNameNotInUse(const domainname *const name, DNSMessage *const msg, mDNSu8 *const ptr, mDNSu8 *const end)
187947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
188047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord prereq;
188147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_SetupResourceRecord(&prereq, mDNSNULL, mDNSInterface_Any, kDNSQType_ANY, kStandardTTL, 0, AuthRecordAny, mDNSNULL, mDNSNULL);
188247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AssignDomainName(&prereq.namestorage, name);
188347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	prereq.resrec.rrtype = kDNSQType_ANY;
188447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	prereq.resrec.rrclass = kDNSClass_NONE;
188547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return putEmptyResourceRecord(msg, ptr, end, &msg->h.mDNS_numPrereqs, &prereq);
188647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
188747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
188847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for dynamic updates
188947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putDeletionRecord(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr)
189047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
189147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// deletion: specify record w/ TTL 0, class NONE
189247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu16 origclass = rr->rrclass;
189347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->rrclass = kDNSClass_NONE;
189447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = PutResourceRecordTTLJumbo(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0);
189547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->rrclass = origclass;
189647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr;
189747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
189847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
189947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for dynamic updates
190047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putDeletionRecordWithLimit(DNSMessage *msg, mDNSu8 *ptr, ResourceRecord *rr, mDNSu8 *limit)
190147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
190247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// deletion: specify record w/ TTL 0, class NONE
190347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu16 origclass = rr->rrclass;
190447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->rrclass = kDNSClass_NONE;
190547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = PutResourceRecordTTLWithLimit(msg, ptr, &msg->h.mDNS_numUpdates, rr, 0, limit);
190647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->rrclass = origclass;
190747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr;
190847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
190947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
191047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putDeleteRRSetWithLimit(DNSMessage *msg, mDNSu8 *ptr, const domainname *name, mDNSu16 rrtype, mDNSu8 *limit)
191147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
191247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 class = kDNSQClass_ANY;
191347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
191447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDomainNameAsLabels(msg, ptr, limit, name);
191547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr || ptr + 10 >= limit) return mDNSNULL;	// If we're out-of-space, return mDNSNULL
191647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)(rrtype  >> 8);
191747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)(rrtype  &  0xFF);
191847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[2] = (mDNSu8)(class >> 8);
191947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[3] = (mDNSu8)(class &  0xFF);
192047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
192147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[8] = ptr[9] = 0; // zero rdlength/rdata
192247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
192347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.mDNS_numUpdates++;
192447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr + 10;
192547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
192647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
192747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for dynamic updates
192847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname *name)
192947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
193047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
193147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 class = kDNSQClass_ANY;
193247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 rrtype = kDNSQType_ANY;
193347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
193447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = putDomainNameAsLabels(msg, ptr, limit, name);
193547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr || ptr + 10 >= limit) return mDNSNULL;	// If we're out-of-space, return mDNSNULL
193647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[0] = (mDNSu8)(rrtype >> 8);
193747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[1] = (mDNSu8)(rrtype &  0xFF);
193847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[2] = (mDNSu8)(class  >> 8);
193947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[3] = (mDNSu8)(class  &  0xFF);
194047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[4] = ptr[5] = ptr[6] = ptr[7] = 0; // zero ttl
194147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr[8] = ptr[9] = 0; // zero rdlength/rdata
194247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
194347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.mDNS_numUpdates++;
194447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return ptr + 10;
194547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
194647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
194747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for dynamic updates
194847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease)
194947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
195047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord rr;
195147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
195247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rrclass    = NormalMaxDNSMessageData;
195347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
195447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdestimate = sizeof(rdataOPT);
195547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
195647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdata->u.opt[0].u.updatelease = lease;
195747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = PutResourceRecordTTLJumbo(msg, end, &msg->h.numAdditionals, &rr.resrec, 0);
195847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTL"); return mDNSNULL; }
195947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return end;
196047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
196147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
196247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// for dynamic updates
196347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *end, mDNSu32 lease, mDNSu8 *limit)
196447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
196547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord rr;
196647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_SetupResourceRecord(&rr, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
196747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rrclass    = NormalMaxDNSMessageData;
196847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdlength   = sizeof(rdataOPT);	// One option in this OPT record
196947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdestimate = sizeof(rdataOPT);
197047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
197147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr.resrec.rdata->u.opt[0].u.updatelease = lease;
197247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &rr.resrec, 0, limit);
197347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { LogMsg("ERROR: putUpdateLease - PutResourceRecordTTLWithLimit"); return mDNSNULL; }
197447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return end;
197547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
197647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
197747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo, mDNSu8 *limit)
197847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
197947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (authInfo && authInfo->AutoTunnel)
198047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
198147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AuthRecord hinfo;
198247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *h = hinfo.rdatastorage.u.data;
198347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu16 len = 2 + m->HIHardware.c[0] + m->HISoftware.c[0];
198447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *newptr;
198547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_SetupResourceRecord(&hinfo, mDNSNULL, mDNSInterface_Any, kDNSType_HINFO, 0, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
198647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AppendDomainLabel(&hinfo.namestorage, &m->hostlabel);
198747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		AppendDomainName (&hinfo.namestorage, &authInfo->domain);
198847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		hinfo.resrec.rroriginalttl = 0;
198947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformMemCopy(h, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
199047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		h += 1 + (int)h[0];
199147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPlatformMemCopy(h, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
199247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		hinfo.resrec.rdlength   = len;
199347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		hinfo.resrec.rdestimate = len;
199447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		newptr = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &hinfo.resrec, 0, limit);
199547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return newptr;
199647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
199747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
199847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return end;
199947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
200047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
200147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
200247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
200347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
200447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - DNS Message Parsing Functions
200547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
200647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
200747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 DomainNameHashValue(const domainname *const name)
200847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
200947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 sum = 0;
201047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *c;
201147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
201247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (c = name->c; c[0] != 0 && c[1] != 0; c += 2)
201347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
201447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8) |
201547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				(mDNSIsUpperCase(c[1]) ? c[1] + 'a' - 'A' : c[1]);
201647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		sum = (sum<<3) | (sum>>29);
201747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
201847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (c[0]) sum += ((mDNSIsUpperCase(c[0]) ? c[0] + 'a' - 'A' : c[0]) << 8);
201947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(sum);
202047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
202147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
202247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void SetNewRData(ResourceRecord *const rr, RData *NewRData, mDNSu16 rdlength)
202347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
202447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname *target;
202547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (NewRData)
202647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
202747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->rdata    = NewRData;
202847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->rdlength = rdlength;
202947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
203047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Must not try to get target pointer until after updating rr->rdata
203147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	target = GetRRDomainNameTarget(rr);
203247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->rdlength   = GetRDLength(rr, mDNSfalse);
203347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->rdestimate = GetRDLength(rr, mDNStrue);
203447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->rdatahash  = target ? DomainNameHashValue(target) : RDataHashValue(rr);
203547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
203647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
203747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *skipDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end)
203847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
203947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 total = 0;
204047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
204147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr < (mDNSu8*)msg || ptr >= end)
204247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ debugf("skipDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
204347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
204447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (1)						// Read sequence of labels
204547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
204647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 len = *ptr++;	// Read length of this label
204747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (len == 0) return(ptr);	// If length is zero, that means this name is complete
204847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		switch (len & 0xC0)
204947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
205047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0x00:	if (ptr + len >= end)					// Remember: expect at least one more byte for the root label
205147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							{ debugf("skipDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
205247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						if (total + 1 + len >= MAX_DOMAIN_NAME)	// Remember: expect at least one more byte for the root label
205347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							{ debugf("skipDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
205447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						ptr += len;
205547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						total += 1 + len;
205647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						break;
205747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
205847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0x40:	debugf("skipDomainName: Extended EDNS0 label types 0x%X not supported", len); return(mDNSNULL);
205947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0x80:	debugf("skipDomainName: Illegal label length 0x%X", len); return(mDNSNULL);
206047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0xC0:	return(ptr+1);
206147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
206247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
206347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
206447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
206547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Routine to fetch an FQDN from the DNS message, following compression pointers if necessary.
206647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *getDomainName(const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end,
206747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname *const name)
206847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
206947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *nextbyte = mDNSNULL;					// Record where we got to before we started following pointers
207047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8       *np = name->c;							// Name pointer
207147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const limit = np + MAX_DOMAIN_NAME;	// Limit so we don't overrun buffer
207247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
207347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr < (mDNSu8*)msg || ptr >= end)
207447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ debugf("getDomainName: Illegal ptr not within packet boundaries"); return(mDNSNULL); }
207547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
207647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*np = 0;						// Tentatively place the root label here (may be overwritten if we have more labels)
207747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
207847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (1)						// Read sequence of labels
207947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
208047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 len = *ptr++;	// Read length of this label
208147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (len == 0) break;		// If length is zero, that means this name is complete
208247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		switch (len & 0xC0)
208347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
208447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			int i;
208547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSu16 offset;
208647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
208747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0x00:	if (ptr + len >= end)		// Remember: expect at least one more byte for the root label
208847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							{ debugf("getDomainName: Malformed domain name (overruns packet end)"); return(mDNSNULL); }
208947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						if (np + 1 + len >= limit)	// Remember: expect at least one more byte for the root label
209047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							{ debugf("getDomainName: Malformed domain name (more than 256 characters)"); return(mDNSNULL); }
209147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						*np++ = len;
209247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						for (i=0; i<len; i++) *np++ = *ptr++;
209347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						*np = 0;	// Tentatively place the root label here (may be overwritten if we have more labels)
209447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						break;
209547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
209647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0x40:	debugf("getDomainName: Extended EDNS0 label types 0x%X not supported in name %##s", len, name->c);
209747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						return(mDNSNULL);
209847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
209947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0x80:	debugf("getDomainName: Illegal label length 0x%X in domain name %##s", len, name->c); return(mDNSNULL);
210047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
210147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			case 0xC0:	offset = (mDNSu16)((((mDNSu16)(len & 0x3F)) << 8) | *ptr++);
210247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						if (!nextbyte) nextbyte = ptr;	// Record where we got to before we started following pointers
210347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						ptr = (mDNSu8 *)msg + offset;
210447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						if (ptr < (mDNSu8*)msg || ptr >= end)
210547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							{ debugf("getDomainName: Illegal compression pointer not within packet boundaries"); return(mDNSNULL); }
210647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						if (*ptr & 0xC0)
210747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							{ debugf("getDomainName: Compression pointer must point to real label"); return(mDNSNULL); }
210847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						break;
210947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
211047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
211147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
211247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (nextbyte) return(nextbyte);
211347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else return(ptr);
211447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
211547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
211647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *skipResourceRecord(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
211747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
211847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 pktrdlength;
211947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
212047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = skipDomainName(msg, ptr, end);
212147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { debugf("skipResourceRecord: Malformed RR name"); return(mDNSNULL); }
212247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
212347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr + 10 > end) { debugf("skipResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
212447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pktrdlength = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
212547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr += 10;
212647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr + pktrdlength > end) { debugf("skipResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
212747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
212847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr + pktrdlength);
212947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
213047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
213147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr,
213247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    const mDNSu8 *end, const mDNSInterfaceID InterfaceID, mDNSu8 RecordType, LargeCacheRecord *const largecr)
213347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
213447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CacheRecord *const rr = &largecr->r;
213547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	RDataBody2 *const rdb = (RDataBody2 *)rr->smallrdatastorage.data;
213647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu16 pktrdlength;
213747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
213847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (largecr == &m->rec && m->rec.r.resrec.RecordType)
213947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
214047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
214147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts
214247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*(long*)0 = 0;
214347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
214447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
214547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
214647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->next              = mDNSNULL;
214747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.name       = &largecr->namestorage;
214847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
214947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->NextInKAList      = mDNSNULL;
215047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->TimeRcvd          = m ? m->timenow : 0;
215147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->DelayDelivery     = 0;
215247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->NextRequiredQuery = m ? m->timenow : 0;		// Will be updated to the real value when we call SetNextCacheCheckTimeForRecord()
215347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->LastUsed          = m ? m->timenow : 0;
215447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->CRActiveQuestion  = mDNSNULL;
215547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->UnansweredQueries = 0;
215647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->LastUnansweredTime= 0;
215747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
215847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->MPUnansweredQ     = 0;
215947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->MPLastUnansweredQT= 0;
216047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->MPUnansweredKA    = 0;
216147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->MPExpectingKA     = mDNSfalse;
216247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
216347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->NextInCFList      = mDNSNULL;
216447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
216547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.InterfaceID       = InterfaceID;
216647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rDNSServer = mDNSNULL;
216747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
216847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = getDomainName(msg, ptr, end, &largecr->namestorage);		// Will bail out correctly if ptr is NULL
216947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { debugf("GetLargeResourceRecord: Malformed RR name"); return(mDNSNULL); }
217047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
217147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
217247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr + 10 > end) { debugf("GetLargeResourceRecord: Malformed RR -- no type/class/ttl/len!"); return(mDNSNULL); }
217347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
217447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rrtype            = (mDNSu16) ((mDNSu16)ptr[0] <<  8 | ptr[1]);
217547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rrclass           = (mDNSu16)(((mDNSu16)ptr[2] <<  8 | ptr[3]) & kDNSClass_Mask);
217647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rroriginalttl     = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
217747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->resrec.rroriginalttl > 0x70000000UL / mDNSPlatformOneSecond && (mDNSs32)rr->resrec.rroriginalttl != -1)
217847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->resrec.rroriginalttl = 0x70000000UL / mDNSPlatformOneSecond;
217947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Note: We don't have to adjust m->NextCacheCheck here -- this is just getting a record into memory for
218047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// us to look at. If we decide to copy it into the cache, then we'll update m->NextCacheCheck accordingly.
218147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	pktrdlength           = (mDNSu16)((mDNSu16)ptr[8] <<  8 | ptr[9]);
218247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
218347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If mDNS record has cache-flush bit set, we mark it unique
218447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// For uDNS records, all are implicitly deemed unique (a single DNS server is always
218547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// authoritative for the entire RRSet), unless this is a truncated response
218647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr[2] & (kDNSClass_UniqueRRSet >> 8) || (!InterfaceID && !(msg->h.flags.b[0] & kDNSFlag0_TC)))
218747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		RecordType |= kDNSRecordTypePacketUniqueMask;
218847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr += 10;
218947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr + pktrdlength > end) { debugf("GetLargeResourceRecord: RDATA exceeds end of packet"); return(mDNSNULL); }
219047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	end = ptr + pktrdlength;		// Adjust end to indicate the end of the rdata for this resource record
219147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
219247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rdata = (RData*)&rr->smallrdatastorage;
219347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rdata->MaxRDLength = MaximumRDSize;
219447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
219547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!RecordType) LogMsg("GetLargeResourceRecord: No RecordType for %##s", rr->resrec.name->c);
219647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
219747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// IMPORTANT: Any record type we understand and unpack into a structure containing domainnames needs to have corresponding
219847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// cases in SameRDataBody() and RDataHashValue() to do a semantic comparison (or checksum) of the structure instead of a blind
219947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// bitwise memory compare (or sum). This is because a domainname is a fixed size structure holding variable-length data.
220047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Any bytes past the logical end of the name are undefined, and a blind bitwise memory compare may indicate that
220147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// two domainnames are different when semantically they are the same name and it's only the unused bytes that differ.
220247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (rr->resrec.rrclass == kDNSQClass_ANY && pktrdlength == 0)	// Used in update packets to mean "Delete An RRset" (RFC 2136)
220347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr->resrec.rdlength = 0;
220447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else switch (rr->resrec.rrtype)
220547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
220647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_A:	if (pktrdlength != sizeof(mDNSv4Addr)) goto fail;
220747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->ipv4.b[0] = ptr[0];
220847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->ipv4.b[1] = ptr[1];
220947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->ipv4.b[2] = ptr[2];
221047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->ipv4.b[3] = ptr[3];
221147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
221247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
221347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NS:
221447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_CNAME:
221547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:
221647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DNAME:ptr = getDomainName(msg, ptr, end, &rdb->name);
221747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed CNAME/PTR RDATA name"); goto fail; }
221847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							//debugf("%##s PTR %##s rdlen %d", rr->resrec.name.c, rdb->name.c, pktrdlength);
221947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
222047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
222147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SOA:  ptr = getDomainName(msg, ptr, end, &rdb->soa.mname);
222247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA mname"); goto fail; }
222347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = getDomainName(msg, ptr, end, &rdb->soa.rname);
222447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr)              { debugf("GetLargeResourceRecord: Malformed SOA RDATA rname"); goto fail; }
222547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr + 0x14 != end) { debugf("GetLargeResourceRecord: Malformed SOA RDATA");       goto fail; }
222647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->soa.serial  = (mDNSs32) ((mDNSs32)ptr[0x00] << 24 | (mDNSs32)ptr[0x01] << 16 | (mDNSs32)ptr[0x02] << 8 | ptr[0x03]);
222747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->soa.refresh = (mDNSu32) ((mDNSu32)ptr[0x04] << 24 | (mDNSu32)ptr[0x05] << 16 | (mDNSu32)ptr[0x06] << 8 | ptr[0x07]);
222847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->soa.retry   = (mDNSu32) ((mDNSu32)ptr[0x08] << 24 | (mDNSu32)ptr[0x09] << 16 | (mDNSu32)ptr[0x0A] << 8 | ptr[0x0B]);
222947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->soa.expire  = (mDNSu32) ((mDNSu32)ptr[0x0C] << 24 | (mDNSu32)ptr[0x0D] << 16 | (mDNSu32)ptr[0x0E] << 8 | ptr[0x0F]);
223047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->soa.min     = (mDNSu32) ((mDNSu32)ptr[0x10] << 24 | (mDNSu32)ptr[0x11] << 16 | (mDNSu32)ptr[0x12] << 8 | ptr[0x13]);
223147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
223247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
223347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NULL:
223447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_HINFO:
223547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TSIG:
223647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TXT:
223747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_X25:
223847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_ISDN:
223947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_LOC:
224047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_DHCID:if (pktrdlength > rr->resrec.rdata->MaxRDLength)
224147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
224247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								debugf("GetLargeResourceRecord: %s rdata size (%d) exceeds storage (%d)",
224347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
224447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								goto fail;
224547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
224647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rr->resrec.rdlength = pktrdlength;
224747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength);
224847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
224947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
225047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_MX:
225147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AFSDB:
225247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RT:
225347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_KX:	if (pktrdlength < 3) goto fail;	// Preference + domainname
225447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->mx.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
225547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = getDomainName(msg, ptr+2, end, &rdb->mx.exchange);
225647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed MX name"); goto fail; }
225747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
225847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
225947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
226047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_RP:	ptr = getDomainName(msg, ptr, end, &rdb->rp.mbox);	// Domainname + domainname
226147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr)       { debugf("GetLargeResourceRecord: Malformed RP mbox"); goto fail; }
226247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = getDomainName(msg, ptr, end, &rdb->rp.txt);
226347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed RP txt"); goto fail; }
226447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
226547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
226647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PX:	if (pktrdlength < 4) goto fail;	// Preference + domainname + domainname
226747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->px.preference = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
226847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = getDomainName(msg, ptr, end, &rdb->px.map822);
226947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr)       { debugf("GetLargeResourceRecord: Malformed PX map822"); goto fail; }
227047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = getDomainName(msg, ptr, end, &rdb->px.mapx400);
227147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed PX mapx400"); goto fail; }
227247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
227347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
227447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AAAA:	if (pktrdlength != sizeof(mDNSv6Addr)) goto fail;
227547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSPlatformMemCopy(&rdb->ipv6, ptr, sizeof(rdb->ipv6));
227647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
227747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
227847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	if (pktrdlength < 7) goto fail;	// Priority + weight + port + domainname
227947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->srv.priority = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
228047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->srv.weight   = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
228147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->srv.port.b[0] = ptr[4];
228247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdb->srv.port.b[1] = ptr[5];
228347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = getDomainName(msg, ptr+6, end, &rdb->srv.target);
228447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed SRV RDATA name"); goto fail; }
228547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							//debugf("%##s SRV %##s rdlen %d", rr->resrec.name.c, rdb->srv.target.c, pktrdlength);
228647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
228747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
228847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:	{
228947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rdataOPT *opt = rr->resrec.rdata->u.opt;
229047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rr->resrec.rdlength = 0;
229147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							while (ptr < end && (mDNSu8 *)(opt+1) < &rr->resrec.rdata->u.data[MaximumRDSize])
229247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
229347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								const rdataOPT *const currentopt = opt;
229447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (ptr + 4 > end) { LogInfo("GetLargeResourceRecord: OPT RDATA ptr + 4 > end"); goto fail; }
229547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								opt->opt    = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
229647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								opt->optlen = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
229747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								ptr += 4;
229847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (ptr + opt->optlen > end) { LogInfo("GetLargeResourceRecord: ptr + opt->optlen > end"); goto fail; }
229947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								switch (opt->opt)
230047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
230147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_LLQ:
230247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										if (opt->optlen == DNSOpt_LLQData_Space - 4)
230347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											{
230447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.llq.vers  = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
230547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.llq.llqOp = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
230647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.llq.err   = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
230747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											mDNSPlatformMemCopy(opt->u.llq.id.b, ptr+6, 8);
230847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.llq.llqlease = (mDNSu32) ((mDNSu32)ptr[14] << 24 | (mDNSu32)ptr[15] << 16 | (mDNSu32)ptr[16] << 8 | ptr[17]);
230947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (opt->u.llq.llqlease > 0x70000000UL / mDNSPlatformOneSecond)
231047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												opt->u.llq.llqlease = 0x70000000UL / mDNSPlatformOneSecond;
231147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt++;
231247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											}
231347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
231447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_Lease:
231547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										if (opt->optlen == DNSOpt_LeaseData_Space - 4)
231647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											{
231747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.updatelease = (mDNSu32) ((mDNSu32)ptr[0] << 24 | (mDNSu32)ptr[1] << 16 | (mDNSu32)ptr[2] << 8 | ptr[3]);
231847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (opt->u.updatelease > 0x70000000UL / mDNSPlatformOneSecond)
231947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												opt->u.updatelease = 0x70000000UL / mDNSPlatformOneSecond;
232047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt++;
232147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											}
232247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
232347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case kDNSOpt_Owner:
232447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										if (ValidOwnerLength(opt->optlen))
232547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											{
232647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.owner.vers = ptr[0];
232747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.owner.seq  = ptr[1];
232847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											mDNSPlatformMemCopy(opt->u.owner.HMAC.b, ptr+2, 6);		// 6-byte MAC address
232947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+2, 6);		// 6-byte MAC address
233047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt->u.owner.password = zeroEthAddr;
233147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (opt->optlen >= DNSOpt_OwnerData_ID_Wake_Space-4)
233247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												{
233347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												mDNSPlatformMemCopy(opt->u.owner.IMAC.b, ptr+8, 6);	// 6-byte MAC address
233447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												// This mDNSPlatformMemCopy is safe because the ValidOwnerLength(opt->optlen) check above
233547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												// ensures that opt->optlen is no more than DNSOpt_OwnerData_ID_Wake_PW6_Space - 4
233647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												if (opt->optlen > DNSOpt_OwnerData_ID_Wake_Space-4)
233747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt													mDNSPlatformMemCopy(opt->u.owner.password.b, ptr+14, opt->optlen - (DNSOpt_OwnerData_ID_Wake_Space-4));
233847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												}
233947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											opt++;
234047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											}
234147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
234247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
234347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								ptr += currentopt->optlen;
234447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
234547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rr->resrec.rdlength = (mDNSu16)((mDNSu8*)opt - rr->resrec.rdata->u.data);
234647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr != end) { LogInfo("GetLargeResourceRecord: Malformed OptRdata"); goto fail; }
234747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
234847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
234947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
235047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC: {
235147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							unsigned int i, j;
235247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							domainname d;
235347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							ptr = getDomainName(msg, ptr, end, &d);		// Ignored for our simplified use of NSEC synthetic records
235447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!ptr) { LogInfo("GetLargeResourceRecord: Malformed NSEC nextname"); goto fail; }
235547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSPlatformMemZero(rdb->nsec.bitmap, sizeof(rdb->nsec.bitmap));
235647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr < end)
235747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
235847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (*ptr++ != 0) { debugf("GetLargeResourceRecord: We only handle block zero NSECs"); goto fail; }
235947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								i = *ptr++;
236047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (i > sizeof(rdataNSEC)) { debugf("GetLargeResourceRecord: invalid block length %d", i); goto fail; }
236147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								for (j=0; j<i; j++) rdb->nsec.bitmap[j] = *ptr++;
236247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
236347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (ptr != end) { debugf("GetLargeResourceRecord: Malformed NSEC"); goto fail; }
236447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
236547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
236647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
236747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			if (pktrdlength > rr->resrec.rdata->MaxRDLength)
236847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
236947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								debugf("GetLargeResourceRecord: rdata %d (%s) size (%d) exceeds storage (%d)",
237047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype), pktrdlength, rr->resrec.rdata->MaxRDLength);
237147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								goto fail;
237247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
237347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							debugf("GetLargeResourceRecord: Warning! Reading resource type %d (%s) as opaque data",
237447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								rr->resrec.rrtype, DNSTypeName(rr->resrec.rrtype));
237547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// Note: Just because we don't understand the record type, that doesn't
237647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// mean we fail. The DNS protocol specifies rdlength, so we can
237747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// safely skip over unknown records and ignore them.
237847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// We also grab a binary copy of the rdata anyway, since the caller
237947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// might know how to interpret it even if we don't.
238047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							rr->resrec.rdlength = pktrdlength;
238147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSPlatformMemCopy(rdb->data, ptr, pktrdlength);
238247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
238347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
238447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
238547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SetNewRData(&rr->resrec, mDNSNULL, 0);		// Sets rdlength, rdestimate, rdatahash for us
238647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
238747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Success! Now fill in RecordType to show this record contains valid data
238847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.RecordType = RecordType;
238947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(end);
239047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
239147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltfail:
239247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If we were unable to parse the rdata in this record, we indicate that by
239347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// returing a 'kDNSRecordTypePacketNegative' record with rdlength set to zero
239447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.RecordType = kDNSRecordTypePacketNegative;
239547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rdlength   = 0;
239647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rdestimate = 0;
239747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	rr->resrec.rdatahash  = 0;
239847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(end);
239947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
240047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
240147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *skipQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end)
240247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
240347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = skipDomainName(msg, ptr, end);
240447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { debugf("skipQuestion: Malformed domain name in DNS question section"); return(mDNSNULL); }
240547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr+4 > end) { debugf("skipQuestion: Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
240647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr+4);
240747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
240847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
240947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *getQuestion(const DNSMessage *msg, const mDNSu8 *ptr, const mDNSu8 *end, const mDNSInterfaceID InterfaceID,
241047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSQuestion *question)
241147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
241247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformMemZero(question, sizeof(*question));
241347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	question->InterfaceID = InterfaceID;
241447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!InterfaceID) question->TargetQID = onesID;	// In DNSQuestions we use TargetQID as the indicator of whether it's unicast or multicast
241547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = getDomainName(msg, ptr, end, &question->qname);
241647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) { debugf("Malformed domain name in DNS question section"); return(mDNSNULL); }
241747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr+4 > end) { debugf("Malformed DNS question section -- no query type and class!"); return(mDNSNULL); }
241847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
241947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	question->qnamehash = DomainNameHashValue(&question->qname);
242047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	question->qtype  = (mDNSu16)((mDNSu16)ptr[0] << 8 | ptr[1]);			// Get type
242147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	question->qclass = (mDNSu16)((mDNSu16)ptr[2] << 8 | ptr[3]);			// and class
242247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr+4);
242347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
242447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
242547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *LocateAnswers(const DNSMessage *const msg, const mDNSu8 *const end)
242647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
242747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
242847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = msg->data;
242947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < msg->h.numQuestions && ptr; i++) ptr = skipQuestion(msg, ptr, end);
243047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);
243147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
243247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
243347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *LocateAuthorities(const DNSMessage *const msg, const mDNSu8 *const end)
243447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
243547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
243647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = LocateAnswers(msg, end);
243747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < msg->h.numAnswers && ptr; i++) ptr = skipResourceRecord(msg, ptr, end);
243847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);
243947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
244047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
244147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8 *const end)
244247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
244347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
244447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = LocateAuthorities(msg, end);
244547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < msg->h.numAuthorities; i++) ptr = skipResourceRecord(msg, ptr, end);
244647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return (ptr);
244747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
244847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
244947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize)
245047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
245147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
245247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = LocateAdditionals(msg, end);
245347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
245447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Locate the OPT record.
245547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// According to RFC 2671, "One OPT pseudo-RR can be added to the additional data section of either a request or a response."
245647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// This implies that there may be *at most* one OPT record per DNS message, in the Additional Section,
245747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// but not necessarily the *last* entry in the Additional Section.
245847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; ptr && i < msg->h.numAdditionals; i++)
245947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
246047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr + DNSOpt_Header_Space + minsize <= end &&	// Make sure we have 11+minsize bytes of data
246147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			ptr[0] == 0                                &&	// Name must be root label
246247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			ptr[1] == (kDNSType_OPT >> 8  )            &&	// rrtype OPT
246347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			ptr[2] == (kDNSType_OPT & 0xFF)            &&
246447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			((mDNSu16)ptr[9] << 8 | (mDNSu16)ptr[10]) >= (mDNSu16)minsize)
246547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return(ptr);
246647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
246747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			ptr = skipResourceRecord(msg, ptr, end);
246847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
246947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSNULL);
247047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
247147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
247247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// On success, GetLLQOptData returns pointer to storage within shared "m->rec";
247347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// it is caller's responsibilty to clear m->rec.r.resrec.RecordType after use
247447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: An OPT RDataBody actually contains one or more variable-length rdataOPT objects packed together
247547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// The code that currently calls this assumes there's only one, instead of iterating through the set
247647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end)
247747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
247847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LLQData_Space);
247947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr)
248047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
248147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
248247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative) return(&m->rec.r.resrec.rdata->u.opt[0]);
248347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
248447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSNULL);
248547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
248647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
248747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Get the lease life of records in a dynamic update
248847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// returns 0 on error or if no lease present
248947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 GetPktLease(mDNS *m, DNSMessage *msg, const mDNSu8 *end)
249047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
249147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 result = 0;
249247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space);
249347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr) ptr = GetLargeResourceRecord(m, msg, ptr, end, 0, kDNSRecordTypePacketAdd, &m->rec);
249447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ptr && m->rec.r.resrec.rdlength >= DNSOpt_LeaseData_Space && m->rec.r.resrec.rdata->u.opt[0].opt == kDNSOpt_Lease)
249547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		result = m->rec.r.resrec.rdata->u.opt[0].u.updatelease;
249647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	m->rec.r.resrec.RecordType = 0;		// Clear RecordType to show we're not still using it
249747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(result);
249847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
249947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
250047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal const mDNSu8 *DumpRecords(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *ptr, const mDNSu8 *const end, int count, char *label)
250147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
250247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
250347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LogMsg("%2d %s", count, label);
250447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < count && ptr; i++)
250547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
250647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// This puts a LargeCacheRecord on the stack instead of using the shared m->rec storage,
250747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// but since it's only used for debugging (and probably only on OS X, not on
250847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// embedded systems) putting a 9kB object on the stack isn't a big problem.
250947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LargeCacheRecord largecr;
251047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSInterface_Any, kDNSRecordTypePacketAns, &largecr);
251147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr) LogMsg("%2d TTL%8d %s", i, largecr.r.resrec.rroriginalttl, CRDisplayString(m, &largecr.r));
251247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
251347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ptr) LogMsg("ERROR: Premature end of packet data");
251447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(ptr);
251547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
251647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
251747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DNS_OP_Name(X) (                              \
251847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag0_OP_StdQuery ? ""         :       \
251947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag0_OP_Iquery   ? "Iquery "  :       \
252047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag0_OP_Status   ? "Status "  :       \
252147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag0_OP_Unused3  ? "Unused3 " :       \
252247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag0_OP_Notify   ? "Notify "  :       \
252347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag0_OP_Update   ? "Update "  : "?? " )
252447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
252547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define DNS_RC_Name(X) (                             \
252647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_NoErr    ? "NoErr"    :      \
252747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_FormErr  ? "FormErr"  :      \
252847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_ServFail ? "ServFail" :      \
252947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_NXDomain ? "NXDomain" :      \
253047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_NotImpl  ? "NotImpl"  :      \
253147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_Refused  ? "Refused"  :      \
253247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_YXDomain ? "YXDomain" :      \
253347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_YXRRSet  ? "YXRRSet"  :      \
253447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_NXRRSet  ? "NXRRSet"  :      \
253547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_NotAuth  ? "NotAuth"  :      \
253647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(X) == kDNSFlag1_RC_NotZone  ? "NotZone"  : "??" )
253747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
253847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: DumpPacket expects the packet header fields in host byte order, not network byte order
253947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void DumpPacket(mDNS *const m, mStatus status, mDNSBool sent, char *transport,
254047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSAddr *srcaddr, mDNSIPPort srcport,
254147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
254247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
254347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool IsUpdate = ((msg->h.flags.b[0] & kDNSFlag0_OP_Mask) == kDNSFlag0_OP_Update);
254447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = msg->data;
254547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
254647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSQuestion q;
254747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char tbuffer[64], sbuffer[64], dbuffer[64] = "";
254847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!status) tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), sent ? "Sent" : "Received"                        )] = 0;
254947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else         tbuffer[mDNS_snprintf(tbuffer, sizeof(tbuffer), "ERROR %d %sing", status, sent ? "Send" : "Receiv")] = 0;
255047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (sent) sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "port "        )] = 0;
255147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else      sbuffer[mDNS_snprintf(sbuffer, sizeof(sbuffer), "%#a:", srcaddr)] = 0;
255247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (dstaddr || !mDNSIPPortIsZero(dstport))
255347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		dbuffer[mDNS_snprintf(dbuffer, sizeof(dbuffer), " to %#a:%d", dstaddr, mDNSVal16(dstport))] = 0;
255447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
255547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LogMsg("-- %s %s DNS %s%s (flags %02X%02X) RCODE: %s (%d) %s%s%s%s%s%sID: %d %d bytes from %s%d%s%s --",
255647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		tbuffer, transport,
255747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
255847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[0] & kDNSFlag0_QR_Response ? "Response" : "Query",
255947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[0], msg->h.flags.b[1],
256047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DNS_RC_Name(msg->h.flags.b[1] & kDNSFlag1_RC_Mask),
256147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[1] & kDNSFlag1_RC_Mask,
256247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[0] & kDNSFlag0_AA ? "AA " : "",
256347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[0] & kDNSFlag0_TC ? "TC " : "",
256447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[0] & kDNSFlag0_RD ? "RD " : "",
256547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[1] & kDNSFlag1_RA ? "RA " : "",
256647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[1] & kDNSFlag1_AD ? "AD " : "",
256747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		msg->h.flags.b[1] & kDNSFlag1_CD ? "CD " : "",
256847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSVal16(msg->h.id),
256947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		end - msg->data,
257047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		sbuffer, mDNSVal16(srcport), dbuffer,
257147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		(msg->h.flags.b[0] & kDNSFlag0_TC) ? " (truncated)" : ""
257247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		);
257347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
257447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LogMsg("%2d %s", msg->h.numQuestions, IsUpdate ? "Zone" : "Questions");
257547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < msg->h.numQuestions && ptr; i++)
257647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
257747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = getQuestion(msg, ptr, end, mDNSInterface_Any, &q);
257847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr) LogMsg("%2d %##s %s", i, q.qname.c, DNSTypeName(q.qtype));
257947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
258047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = DumpRecords(m, msg, ptr, end, msg->h.numAnswers,     IsUpdate ? "Prerequisites" : "Answers");
258147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = DumpRecords(m, msg, ptr, end, msg->h.numAuthorities, IsUpdate ? "Updates"       : "Authorities");
258247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ptr = DumpRecords(m, msg, ptr, end, msg->h.numAdditionals, "Additionals");
258347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LogMsg("--------------");
258447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
258547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
258647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
258747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
258847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
258947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Packet Sending Functions
259047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
259147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
259247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
259347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
259447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
259547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct UDPSocket_struct
259647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
259747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
259847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	};
259947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
260047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
260147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
260247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
260347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt    mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo)
260447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
260547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus status = mStatus_NoError;
260647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu16 numAdditionals = msg->h.numAdditionals;
260747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *newend;
260847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
260947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
261047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Zero-length message data is okay (e.g. for a DNS Update ack, where all we need is an ID and an error code
261147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (end < msg->data || end - msg->data > AbsoluteMaxDNSMessageData)
261247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
261347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("mDNSSendDNSMessage: invalid message %p %p %d", msg->data, end, end - msg->data);
261447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return mStatus_BadParamErr;
261547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
261647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
261747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	newend = putHINFO(m, msg, end, authInfo, limit);
261847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
261947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else end = newend;
262047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
262147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Put all the integer values in IETF byte-order (MSB first, LSB second)
262247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SwapDNSHeaderBytes(msg);
262347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
262447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (authInfo) DNSDigest_SignMessage(msg, &end, authInfo, 0);	// DNSDigest_SignMessage operates on message in network byte order
262547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!end) { LogMsg("mDNSSendDNSMessage: DNSDigest_SignMessage failed"); status = mStatus_NoMemoryErr; }
262647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
262747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
262847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Send the packet on the wire
262947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!sock)
263047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport);
263147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
263247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
263347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
263447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSu8 lenbuf[2] = { (mDNSu8)(msglen >> 8), (mDNSu8)(msglen & 0xFF) };
263547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			long nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);		// Should do scatter/gather here -- this is probably going out as two packets
263647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (nsent != 2) { LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2); status = mStatus_ConnFailed; }
263747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
263847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
263947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
264047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (nsent != msglen) { LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen); status = mStatus_ConnFailed; }
264147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
264247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
264347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
264447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
264547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Swap the integer values back the way they were (remember that numAdditionals may have been changed by putHINFO and/or SignMessage)
264647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	SwapDNSHeaderBytes(msg);
264747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
264847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Dump the packet with the HINFO and TSIG
264947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id))
265047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DumpPacket(m, status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
265147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
265247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// put the number of additionals back the way it was
265347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.numAdditionals = numAdditionals;
265447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
265547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(status);
265647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
265747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
265847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
265947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
266047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
266147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - RR List Management & Task Management
266247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
266347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
266447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_Lock_(mDNS *const m, const char * const functionname)
266547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
266647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// MUST grab the platform lock FIRST!
266747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformLock(m);
266847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
266947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Normally, mDNS_reentrancy is zero and so is mDNS_busy
267047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// However, when we call a client callback mDNS_busy is one, and we increment mDNS_reentrancy too
267147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If that client callback does mDNS API calls, mDNS_reentrancy and mDNS_busy will both be one
267247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If mDNS_busy != mDNS_reentrancy that's a bad sign
267347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->mDNS_busy != m->mDNS_reentrancy)
267447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
267547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("%s: mDNS_Lock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
267647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts
267747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*(long*)0 = 0;
267847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
267947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
268047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
268147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If this is an initial entry into the mDNSCore code, set m->timenow
268247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// else, if this is a re-entrant entry into the mDNSCore code, m->timenow should already be set
268347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->mDNS_busy == 0)
268447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
268547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (m->timenow)
268647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			LogMsg("%s: mDNS_Lock: m->timenow already set (%ld/%ld)", functionname, m->timenow, mDNS_TimeNow_NoLock(m));
268747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		m->timenow = mDNS_TimeNow_NoLock(m);
268847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (m->timenow == 0) m->timenow = 1;
268947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
269047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (m->timenow == 0)
269147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
269247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("%s: mDNS_Lock: m->mDNS_busy is %ld but m->timenow not set", functionname, m->mDNS_busy);
269347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		m->timenow = mDNS_TimeNow_NoLock(m);
269447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (m->timenow == 0) m->timenow = 1;
269547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
269647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
269747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow_last - m->timenow > 0)
269847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
269947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		m->timenow_adjust += m->timenow_last - m->timenow;
270047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("%s: mDNSPlatformRawTime went backwards by %ld ticks; setting correction factor to %ld", functionname, m->timenow_last - m->timenow, m->timenow_adjust);
270147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		m->timenow = m->timenow_last;
270247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
270347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	m->timenow_last = m->timenow;
270447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
270547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Increment mDNS_busy so we'll recognise re-entrant calls
270647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	m->mDNS_busy++;
270747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
270847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
270947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal AuthRecord *AnyLocalRecordReady(const mDNS *const m)
271047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
271147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord *rr;
271247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (rr = m->NewLocalRecords; rr; rr = rr->next)
271347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (LocalRecordReady(rr)) return rr;
271447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return mDNSNULL;
271547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
271647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
271747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
271847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
271947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSs32 e = m->timenow + 0x78000000;
272047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->mDNSPlatformStatus != mStatus_NoError) return(e);
272147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewQuestions)
272247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
272347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (m->NewQuestions->DelayAnswering) e = m->NewQuestions->DelayAnswering;
272447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else return(m->timenow);
272547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
272647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewLocalOnlyQuestions)                     return(m->timenow);
272747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewLocalRecords && AnyLocalRecordReady(m)) return(m->timenow);
272847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewLocalOnlyRecords)                       return(m->timenow);
272947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->SPSProxyListChanged)                       return(m->timenow);
273047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->LocalRemoveEvents)                         return(m->timenow);
273147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
273247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED
273347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e - m->NextuDNSEvent         > 0) e = m->NextuDNSEvent;
273447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e - m->NextScheduledNATOp    > 0) e = m->NextScheduledNATOp;
273547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NextSRVUpdate && e - m->NextSRVUpdate > 0) e = m->NextSRVUpdate;
273647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
273747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
273847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e - m->NextCacheCheck        > 0) e = m->NextCacheCheck;
273947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e - m->NextScheduledSPS      > 0) e = m->NextScheduledSPS;
274047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// NextScheduledSPRetry only valid when DelaySleep not set
274147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
274247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->DelaySleep && e - m->DelaySleep > 0) e = m->DelaySleep;
274347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
274447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->SuppressSending)
274547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
274647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (e - m->SuppressSending       > 0) e = m->SuppressSending;
274747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
274847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
274947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
275047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (e - m->NextScheduledQuery    > 0) e = m->NextScheduledQuery;
275147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (e - m->NextScheduledProbe    > 0) e = m->NextScheduledProbe;
275247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (e - m->NextScheduledResponse > 0) e = m->NextScheduledResponse;
275347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
275447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (e - m->NextScheduledStopTime > 0) e = m->NextScheduledStopTime;
275547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(e);
275647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
275747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
275847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void ShowTaskSchedulingError(mDNS *const m)
275947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
276047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	AuthRecord *rr;
276147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_Lock(m);
276247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
276347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LogMsg("Task Scheduling Error: Continuously busy for more than a second");
276447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
276547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Note: To accurately diagnose *why* we're busy, the debugging code here needs to mirror the logic in GetNextScheduledEvent above
276647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
276747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewQuestions && (!m->NewQuestions->DelayAnswering || m->timenow - m->NewQuestions->DelayAnswering >= 0))
276847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: NewQuestion %##s (%s)",
276947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
277047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
277147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewLocalOnlyQuestions)
277247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: NewLocalOnlyQuestions %##s (%s)",
277347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
277447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
277547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewLocalRecords)
277647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
277747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		rr = AnyLocalRecordReady(m);
277847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (rr) LogMsg("Task Scheduling Error: NewLocalRecords %s", ARDisplayString(m, rr));
277947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
278047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
278147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NewLocalOnlyRecords) LogMsg("Task Scheduling Error: NewLocalOnlyRecords");
278247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
278347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->SPSProxyListChanged) LogMsg("Task Scheduling Error: SPSProxyListChanged");
278447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->LocalRemoveEvents)   LogMsg("Task Scheduling Error: LocalRemoveEvents");
278547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
278647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextScheduledEvent    >= 0)
278747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextScheduledEvent %d",    m->timenow - m->NextScheduledEvent);
278847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
278947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#ifndef UNICAST_DISABLED
279047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextuDNSEvent         >= 0)
279147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextuDNSEvent %d",         m->timenow - m->NextuDNSEvent);
279247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextScheduledNATOp    >= 0)
279347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextScheduledNATOp %d",    m->timenow - m->NextScheduledNATOp);
279447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->NextSRVUpdate && m->timenow - m->NextSRVUpdate >= 0)
279547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextSRVUpdate %d",         m->timenow - m->NextSRVUpdate);
279647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
279747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
279847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextCacheCheck        >= 0)
279947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextCacheCheck %d",        m->timenow - m->NextCacheCheck);
280047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextScheduledSPS      >= 0)
280147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextScheduledSPS %d",      m->timenow - m->NextScheduledSPS);
280247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!m->DelaySleep && m->SleepLimit && m->timenow - m->NextScheduledSPRetry >= 0)
280347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextScheduledSPRetry %d",  m->timenow - m->NextScheduledSPRetry);
280447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
280547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->DelaySleep %d",            m->timenow - m->DelaySleep);
280647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
280747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->SuppressSending && m->timenow - m->SuppressSending >= 0)
280847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->SuppressSending %d",       m->timenow - m->SuppressSending);
280947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextScheduledQuery    >= 0)
281047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextScheduledQuery %d",    m->timenow - m->NextScheduledQuery);
281147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextScheduledProbe    >= 0)
281247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextScheduledProbe %d",    m->timenow - m->NextScheduledProbe);
281347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->timenow - m->NextScheduledResponse >= 0)
281447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("Task Scheduling Error: m->NextScheduledResponse %d", m->timenow - m->NextScheduledResponse);
281547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
281647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_Unlock(m);
281747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
281847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
281947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNS_Unlock_(mDNS *const m, const char * const functionname)
282047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
282147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Decrement mDNS_busy
282247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	m->mDNS_busy--;
282347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
282447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Check for locking failures
282547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->mDNS_busy != m->mDNS_reentrancy)
282647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
282747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LogMsg("%s: mDNS_Unlock: Locking failure! mDNS_busy (%ld) != mDNS_reentrancy (%ld)", functionname, m->mDNS_busy, m->mDNS_reentrancy);
282847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if ForceAlerts
282947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*(long*)0 = 0;
283047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
283147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
283247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
283347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If this is a final exit from the mDNSCore code, set m->NextScheduledEvent and clear m->timenow
283447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (m->mDNS_busy == 0)
283547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
283647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		m->NextScheduledEvent = GetNextScheduledEvent(m);
283747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (m->timenow == 0) LogMsg("%s: mDNS_Unlock: ERROR! m->timenow aready zero", functionname);
283847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		m->timenow = 0;
283947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
284047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
284147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// MUST release the platform lock LAST!
284247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPlatformUnlock(m);
284347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
284447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
284547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// ***************************************************************************
284647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if COMPILER_LIKES_PRAGMA_MARK
284747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark -
284847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#pragma mark - Specialized mDNS version of vsnprintf
284947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
285047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
285147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic const struct mDNSprintf_format
285247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
285347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned      leftJustify : 1;
285447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned      forceSign : 1;
285547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned      zeroPad : 1;
285647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned      havePrecision : 1;
285747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned      hSize : 1;
285847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned      lSize : 1;
285947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char          altForm;
286047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char          sign;		// +, - or space
286147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned int  fieldWidth;
286247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned int  precision;
286347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} mDNSprintf_format_default = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
286447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
286547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg)
286647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
286747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 nwritten = 0;
286847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int c;
286947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (buflen == 0) return(0);
287047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	buflen--;		// Pre-reserve one space in the buffer for the terminating null
287147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (buflen == 0) goto exit;
287247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
287347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (c = *fmt; c != 0; c = *++fmt)
287447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
287547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (c != '%')
287647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
287747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			*sbuffer++ = (char)c;
287847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (++nwritten >= buflen) goto exit;
287947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
288047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
288147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
288247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			unsigned int i=0, j;
288347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// The mDNS Vsprintf Argument Conversion Buffer is used as a temporary holding area for
288447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// generating decimal numbers, hexdecimal numbers, IP addresses, domain name strings, etc.
288547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// The size needs to be enough for a 256-byte domain name plus some error text.
288647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			#define mDNS_VACB_Size 300
288747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			char mDNS_VACB[mDNS_VACB_Size];
288847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			#define mDNS_VACB_Lim (&mDNS_VACB[mDNS_VACB_Size])
288947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			#define mDNS_VACB_Remain(s) ((mDNSu32)(mDNS_VACB_Lim - s))
289047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			char *s = mDNS_VACB_Lim, *digits;
289147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			struct mDNSprintf_format F = mDNSprintf_format_default;
289247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
289347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			while (1)	//  decode flags
289447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
289547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				c = *++fmt;
289647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if      (c == '-') F.leftJustify = 1;
289747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else if (c == '+') F.forceSign = 1;
289847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else if (c == ' ') F.sign = ' ';
289947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else if (c == '#') F.altForm++;
290047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else if (c == '0') F.zeroPad = 1;
290147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else break;
290247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
290347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
290447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (c == '*')	//  decode field width
290547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
290647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				int f = va_arg(arg, int);
290747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (f < 0) { f = -f; F.leftJustify = 1; }
290847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				F.fieldWidth = (unsigned int)f;
290947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				c = *++fmt;
291047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
291147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
291247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
291347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				for (; c >= '0' && c <= '9'; c = *++fmt)
291447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					F.fieldWidth = (10 * F.fieldWidth) + (c - '0');
291547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
291647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
291747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (c == '.')	//  decode precision
291847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
291947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if ((c = *++fmt) == '*')
292047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					{ F.precision = va_arg(arg, unsigned int); c = *++fmt; }
292147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else for (; c >= '0' && c <= '9'; c = *++fmt)
292247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt						F.precision = (10 * F.precision) + (c - '0');
292347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				F.havePrecision = 1;
292447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
292547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
292647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (F.leftJustify) F.zeroPad = 0;
292747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
292847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			conv:
292947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			switch (c)	//  perform appropriate conversion
293047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
293147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				unsigned long n;
293247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'h' :	F.hSize = 1; c = *++fmt; goto conv;
293347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'l' :	// fall through
293447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'L' :	F.lSize = 1; c = *++fmt; goto conv;
293547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'd' :
293647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'i' :	if (F.lSize) n = (unsigned long)va_arg(arg, long);
293747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else n = (unsigned long)va_arg(arg, int);
293847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.hSize) n = (short) n;
293947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if ((long) n < 0) { n = (unsigned long)-(long)n; F.sign = '-'; }
294047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else if (F.forceSign) F.sign = '+';
294147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							goto decimal;
294247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'u' :	if (F.lSize) n = va_arg(arg, unsigned long);
294347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else n = va_arg(arg, unsigned int);
294447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.hSize) n = (unsigned short) n;
294547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							F.sign = 0;
294647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							goto decimal;
294747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				decimal:	if (!F.havePrecision)
294847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
294947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.zeroPad)
295047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
295147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									F.precision = F.fieldWidth;
295247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									if (F.sign) --F.precision;
295347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
295447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.precision < 1) F.precision = 1;
295547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
295647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.precision > mDNS_VACB_Size - 1)
295747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								F.precision = mDNS_VACB_Size - 1;
295847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (i = 0; n; n /= 10, i++) *--s = (char)(n % 10 + '0');
295947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (; i < F.precision; i++) *--s = '0';
296047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.sign) { *--s = F.sign; i++; }
296147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
296247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
296347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'o' :	if (F.lSize) n = va_arg(arg, unsigned long);
296447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else n = va_arg(arg, unsigned int);
296547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.hSize) n = (unsigned short) n;
296647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!F.havePrecision)
296747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
296847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.zeroPad) F.precision = F.fieldWidth;
296947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.precision < 1) F.precision = 1;
297047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
297147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.precision > mDNS_VACB_Size - 1)
297247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								F.precision = mDNS_VACB_Size - 1;
297347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (i = 0; n; n /= 8, i++) *--s = (char)(n % 8 + '0');
297447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.altForm && i && *s != '0') { *--s = '0'; i++; }
297547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (; i < F.precision; i++) *--s = '0';
297647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
297747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
297847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'a' :	{
297947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							unsigned char *a = va_arg(arg, unsigned char *);
298047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!a) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
298147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else
298247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
298347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								s = mDNS_VACB;	// Adjust s to point to the start of the buffer, not the end
298447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.altForm)
298547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
298647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									mDNSAddr *ip = (mDNSAddr*)a;
298747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									switch (ip->type)
298847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										{
298947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										case mDNSAddrType_IPv4: F.precision =  4; a = (unsigned char *)&ip->ip.v4; break;
299047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										case mDNSAddrType_IPv6: F.precision = 16; a = (unsigned char *)&ip->ip.v6; break;
299147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										default:                F.precision =  0; break;
299247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										}
299347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
299447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.altForm && !F.precision)
299547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "«ZERO ADDRESS»");
299647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								else switch (F.precision)
299747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
299847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case  4: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%d.%d.%d.%d",
299947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt														a[0], a[1], a[2], a[3]); break;
300047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case  6: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%02X:%02X:%02X:%02X:%02X:%02X",
300147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt														a[0], a[1], a[2], a[3], a[4], a[5]); break;
300247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									case 16: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB),
300347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt														"%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X",
300447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt														a[0x0], a[0x1], a[0x2], a[0x3], a[0x4], a[0x5], a[0x6], a[0x7],
300547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt														a[0x8], a[0x9], a[0xA], a[0xB], a[0xC], a[0xD], a[0xE], a[0xF]); break;
300647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									default: i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "%s", "<< ERROR: Must specify"
300747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt														" address size (i.e. %.4a=IPv4, %.6a=Ethernet, %.16a=IPv6) >>"); break;
300847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
300947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
301047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							}
301147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
301247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
301347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'p' :	F.havePrecision = F.lSize = 1;
301447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							F.precision = sizeof(void*) * 2;	// 8 characters on 32-bit; 16 characters on 64-bit
301547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'X' :	digits = "0123456789ABCDEF";
301647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							goto hexadecimal;
301747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'x' :	digits = "0123456789abcdef";
301847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				hexadecimal:if (F.lSize) n = va_arg(arg, unsigned long);
301947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else n = va_arg(arg, unsigned int);
302047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.hSize) n = (unsigned short) n;
302147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!F.havePrecision)
302247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
302347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.zeroPad)
302447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
302547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									F.precision = F.fieldWidth;
302647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									if (F.altForm) F.precision -= 2;
302747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
302847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (F.precision < 1) F.precision = 1;
302947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
303047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.precision > mDNS_VACB_Size - 1)
303147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								F.precision = mDNS_VACB_Size - 1;
303247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (i = 0; n; n /= 16, i++) *--s = digits[n % 16];
303347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (; i < F.precision; i++) *--s = '0';
303447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.altForm) { *--s = (char)c; *--s = '0'; i += 2; }
303547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
303647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
303747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'c' :	*--s = (char)va_arg(arg, int); i = 1; break;
303847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
303947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 's' :	s = va_arg(arg, char *);
304047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (!s) { static char emsg[] = "<<NULL>>"; s = emsg; i = sizeof(emsg)-1; }
304147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else switch (F.altForm)
304247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
304347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								case 0: i=0;
304447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										if (!F.havePrecision)				// C string
304547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											while (s[i]) i++;
304647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										else
304747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											{
304847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											while ((i < F.precision) && s[i]) i++;
304947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// Make sure we don't truncate in the middle of a UTF-8 character
305047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// If last character we got was any kind of UTF-8 multi-byte character,
305147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// then see if we have to back up.
305247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// This is not as easy as the similar checks below, because
305347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// here we can't assume it's safe to examine the *next* byte, so we
305447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// have to confine ourselves to working only backwards in the string.
305547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											j = i;		// Record where we got to
305647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// Now, back up until we find first non-continuation-char
305747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											while (i>0 && (s[i-1] & 0xC0) == 0x80) i--;
305847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// Now s[i-1] is the first non-continuation-char
305947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// and (j-i) is the number of continuation-chars we found
306047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (i>0 && (s[i-1] & 0xC0) == 0xC0)	// If we found a start-char
306147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												{
306247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												i--;		// Tentatively eliminate this start-char as well
306347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												// Now (j-i) is the number of characters we're considering eliminating.
306447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												// To be legal UTF-8, the start-char must contain (j-i) one-bits,
306547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												// followed by a zero bit. If we shift it right by (7-(j-i)) bits
306647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												// (with sign extension) then the result has to be 0xFE.
306747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												// If this is right, then we reinstate the tentatively eliminated bytes.
306847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												if (((j-i) < 7) && (((s[i] >> (7-(j-i))) & 0xFF) == 0xFE)) i = j;
306947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												}
307047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											}
307147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
307247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								case 1: i = (unsigned char) *s++; break;	// Pascal string
307347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								case 2: {									// DNS label-sequence name
307447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										unsigned char *a = (unsigned char *)s;
307547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										s = mDNS_VACB;	// Adjust s to point to the start of the buffer, not the end
307647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										if (*a == 0) *s++ = '.';	// Special case for root DNS name
307747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										while (*a)
307847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											{
307947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											char buf[63*4+1];
308047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (*a > 63)
308147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												{ s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<INVALID LABEL LENGTH %u>>", *a); break; }
308247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											if (s + *a >= &mDNS_VACB[254])
308347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt												{ s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "<<NAME TOO LONG>>"); break; }
308447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// Need to use ConvertDomainLabelToCString to do proper escaping here,
308547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											// so it's clear what's a literal dot and what's a label separator
308647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											ConvertDomainLabelToCString((domainlabel*)a, buf);
308747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											s += mDNS_snprintf(s, mDNS_VACB_Remain(s), "%s.", buf);
308847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											a += 1 + *a;
308947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt											}
309047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										i = (mDNSu32)(s - mDNS_VACB);
309147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										s = mDNS_VACB;	// Reset s back to the start of the buffer
309247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										break;
309347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										}
309447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
309547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// Make sure we don't truncate in the middle of a UTF-8 character (see similar comment below)
309647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (F.havePrecision && i > F.precision)
309747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{ i = F.precision; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
309847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
309947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
310047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case 'n' :	s = va_arg(arg, char *);
310147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if      (F.hSize) * (short *) s = (short)nwritten;
310247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else if (F.lSize) * (long  *) s = (long)nwritten;
310347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							else              * (int   *) s = (int)nwritten;
310447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							continue;
310547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
310647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				default:	s = mDNS_VACB;
310747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
310847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
310947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				case '%' :	*sbuffer++ = (char)c;
311047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							if (++nwritten >= buflen) goto exit;
311147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							break;
311247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
311347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
311447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (i < F.fieldWidth && !F.leftJustify)			// Pad on the left
311547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				do	{
311647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					*sbuffer++ = ' ';
311747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					if (++nwritten >= buflen) goto exit;
311847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt					} while (i < --F.fieldWidth);
311947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
312047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// Make sure we don't truncate in the middle of a UTF-8 character.
312147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// Note: s[i] is the first eliminated character; i.e. the next character *after* the last character of the
312247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// allowed output. If s[i] is a UTF-8 continuation character, then we've cut a unicode character in half,
312347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// so back up 'i' until s[i] is no longer a UTF-8 continuation character. (if the input was proprly
312447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// formed, s[i] will now be the UTF-8 start character of the multi-byte character we just eliminated).
312547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (i > buflen - nwritten)
312647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ i = buflen - nwritten; while (i>0 && (s[i] & 0xC0) == 0x80) i--; }
312747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			for (j=0; j<i; j++) *sbuffer++ = *s++;			// Write the converted result
312847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			nwritten += i;
312947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (nwritten >= buflen) goto exit;
313047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
313147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			for (; i < F.fieldWidth; i++)					// Pad on the right
313247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
313347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				*sbuffer++ = ' ';
313447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (++nwritten >= buflen) goto exit;
313547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
313647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
313747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
313847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	exit:
313947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*sbuffer++ = 0;
314047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(nwritten);
314147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
314247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
314347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...)
314447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
314547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 length;
314647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
314747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_list ptr;
314847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_start(ptr,fmt);
314947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	length = mDNS_vsnprintf(sbuffer, buflen, fmt, ptr);
315047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_end(ptr);
315147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
315247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(length);
315347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
3154