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