doubao_chat/lib/net/mdns/code/mdnsembeddedapi.h

2668 lines
144 KiB
C

#ifndef __MDNSENBEDDE_API_H
#define __MDNSENBEDDE_API_H
#include "typedef.h"
#include "mDNSDebug.h"
#include "mDNSUNP.h"
#ifndef mDNSlocal
#define mDNSlocal static
#endif
#ifndef mDNSexport
#define mDNSexport
#endif
typedef enum { // From RFC 1035
kDNSClass_IN = 1, // Internet
kDNSClass_CS = 2, // CSNET
kDNSClass_CH = 3, // CHAOS
kDNSClass_HS = 4, // Hesiod
kDNSClass_NONE = 254, // Used in DNS UPDATE [RFC 2136]
kDNSClass_Mask = 0x7FFF,// Multicast DNS uses the bottom 15 bits to identify the record class...
kDNSClass_UniqueRRSet = 0x8000,// ... and the top bit indicates that all other cached records are now invalid
kDNSQClass_ANY = 255, // Not a DNS class, but a DNS query class, meaning "all classes"
kDNSQClass_UnicastResponse = 0x8000 // Top bit set in a question means "unicast response acceptable"
} DNS_ClassValues;
typedef enum { // From RFC 1035
kDNSType_A = 1, // 1 Address
kDNSType_NS, // 2 Name Server
kDNSType_MD, // 3 Mail Destination
kDNSType_MF, // 4 Mail Forwarder
kDNSType_CNAME, // 5 Canonical Name
kDNSType_SOA, // 6 Start of Authority
kDNSType_MB, // 7 Mailbox
kDNSType_MG, // 8 Mail Group
kDNSType_MR, // 9 Mail Rename
kDNSType_NULL, // 10 NULL RR
kDNSType_WKS, // 11 Well-known-service
kDNSType_PTR, // 12 Domain name pointer
kDNSType_HINFO, // 13 Host information
kDNSType_MINFO, // 14 Mailbox information
kDNSType_MX, // 15 Mail Exchanger
kDNSType_TXT, // 16 Arbitrary text string
kDNSType_RP, // 17 Responsible person
kDNSType_AFSDB, // 18 AFS cell database
kDNSType_X25, // 19 X_25 calling address
kDNSType_ISDN, // 20 ISDN calling address
kDNSType_RT, // 21 Router
kDNSType_NSAP, // 22 NSAP address
kDNSType_NSAP_PTR, // 23 Reverse NSAP lookup (deprecated)
kDNSType_SIG, // 24 Security signature
kDNSType_KEY, // 25 Security key
kDNSType_PX, // 26 X.400 mail mapping
kDNSType_GPOS, // 27 Geographical position (withdrawn)
kDNSType_AAAA, // 28 IPv6 Address
kDNSType_LOC, // 29 Location Information
kDNSType_NXT, // 30 Next domain (security)
kDNSType_EID, // 31 Endpoint identifier
kDNSType_NIMLOC, // 32 Nimrod Locator
kDNSType_SRV, // 33 Service record
kDNSType_ATMA, // 34 ATM Address
kDNSType_NAPTR, // 35 Naming Authority PoinTeR
kDNSType_KX, // 36 Key Exchange
kDNSType_CERT, // 37 Certification record
kDNSType_A6, // 38 IPv6 Address (deprecated)
kDNSType_DNAME, // 39 Non-terminal DNAME (for IPv6)
kDNSType_SINK, // 40 Kitchen sink (experimental)
kDNSType_OPT, // 41 EDNS0 option (meta-RR)
kDNSType_APL, // 42 Address Prefix List
kDNSType_DS, // 43 Delegation Signer
kDNSType_SSHFP, // 44 SSH Key Fingerprint
kDNSType_IPSECKEY, // 45 IPSECKEY
kDNSType_RRSIG, // 46 RRSIG
kDNSType_NSEC, // 47 Denial of Existence
kDNSType_DNSKEY, // 48 DNSKEY
kDNSType_DHCID, // 49 DHCP Client Identifier
kDNSType_NSEC3, // 50 Hashed Authenticated Denial of Existence
kDNSType_NSEC3PARAM, // 51 Hashed Authenticated Denial of Existence
kDNSType_HIP = 55, // 55 Host Identity Protocol
kDNSType_SPF = 99, // 99 Sender Policy Framework for E-Mail
kDNSType_UINFO, // 100 IANA-Reserved
kDNSType_UID, // 101 IANA-Reserved
kDNSType_GID, // 102 IANA-Reserved
kDNSType_UNSPEC, // 103 IANA-Reserved
kDNSType_TKEY = 249, // 249 Transaction key
kDNSType_TSIG, // 250 Transaction signature
kDNSType_IXFR, // 251 Incremental zone transfer
kDNSType_AXFR, // 252 Transfer zone of authority
kDNSType_MAILB, // 253 Transfer mailbox records
kDNSType_MAILA, // 254 Transfer mail agent records
kDNSQType_ANY // Not a DNS type, but a DNS query type, meaning "all types"
} DNS_TypeValues;
// mDNS defines its own names for these common types to simplify portability across
// multiple platforms that may each have their own (different) names for these types.
typedef int mDNSBool;
typedef signed char mDNSs8;
typedef unsigned char mDNSu8;
typedef signed short mDNSs16;
typedef unsigned short mDNSu16;
typedef signed int mDNSs32;
typedef unsigned int mDNSu32;
// To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
// This way, mDNSInterfaceIDs can be assigned, and compared with each other, but not with other types
// Declaring the type to be the typical generic "void *" would lack this type checking
typedef struct mDNSInterfaceID_dummystruct {
void *dummy;
} *mDNSInterfaceID;
typedef union {
mDNSu8 b[ 2];
mDNSu16 NotAnInteger;
} mDNSOpaque16;
typedef union {
mDNSu8 b[ 4];
mDNSu32 NotAnInteger;
} mDNSOpaque32;
typedef packedunion { mDNSu8 b[ 6]; mDNSu16 w[3]; mDNSu32 l[1]; } mDNSOpaque48;
typedef union {
mDNSu8 b[ 8];
mDNSu16 w[4];
mDNSu32 l[2];
} mDNSOpaque64;
typedef union {
mDNSu8 b[16];
mDNSu16 w[8];
mDNSu32 l[4];
} mDNSOpaque128;
typedef mDNSOpaque16 mDNSIPPort; // An IP port is a two-byte opaque identifier (not an integer)
typedef mDNSOpaque32 mDNSv4Addr; // An IP address is a four-byte opaque identifier (not an integer)
typedef mDNSOpaque128 mDNSv6Addr; // An IPv6 address is a 16-byte opaque identifier (not an integer)
typedef mDNSOpaque48 mDNSEthAddr; // An Ethernet address is a six-byte opaque identifier (not an integer)
// Bit operations for opaque 64 bit quantity. Uses the 32 bit quantity(l[2]) to set and clear bits
#define mDNSNBBY 8
#define bit_set_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] |= (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
#define bit_clr_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] &= ~(1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
#define bit_get_opaque64(op64, index) (op64.l[((index))/(sizeof(mDNSu32) * mDNSNBBY)] & (1 << ((index) % (sizeof(mDNSu32) * mDNSNBBY))))
enum {
mDNSAddrType_None = 0,
mDNSAddrType_IPv4 = 4,
mDNSAddrType_IPv6 = 6,
mDNSAddrType_Unknown = ~0 // Special marker value used in known answer list recording
};
enum {
mDNSTransport_None = 0,
mDNSTransport_UDP = 1,
mDNSTransport_TCP = 2
};
typedef struct {
mDNSs32 type;
union {
mDNSv6Addr v6;
mDNSv4Addr v4;
} ip;
} mDNSAddr;
enum { mDNSfalse = 0, mDNStrue = 1 };
#define mDNSNULL 0L
enum {
mStatus_Waiting = 1,
mStatus_NoError = 0,
// mDNS return values are in the range FFFE FF00 (-65792) to FFFE FFFF (-65537)
// The top end of the range (FFFE FFFF) is used for error codes;
// the bottom end of the range (FFFE FF00) is used for non-error values;
// Error codes:
mStatus_UnknownErr = -65537, // First value: 0xFFFE FFFF
mStatus_NoSuchNameErr = -65538,
mStatus_NoMemoryErr = -65539,
mStatus_BadParamErr = -65540,
mStatus_BadReferenceErr = -65541,
mStatus_BadStateErr = -65542,
mStatus_BadFlagsErr = -65543,
mStatus_UnsupportedErr = -65544,
mStatus_NotInitializedErr = -65545,
mStatus_NoCache = -65546,
mStatus_AlreadyRegistered = -65547,
mStatus_NameConflict = -65548,
mStatus_Invalid = -65549,
mStatus_Firewall = -65550,
mStatus_Incompatible = -65551,
mStatus_BadInterfaceErr = -65552,
mStatus_Refused = -65553,
mStatus_NoSuchRecord = -65554,
mStatus_NoAuth = -65555,
mStatus_NoSuchKey = -65556,
mStatus_NATTraversal = -65557,
mStatus_DoubleNAT = -65558,
mStatus_BadTime = -65559,
mStatus_BadSig = -65560, // while we define this per RFC 2845, BIND 9 returns Refused for bad/missing signatures
mStatus_BadKey = -65561,
mStatus_TransientErr = -65562, // transient failures, e.g. sending packets shortly after a network transition or wake from sleep
mStatus_ServiceNotRunning = -65563, // Background daemon not running
mStatus_NATPortMappingUnsupported = -65564, // NAT doesn't support NAT-PMP or UPnP
mStatus_NATPortMappingDisabled = -65565, // NAT supports NAT-PMP or UPnP but it's disabled by the administrator
mStatus_NoRouter = -65566,
mStatus_PollingMode = -65567,
mStatus_Timeout = -65568,
// -65568 to -65786 currently unused; available for allocation
// tcp connection status
mStatus_ConnPending = -65787,
mStatus_ConnFailed = -65788,
mStatus_ConnEstablished = -65789,
// Non-error values:
mStatus_GrowCache = -65790,
mStatus_ConfigChanged = -65791,
mStatus_MemFree = -65792 // Last value: 0xFFFE FF00
// mStatus_MemFree is the last legal mDNS error code, at the end of the range allocated for mDNS
};
typedef mDNSs32 mStatus;
// RFC 1034/1035 specify that a domain label consists of a length byte plus up to 63 characters
#define MAX_DOMAIN_LABEL 63
typedef struct {
mDNSu8 c[ 64];
} domainlabel; // One label: length byte and up to 63 characters
// RFC 1034/1035/2181 specify that a domain name (length bytes and data bytes) may be up to 255 bytes long,
// plus the terminating zero at the end makes 256 bytes total in the on-the-wire format.
#define MAX_DOMAIN_NAME 256
typedef struct {
mDNSu8 c[256];
} domainname; // Up to 256 bytes of length-prefixed domainlabels
typedef struct {
mDNSu8 c[256];
} UTF8str255; // Null-terminated C string
// The longest legal textual form of a DNS name is 1009 bytes, including the C-string terminating NULL at the end.
// Explanation:
// When a native domainname object is converted to printable textual form using ConvertDomainNameToCString(),
// non-printing characters are represented in the conventional DNS way, as '\ddd', where ddd is a three-digit decimal number.
// The longest legal domain name is 256 bytes, in the form of four labels as shown below:
// Length byte, 63 data bytes, length byte, 63 data bytes, length byte, 63 data bytes, length byte, 62 data bytes, zero byte.
// Each label is encoded textually as characters followed by a trailing dot.
// If every character has to be represented as a four-byte escape sequence, then this makes the maximum textual form four labels
// plus the C-string terminating NULL as shown below:
// 63*4+1 + 63*4+1 + 63*4+1 + 62*4+1 + 1 = 1009.
// Note that MAX_ESCAPED_DOMAIN_LABEL is not normally used: If you're only decoding a single label, escaping is usually not required.
// It is for domain names, where dots are used as label separators, that proper escaping is vital.
#define MAX_ESCAPED_DOMAIN_LABEL 254
#define MAX_ESCAPED_DOMAIN_NAME 1009
// MAX_REVERSE_MAPPING_NAME
// For IPv4: "123.123.123.123.in-addr.arpa." 30 bytes including terminating NUL
// For IPv6: "x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.x.ip6.arpa." 74 bytes including terminating NUL
#define MAX_REVERSE_MAPPING_NAME_V4 30
#define MAX_REVERSE_MAPPING_NAME_V6 74
#define MAX_REVERSE_MAPPING_NAME 74
// Most records have a TTL of 75 minutes, so that their 80% cache-renewal query occurs once per hour.
// For records containing a hostname (in the name on the left, or in the rdata on the right),
// like A, AAAA, reverse-mapping PTR, and SRV, we use a two-minute TTL by default, because we don't want
// them to hang around for too long in the cache if the host in question crashes or otherwise goes away.
#define kStandardTTL (3600UL * 100 / 80)
#define kHostNameTTL 120UL
// Some applications want to register their SRV records with a lower ttl so that in case the server
// using a dynamic port number restarts, the clients will not have stale information for more than
// 10 seconds
#define kHostNameSmallTTL 10UL
// Multicast DNS uses announcements (gratuitous responses) to update peer caches.
// This means it is feasible to use relatively larger TTL values than we might otherwise
// use, because we have a cache coherency protocol to keep the peer caches up to date.
// With Unicast DNS, once an authoritative server gives a record with a certain TTL value to a client
// or caching server, that client or caching server is entitled to hold onto the record until its TTL
// expires, and has no obligation to contact the authoritative server again until that time arrives.
// This means that whereas Multicast DNS can use announcements to pre-emptively update stale data
// before it would otherwise have expired, standard Unicast DNS (not using LLQs) has no equivalent
// mechanism, and TTL expiry is the *only* mechanism by which stale data gets deleted. Because of this,
// we currently limit the TTL to ten seconds in such cases where no dynamic cache updating is possible.
#define kStaticCacheTTL 10
#define DefaultTTLforRRType(X) (((X) == kDNSType_A || (X) == kDNSType_AAAA || (X) == kDNSType_SRV) ? kHostNameTTL : kStandardTTL)
typedef struct AuthRecord_struct AuthRecord;
typedef struct ServiceRecordSet_struct ServiceRecordSet;
typedef struct CacheRecord_struct CacheRecord;
typedef struct CacheGroup_struct CacheGroup;
typedef struct AuthGroup_struct AuthGroup;
typedef struct DNSQuestion_struct DNSQuestion;
typedef struct ZoneData_struct ZoneData;
typedef struct mDNS_struct mDNS;
typedef struct mDNS_PlatformSupport_struct mDNS_PlatformSupport;
typedef struct NATTraversalInfo_struct NATTraversalInfo;
// Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
// The actual definition of these structures appear in the appropriate platform support code
typedef struct TCPSocket_struct TCPSocket;
typedef struct UDPSocket_struct UDPSocket;
//mDNSOpaque16
// ***************************************************************************
#define mDNS_numZones numQuestions
#define mDNS_numPrereqs numAnswers
#define mDNS_numUpdates numAuthorities
typedef packedstruct {
mDNSOpaque16 id;
mDNSOpaque16 flags;
mDNSu16 numQuestions;
mDNSu16 numAnswers;
mDNSu16 numAuthorities;
mDNSu16 numAdditionals;
} DNSMessageHeader;
// We can send and receive packets up to 9000 bytes (Ethernet Jumbo Frame size, if that ever becomes widely used)
// However, in the normal case we try to limit packets to 1500 bytes so that we don't get IP fragmentation on standard Ethernet
// 40 (IPv6 header) + 8 (UDP header) + 12 (DNS message header) + 1440 (DNS message body) = 1500 total
#define AbsoluteMaxDNSMessageData 8940
#define NormalMaxDNSMessageData 1440
typedef packedstruct {
DNSMessageHeader h; // Note: Size 12 bytes
mDNSu8 data[AbsoluteMaxDNSMessageData]; // 40 (IPv6) + 8 (UDP) + 12 (DNS header) + 8940 (data) = 9000
} DNSMessage;
typedef struct tcpInfo_t {
mDNS *m;
TCPSocket *sock;
DNSMessage request;
int requestLen;
DNSQuestion *question; // For queries
AuthRecord *rr; // For record updates
mDNSAddr Addr;
mDNSIPPort Port;
mDNSIPPort SrcPort;
DNSMessage *reply;
mDNSu16 replylen;
unsigned long nread;
int numReplies;
} tcpInfo_t;
// ***************************************************************************
typedef packedstruct {
mDNSEthAddr dst;
mDNSEthAddr src;
mDNSOpaque16 ethertype;
} EthernetHeader; // 14 bytes
typedef packedstruct {
mDNSOpaque16 hrd;
mDNSOpaque16 pro;
mDNSu8 hln;
mDNSu8 pln;
mDNSOpaque16 op;
mDNSEthAddr sha;
mDNSv4Addr spa;
mDNSEthAddr tha;
mDNSv4Addr tpa;
} ARP_EthIP; // 28 bytes
typedef packedstruct {
mDNSu8 vlen;
mDNSu8 tos;
mDNSu16 totlen;
mDNSOpaque16 id;
mDNSOpaque16 flagsfrags;
mDNSu8 ttl;
mDNSu8 protocol; // Payload type: 0x06 = TCP, 0x11 = UDP
mDNSu16 checksum;
mDNSv4Addr src;
mDNSv4Addr dst;
} IPv4Header; // 20 bytes
typedef packedstruct {
mDNSu32 vcf; // Version, Traffic Class, Flow Label
mDNSu16 len; // Payload Length
mDNSu8 pro; // Type of next header: 0x06 = TCP, 0x11 = UDP, 0x3A = ICMPv6
mDNSu8 ttl; // Hop Limit
mDNSv6Addr src;
mDNSv6Addr dst;
} IPv6Header; // 40 bytes
typedef packedstruct {
mDNSv6Addr src;
mDNSv6Addr dst;
mDNSOpaque32 len;
mDNSOpaque32 pro;
} IPv6PseudoHeader; // 40 bytes
typedef union {
mDNSu8 bytes[20];
ARP_EthIP arp;
IPv4Header v4;
IPv6Header v6;
} NetworkLayerPacket;
typedef packedstruct {
mDNSIPPort src;
mDNSIPPort dst;
mDNSu32 seq;
mDNSu32 ack;
mDNSu8 offset;
mDNSu8 flags;
mDNSu16 window;
mDNSu16 checksum;
mDNSu16 urgent;
} TCPHeader; // 20 bytes; IP protocol type 0x06
typedef packedstruct {
mDNSIPPort src;
mDNSIPPort dst;
mDNSu16 len; // Length including UDP header (i.e. minimum value is 8 bytes)
mDNSu16 checksum;
} UDPHeader; // 8 bytes; IP protocol type 0x11
typedef packedstruct {
mDNSu8 type; // 0x87 == Neighbor Solicitation, 0x88 == Neighbor Advertisement
mDNSu8 code;
mDNSu16 checksum;
mDNSu32 flags_res; // R/S/O flags and reserved bits
mDNSv6Addr target;
// Typically 8 bytes of options are also present
} IPv6NDP; // 24 bytes or more; IP protocol type 0x3A
#define NDP_Sol 0x87
#define NDP_Adv 0x88
#define NDP_Router 0x80
#define NDP_Solicited 0x40
#define NDP_Override 0x20
#define NDP_SrcLL 1
#define NDP_TgtLL 2
typedef union {
mDNSu8 bytes[20];
TCPHeader tcp;
UDPHeader udp;
IPv6NDP ndp;
} TransportLayerPacket;
typedef packedstruct {
mDNSOpaque64 InitiatorCookie;
mDNSOpaque64 ResponderCookie;
mDNSu8 NextPayload;
mDNSu8 Version;
mDNSu8 ExchangeType;
mDNSu8 Flags;
mDNSOpaque32 MessageID;
mDNSu32 Length;
} IKEHeader; // 28 bytes
enum {
kDNSRecordTypeUnregistered = 0x00, // Not currently in any list
kDNSRecordTypeDeregistering = 0x01, // Shared record about to announce its departure and leave the list
kDNSRecordTypeUnique = 0x02, // Will become a kDNSRecordTypeVerified when probing is complete
kDNSRecordTypeAdvisory = 0x04, // Like Shared, but no goodbye packet
kDNSRecordTypeShared = 0x08, // Shared means record name does not have to be unique -- use random delay on responses
kDNSRecordTypeVerified = 0x10, // Unique means mDNS should check that name is unique (and then send immediate responses)
kDNSRecordTypeKnownUnique = 0x20, // Known Unique means mDNS can assume name is unique without checking
// For Dynamic Update records, Known Unique means the record must already exist on the server.
kDNSRecordTypeUniqueMask = (kDNSRecordTypeUnique | kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
kDNSRecordTypeActiveSharedMask = (kDNSRecordTypeAdvisory | kDNSRecordTypeShared),
kDNSRecordTypeActiveUniqueMask = (kDNSRecordTypeVerified | kDNSRecordTypeKnownUnique),
kDNSRecordTypeActiveMask = (kDNSRecordTypeActiveSharedMask | kDNSRecordTypeActiveUniqueMask),
kDNSRecordTypePacketAdd = 0x80, // Received in the Additional Section of a DNS Response
kDNSRecordTypePacketAddUnique = 0x90, // Received in the Additional Section of a DNS Response with kDNSClass_UniqueRRSet set
kDNSRecordTypePacketAuth = 0xA0, // Received in the Authorities Section of a DNS Response
kDNSRecordTypePacketAuthUnique = 0xB0, // Received in the Authorities Section of a DNS Response with kDNSClass_UniqueRRSet set
kDNSRecordTypePacketAns = 0xC0, // Received in the Answer Section of a DNS Response
kDNSRecordTypePacketAnsUnique = 0xD0, // Received in the Answer Section of a DNS Response with kDNSClass_UniqueRRSet set
kDNSRecordTypePacketNegative = 0xF0, // Pseudo-RR generated to cache non-existence results like NXDomain
kDNSRecordTypePacketUniqueMask = 0x10 // True for PacketAddUnique, PacketAnsUnique, PacketAuthUnique, kDNSRecordTypePacketNegative
};
typedef packedstruct { mDNSu16 priority; mDNSu16 weight; mDNSIPPort port; domainname target; } rdataSRV;
typedef packedstruct { mDNSu16 preference; domainname exchange; } rdataMX;
typedef packedstruct { domainname mbox; domainname txt; } rdataRP;
typedef packedstruct { mDNSu16 preference; domainname map822; domainname mapx400; } rdataPX;
typedef packedstruct {
domainname mname;
domainname rname;
mDNSs32 serial; // Modular counter; increases when zone changes
mDNSu32 refresh; // Time in seconds that a slave waits after successful replication of the database before it attempts replication again
mDNSu32 retry; // Time in seconds that a slave waits after an unsuccessful replication attempt before it attempts replication again
mDNSu32 expire; // Time in seconds that a slave holds on to old data while replication attempts remain unsuccessful
mDNSu32 min; // Nominally the minimum record TTL for this zone, in seconds; also used for negative caching.
} rdataSOA;
#define kDNSOpt_LLQ 1
#define kDNSOpt_Lease 2
#define kDNSOpt_NSID 3
#define kDNSOpt_Owner 4
typedef struct {
mDNSu16 vers;
mDNSu16 llqOp;
mDNSu16 err; // Or UDP reply port, in setup request
// Note: In the in-memory form, there's typically a two-byte space here, so that the following 64-bit id is word-aligned
mDNSOpaque64 id;
mDNSu32 llqlease;
} LLQOptData;
typedef struct {
mDNSu8 vers; // Version number of this Owner OPT record
mDNSs8 seq; // Sleep/wake epoch
mDNSEthAddr HMAC; // Host's primary identifier (e.g. MAC of on-board Ethernet)
mDNSEthAddr IMAC; // Interface's MAC address (if different to primary MAC)
mDNSOpaque48 password; // Optional password
} OwnerOptData;
// Note: rdataOPT format may be repeated an arbitrary number of times in a single resource record
typedef packedstruct {
mDNSu16 opt;
mDNSu16 optlen;
union { LLQOptData llq; mDNSu32 updatelease; OwnerOptData owner; } u;
} rdataOPT;
// Space needed to put OPT records into a packet:
// Header 11 bytes (name 1, type 2, class 2, TTL 4, length 2)
// LLQ rdata 18 bytes (opt 2, len 2, vers 2, op 2, err 2, id 8, lease 4)
// Lease rdata 8 bytes (opt 2, len 2, lease 4)
// Owner rdata 12-24 (opt 2, len 2, owner 8-20)
#define DNSOpt_Header_Space 11
#define DNSOpt_LLQData_Space (4 + 2 + 2 + 2 + 8 + 4)
#define DNSOpt_LeaseData_Space (4 + 4)
#define DNSOpt_OwnerData_ID_Space (4 + 2 + 6)
#define DNSOpt_OwnerData_ID_Wake_Space (4 + 2 + 6 + 6)
#define DNSOpt_OwnerData_ID_Wake_PW4_Space (4 + 2 + 6 + 6 + 4)
#define DNSOpt_OwnerData_ID_Wake_PW6_Space (4 + 2 + 6 + 6 + 6)
#define ValidOwnerLength(X) ( (X) == DNSOpt_OwnerData_ID_Space - 4 || \
(X) == DNSOpt_OwnerData_ID_Wake_Space - 4 || \
(X) == DNSOpt_OwnerData_ID_Wake_PW4_Space - 4 || \
(X) == DNSOpt_OwnerData_ID_Wake_PW6_Space - 4 )
#define DNSOpt_Owner_Space(A,B) (mDNSSameEthAddress((A),(B)) ? DNSOpt_OwnerData_ID_Space : DNSOpt_OwnerData_ID_Wake_Space)
#define DNSOpt_Data_Space(O) ( \
(O)->opt == kDNSOpt_LLQ ? DNSOpt_LLQData_Space : \
(O)->opt == kDNSOpt_Lease ? DNSOpt_LeaseData_Space : \
(O)->opt == kDNSOpt_Owner ? DNSOpt_Owner_Space(&(O)->u.owner.HMAC, &(O)->u.owner.IMAC) : 0x10000)
// A maximal NSEC record is:
// 256 bytes domainname 'nextname'
// + 256 * 34 = 8704 bytes of bitmap data
// = 8960 bytes total
// For now we only support NSEC records encoding DNS types 0-255 and ignore the nextname (we always set it to be the same as the rrname),
// which gives us a fixed in-memory size of 32 bytes (256 bits)
typedef struct {
mDNSu8 bitmap[32];
} rdataNSEC;
// StandardAuthRDSize is 264 (256+8), which is large enough to hold a maximum-sized SRV record (6 + 256 bytes)
// MaximumRDSize is 8K the absolute maximum we support (at least for now)
#define StandardAuthRDSize 264
#define MaximumRDSize 8192
// InlineCacheRDSize is 68
// Records received from the network with rdata this size or less have their rdata stored right in the CacheRecord object
// Records received from the network with rdata larger than this have additional storage allocated for the rdata
// A quick unscientific sample from a busy network at Apple with lots of machines revealed this:
// 1461 records in cache
// 292 were one-byte TXT records
// 136 were four-byte A records
// 184 were sixteen-byte AAAA records
// 780 were various PTR, TXT and SRV records from 12-64 bytes
// Only 69 records had rdata bigger than 64 bytes
// Note that since CacheRecord object and a CacheGroup object are allocated out of the same pool, it's sensible to
// have them both be the same size. Making one smaller without making the other smaller won't actually save any memory.
#define InlineCacheRDSize 68
// On 64-bit, the pointers in a CacheRecord are bigger, and that creates 8 bytes more space for the name in a CacheGroup
#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
#if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64)
#define InlineCacheGroupNameSize 160
#else
#define InlineCacheGroupNameSize 148
#endif
#else
#if defined(_ILP64) || defined(__ILP64__) || defined(_LP64) || defined(__LP64__) || defined(_WIN64)
#define InlineCacheGroupNameSize 144
#else
#define InlineCacheGroupNameSize 132
#endif
#endif
// The RDataBody union defines the common rdata types that fit into our 264-byte limit
typedef union {
mDNSu8 data[StandardAuthRDSize];
mDNSv4Addr ipv4; // For 'A' record
domainname name; // For PTR, NS, CNAME, DNAME
UTF8str255 txt;
rdataMX mx;
mDNSv6Addr ipv6; // For 'AAAA' record
rdataSRV srv;
rdataOPT opt[2]; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
rdataNSEC nsec;
} RDataBody;
// The RDataBody2 union is the same as above, except it includes fields for the larger types like soa, rp, px
typedef union {
mDNSu8 data[StandardAuthRDSize];
mDNSv4Addr ipv4; // For 'A' record
domainname name; // For PTR, NS, CNAME, DNAME
rdataSOA soa; // This is large; not included in the normal RDataBody definition
UTF8str255 txt;
rdataMX mx;
rdataRP rp; // This is large; not included in the normal RDataBody definition
rdataPX px; // This is large; not included in the normal RDataBody definition
mDNSv6Addr ipv6; // For 'AAAA' record
rdataSRV srv;
rdataOPT opt[2]; // For EDNS0 OPT record; RDataBody may contain multiple variable-length rdataOPT objects packed together
rdataNSEC nsec;
} RDataBody2;
typedef struct {
mDNSu16 MaxRDLength; // Amount of storage allocated for rdata (usually sizeof(RDataBody))
mDNSu16 padding; // So that RDataBody is aligned on 32-bit boundary
RDataBody u;
} RData;
// sizeofRDataHeader should be 4 bytes
#define sizeofRDataHeader (sizeof(RData) - sizeof(RDataBody))
// RData_small is a smaller version of the RData object, used for inline data storage embedded in a CacheRecord_struct
typedef struct {
mDNSu16 MaxRDLength; // Storage allocated for data (may be greater than InlineCacheRDSize if additional storage follows this object)
mDNSu16 padding; // So that data is aligned on 32-bit boundary
mDNSu8 data[InlineCacheRDSize];
} RData_small;
// Note: Within an mDNSRecordCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
typedef void mDNSRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
// Note:
// Restrictions: An mDNSRecordUpdateCallback may not make any mDNS API calls.
// The intent of this callback is to allow the client to free memory, if necessary.
// The internal data structures of the mDNS code may not be in a state where mDNS API calls may be made safely.
typedef void mDNSRecordUpdateCallback(mDNS *const m, AuthRecord *const rr, RData *OldRData, mDNSu16 OldRDLen);
// ***************************************************************************
#define NATMAP_MAX_RETRY_INTERVAL ((mDNSPlatformOneSecond * 60) * 15) // Max retry interval is 15 minutes
#define NATMAP_MIN_RETRY_INTERVAL (mDNSPlatformOneSecond * 2) // Min retry interval is 2 seconds
#define NATMAP_INIT_RETRY (mDNSPlatformOneSecond / 4) // start at 250ms w/ exponential decay
#define NATMAP_DEFAULT_LEASE (60 * 60 * 2) // 2 hour lease life in seconds
#define NATMAP_VERS 0
typedef enum {
NATOp_AddrRequest = 0,
NATOp_MapUDP = 1,
NATOp_MapTCP = 2,
NATOp_AddrResponse = 0x80 | 0,
NATOp_MapUDPResponse = 0x80 | 1,
NATOp_MapTCPResponse = 0x80 | 2,
} NATOp_t;
enum {
NATErr_None = 0,
NATErr_Vers = 1,
NATErr_Refused = 2,
NATErr_NetFail = 3,
NATErr_Res = 4,
NATErr_Opcode = 5
};
typedef mDNSu16 NATErr_t;
typedef packedstruct {
mDNSu8 vers;
mDNSu8 opcode;
} NATAddrRequest;
typedef packedstruct {
mDNSu8 vers;
mDNSu8 opcode;
mDNSu16 err;
mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds
mDNSv4Addr ExtAddr;
} NATAddrReply;
typedef packedstruct {
mDNSu8 vers;
mDNSu8 opcode;
mDNSOpaque16 unused;
mDNSIPPort intport;
mDNSIPPort extport;
mDNSu32 NATReq_lease;
} NATPortMapRequest;
typedef packedstruct {
mDNSu8 vers;
mDNSu8 opcode;
mDNSu16 err;
mDNSu32 upseconds; // Time since last NAT engine reboot, in seconds
mDNSIPPort intport;
mDNSIPPort extport;
mDNSu32 NATRep_lease;
} NATPortMapReply;
typedef enum {
LNTDiscoveryOp = 1,
LNTExternalAddrOp = 2,
LNTPortMapOp = 3,
LNTPortMapDeleteOp = 4
} LNTOp_t;
#define LNT_MAXBUFSIZE 8192
typedef struct tcpLNTInfo_struct tcpLNTInfo;
struct tcpLNTInfo_struct {
tcpLNTInfo *next;
mDNS *m;
NATTraversalInfo *parentNATInfo; // pointer back to the parent NATTraversalInfo
TCPSocket *sock;
LNTOp_t op; // operation performed using this connection
mDNSAddr Address; // router address
mDNSIPPort Port; // router port
mDNSu8 *Request; // xml request to router
int requestLen;
mDNSu8 *Reply; // xml reply from router
int replyLen;
unsigned long nread; // number of bytes read so far
int retries; // number of times we've tried to do this port mapping
};
typedef void (*NATTraversalClientCallback)(mDNS *m, NATTraversalInfo *n);
// if m->timenow < ExpiryTime then we have an active mapping, and we'll renew halfway to expiry
// if m->timenow >= ExpiryTime then our mapping has expired, and we're trying to create one
struct NATTraversalInfo_struct {
// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
NATTraversalInfo *next;
mDNSs32 ExpiryTime; // Time this mapping expires, or zero if no mapping
mDNSs32 retryInterval; // Current interval, between last packet we sent and the next one
mDNSs32 retryPortMap; // If Protocol is nonzero, time to send our next mapping packet
mStatus NewResult; // New error code; will be copied to Result just prior to invoking callback
#ifdef _LEGACY_NAT_TRAVERSAL_
tcpLNTInfo tcpInfo; // Legacy NAT traversal (UPnP) TCP connection
#endif
// Result fields: When the callback is invoked these fields contain the answers the client is looking for
// When the callback is invoked ExternalPort is *usually* set to be the same the same as RequestedPort, except:
// (a) When we're behind a NAT gateway with port mapping disabled, ExternalPort is reported as zero to
// indicate that we don't currently have a working mapping (but RequestedPort retains the external port
// we'd like to get, the next time we meet an accomodating NAT gateway willing to give us one).
// (b) When we have a routable non-RFC1918 address, we don't *need* a port mapping, so ExternalPort
// is reported as the same as our InternalPort, since that is effectively our externally-visible port too.
// Again, RequestedPort retains the external port we'd like to get the next time we find ourself behind a NAT gateway.
// To improve stability of port mappings, RequestedPort is updated any time we get a successful
// mapping response from the NAT-PMP or UPnP gateway. For example, if we ask for port 80, and
// get assigned port 81, then thereafter we'll contine asking for port 81.
mDNSInterfaceID InterfaceID;
mDNSv4Addr ExternalAddress; // Initially set to onesIPv4Addr, until first callback
mDNSIPPort ExternalPort;
mDNSu32 Lifetime;
mStatus Result;
// Client API fields: The client must set up these fields *before* making any NAT traversal API calls
mDNSu8 Protocol; // NATOp_MapUDP or NATOp_MapTCP, or zero if just requesting the external IP address
mDNSIPPort IntPort; // Client's internal port number (doesn't change)
mDNSIPPort RequestedPort; // Requested external port; may be updated with actual value assigned by gateway
mDNSu32 NATLease; // Requested lifetime in seconds (doesn't change)
NATTraversalClientCallback clientCallback;
void *clientContext;
};
enum {
DNSServer_Untested = 0,
DNSServer_Passed = 1,
DNSServer_Failed = 2,
DNSServer_Disabled = 3
};
enum {
DNSServer_FlagDelete = 1,
DNSServer_FlagNew = 2
};
enum {
McastResolver_FlagDelete = 1,
McastResolver_FlagNew = 2
};
typedef struct McastResolver {
struct McastResolver *next;
mDNSInterfaceID interface;
mDNSu32 flags; // Set when we're planning to delete this from the list
domainname domain;
mDNSu32 timeout; // timeout value for questions
} McastResolver;
typedef struct DNSServer {
struct DNSServer *next;
mDNSInterfaceID interface; // For specialized uses; we can have DNS servers reachable over specific interfaces
mDNSAddr addr;
mDNSIPPort port;
mDNSOpaque16 testid;
mDNSu32 flags; // Set when we're planning to delete this from the list
mDNSu32 teststate; // Have we sent bug-detection query to this server?
mDNSs32 lasttest; // Time we sent last bug-detection query to this server
domainname domain; // name->server matching for "split dns"
mDNSs32 penaltyTime; // amount of time this server is penalized
mDNSBool scoped; // interface should be matched against question only
// if scoped is set
mDNSu32 timeout; // timeout value for questions
mDNSBool cellIntf; // Resolver from Cellular Interface ?
} DNSServer;
typedef struct { // Size is 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
mDNSu8 RecordType; // See enum above
mDNSu16 rrtype;
mDNSu16 rrclass;
mDNSu32 rroriginalttl; // In seconds
mDNSu16 rdlength; // Size of the raw rdata, in bytes, in the on-the-wire format
// (In-memory storage may be larger, for structures containing 'holes', like SOA,
// or smaller, for NSEC where we don't bother storing the nextname field)
mDNSu16 rdestimate; // Upper bound on on-the-wire size of rdata after name compression
mDNSu32 namehash; // Name-based (i.e. case-insensitive) hash of name
mDNSu32 rdatahash; // For rdata containing domain name (e.g. PTR, SRV, CNAME etc.), case-insensitive name hash
// else, for all other rdata, 32-bit hash of the raw rdata
// Note: This requirement is important. Various routines like AddAdditionalsToResponseList(),
// ReconfirmAntecedents(), etc., use rdatahash as a pre-flight check to see
// whether it's worth doing a full SameDomainName() call. If the rdatahash
// is not a correct case-insensitive name hash, they'll get false negatives.
// Grouping pointers together at the end of the structure improves the memory layout efficiency
mDNSInterfaceID InterfaceID; // Set if this RR is specific to one interface
// For records received off the wire, InterfaceID is *always* set to the receiving interface
// For our authoritative records, InterfaceID is usually zero, except for those few records
// that are interface-specific (e.g. address records, especially linklocal addresses)
const domainname *name;
RData *rdata; // Pointer to storage for this rdata
DNSServer *rDNSServer; // Unicast DNS server authoritative for this entry;null for multicast
} ResourceRecord;
// Unless otherwise noted, states may apply to either independent record registrations or service registrations
typedef enum {
regState_Zero = 0,
regState_Pending = 1, // update sent, reply not received
regState_Registered = 2, // update sent, reply received
regState_DeregPending = 3, // dereg sent, reply not received
regState_Unregistered = 4, // not in any list
regState_Refresh = 5, // outstanding refresh (or target change) message
regState_NATMap = 6, // establishing NAT port mapping
regState_UpdatePending = 7, // update in flight as result of mDNS_Update call
regState_NoTarget = 8, // SRV Record registration pending registration of hostname
regState_NATError = 9 // unable to complete NAT traversal
} regState_t;
enum {
Target_Manual = 0,
Target_AutoHost = 1,
Target_AutoHostAndNATMAP = 2
};
typedef enum {
mergeState_Zero = 0,
mergeState_DontMerge = 1 // Set on fatal error conditions to disable merging
} mergeState_t;
struct AuthGroup_struct { // Header object for a list of AuthRecords with the same name
AuthGroup *next; // Next AuthGroup object in this hash table bucket
mDNSu32 namehash; // Name-based (i.e. case insensitive) hash of name
AuthRecord *members; // List of CacheRecords with this same name
AuthRecord **rrauth_tail; // Tail end of that list
domainname *name; // Common name for all AuthRecords in this list
AuthRecord *NewLocalOnlyRecords;
// Size to here is 20 bytes when compiling 32-bit; 40 bytes when compiling 64-bit
mDNSu8 namestorage[InlineCacheGroupNameSize];
};
#define AUTH_HASH_SLOTS 499
#define FORALL_AUTHRECORDS(SLOT,AG,AR) \
for ((SLOT) = 0; (SLOT) < AUTH_HASH_SLOTS; (SLOT)++) \
for ((AG)=m->rrauth.rrauth_hash[(SLOT)]; (AG); (AG)=(AG)->next) \
for ((AR) = (AG)->members; (AR); (AR)=(AR)->next)
typedef union AuthEntity_union AuthEntity;
union AuthEntity_union {
AuthEntity *next;
AuthGroup ag;
};
typedef struct {
mDNSu32 rrauth_size; // Total number of available auth entries
mDNSu32 rrauth_totalused; // Number of auth entries currently occupied
mDNSu32 rrauth_report;
mDNSu8 rrauth_lock; // For debugging: Set at times when these lists may not be modified
AuthEntity *rrauth_free;
AuthGroup *rrauth_hash[AUTH_HASH_SLOTS];
} AuthHash;
// AuthRecordAny includes mDNSInterface_Any and interface specific auth records (anything
// other than P2P or LocalOnly)
typedef enum {
AuthRecordAny, // registered for *Any, NOT including P2P interfaces
AuthRecordAnyIncludeP2P, // registered for *Any, including P2P interfaces
AuthRecordLocalOnly,
AuthRecordP2P // discovered over D2D/P2P framework
} AuthRecType;
struct AuthRecord_struct {
// For examples of how to set up this structure for use in mDNS_Register(),
// see mDNS_AdvertiseInterface() or mDNS_RegisterService().
// Basically, resrec and persistent metadata need to be set up before calling mDNS_Register().
// mDNS_SetupResourceRecord() is avaliable as a helper routine to set up most fields to sensible default values for you
AuthRecord *next; // Next in list; first element of structure for efficiency reasons
// Field Group 1: Common ResourceRecord fields
ResourceRecord resrec; // 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
// Field Group 2: Persistent metadata for Authoritative Records
AuthRecord *Additional1; // Recommended additional record to include in response (e.g. SRV for PTR record)
AuthRecord *Additional2; // Another additional (e.g. TXT for PTR record)
AuthRecord *DependentOn; // This record depends on another for its uniqueness checking
AuthRecord *RRSet; // This unique record is part of an RRSet
mDNSRecordCallback *RecordCallback; // Callback function to call for state changes, and to free memory asynchronously on deregistration
void *RecordContext; // Context parameter for the callback function
mDNSu8 AutoTarget; // Set if the target of this record (PTR, CNAME, SRV, etc.) is our host name
mDNSu8 AllowRemoteQuery; // Set if we allow hosts not on the local link to query this record
mDNSu8 ForceMCast; // Set by client to advertise solely via multicast, even for apparently unicast names
OwnerOptData WakeUp; // WakeUp.HMAC.l[0] nonzero indicates that this is a Sleep Proxy record
mDNSAddr AddressProxy; // For reverse-mapping Sleep Proxy PTR records, address in question
mDNSs32 TimeRcvd; // In platform time units
mDNSs32 TimeExpire; // In platform time units
AuthRecType ARType; // LocalOnly, P2P or Normal ?
// Field Group 3: Transient state for Authoritative Records
mDNSu8 Acknowledged; // Set if we've given the success callback to the client
mDNSu8 ProbeCount; // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
mDNSu8 AnnounceCount; // Number of announcements remaining (kDNSRecordTypeShared)
mDNSu8 RequireGoodbye; // Set if this RR has been announced on the wire and will require a goodbye packet
mDNSu8 AnsweredLocalQ; // Set if this AuthRecord has been delivered to any local question (LocalOnly or mDNSInterface_Any)
mDNSu8 IncludeInProbe; // Set if this RR is being put into a probe right now
mDNSu8 ImmedUnicast; // Set if we may send our response directly via unicast to the requester
mDNSInterfaceID SendNSECNow; // Set if we need to generate associated NSEC data for this rrname
mDNSInterfaceID ImmedAnswer; // Someone on this interface issued a query we need to answer (all-ones for all interfaces)
#if MDNS_LOG_ANSWER_SUPPRESSION_TIMES
mDNSs32 ImmedAnswerMarkTime;
#endif
mDNSInterfaceID ImmedAdditional; // Hint that we might want to also send this record, just to be helpful
mDNSInterfaceID SendRNow; // The interface this query is being sent on right now
mDNSv4Addr v4Requester; // Recent v4 query for this record, or all-ones if more than one recent query
mDNSv6Addr v6Requester; // Recent v6 query for this record, or all-ones if more than one recent query
AuthRecord *NextResponse; // Link to the next element in the chain of responses to generate
const mDNSu8 *NR_AnswerTo; // Set if this record was selected by virtue of being a direct answer to a question
AuthRecord *NR_AdditionalTo; // Set if this record was selected by virtue of being additional to another
mDNSs32 ThisAPInterval; // In platform time units: Current interval for announce/probe
mDNSs32 LastAPTime; // In platform time units: Last time we sent announcement/probe
mDNSs32 LastMCTime; // Last time we multicast this record (used to guard against packet-storm attacks)
mDNSInterfaceID LastMCInterface; // Interface this record was multicast on at the time LastMCTime was recorded
RData *NewRData; // Set if we are updating this record with new rdata
mDNSu16 newrdlength; // ... and the length of the new RData
mDNSRecordUpdateCallback *UpdateCallback;
mDNSu32 UpdateCredits; // Token-bucket rate limiting of excessive updates
mDNSs32 NextUpdateCredit; // Time next token is added to bucket
mDNSs32 UpdateBlocked; // Set if update delaying is in effect
// Field Group 4: Transient uDNS state for Authoritative Records
regState_t state; // Maybe combine this with resrec.RecordType state? Right now it's ambiguous and confusing.
// e.g. rr->resrec.RecordType can be kDNSRecordTypeUnregistered,
// and rr->state can be regState_Unregistered
// What if we find one of those statements is true and the other false? What does that mean?
mDNSBool uselease; // dynamic update contains (should contain) lease option
mDNSs32 expire; // In platform time units: expiration of lease (-1 for static)
mDNSBool Private; // If zone is private, DNS updates may have to be encrypted to prevent eavesdropping
mDNSOpaque16 updateid; // Identifier to match update request and response -- also used when transferring records to Sleep Proxy
const domainname *zone; // the zone that is updated
ZoneData *nta;
struct tcpInfo_t *tcp;
NATTraversalInfo NATinfo;
mDNSBool SRVChanged; // temporarily deregistered service because its SRV target or port changed
mergeState_t mState; // Unicast Record Registrations merge state
mDNSu8 refreshCount; // Number of refreshes to the server
mStatus updateError; // Record update resulted in Error ?
// uDNS_UpdateRecord support fields
// Do we really need all these in *addition* to NewRData and newrdlength above?
void *UpdateContext; // Context parameter for the update callback function
mDNSu16 OrigRDLen; // previously registered, being deleted
mDNSu16 InFlightRDLen; // currently being registered
mDNSu16 QueuedRDLen; // pending operation (re-transmitting if necessary) THEN register the queued update
RData *OrigRData;
RData *InFlightRData;
RData *QueuedRData;
// Field Group 5: Large data objects go at the end
domainname namestorage;
RData rdatastorage; // Normally the storage is right here, except for oversized records
// rdatastorage MUST be the last thing in the structure -- when using oversized AuthRecords, extra bytes
// are appended after the end of the AuthRecord, logically augmenting the size of the rdatastorage
// DO NOT ADD ANY MORE FIELDS HERE
};
// IsLocalDomain alone is not sufficient to determine that a record is mDNS or uDNS. By default domain names within
// the "local" pseudo-TLD (and within the IPv4 and IPv6 link-local reverse mapping domains) are automatically treated
// as mDNS records, but it is also possible to force any record (even those not within one of the inherently local
// domains) to be handled as an mDNS record by setting the ForceMCast flag, or by setting a non-zero InterfaceID.
// For example, the reverse-mapping PTR record created in AdvertiseInterface sets the ForceMCast flag, since it points to
// a dot-local hostname, and therefore it would make no sense to register this record with a wide-area Unicast DNS server.
// The same applies to Sleep Proxy records, which we will answer for when queried via mDNS, but we never want to try
// to register them with a wide-area Unicast DNS server -- and we probably don't have the required credentials anyway.
// Currently we have no concept of a wide-area uDNS record scoped to a particular interface, so if the InterfaceID is
// nonzero we treat this the same as ForceMCast.
// Note: Question_uDNS(Q) is used in *only* one place -- on entry to mDNS_StartQuery_internal, to decide whether to set TargetQID.
// Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero.
#define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name))
#define Question_uDNS(Q) ((Q)->InterfaceID == mDNSInterface_Unicast || \
((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
#define RRLocalOnly(rr) ((rr)->ARType == AuthRecordLocalOnly || (rr)->ARType == AuthRecordP2P)
#define RRAny(rr) ((rr)->ARType == AuthRecordAny || (rr)->ARType == AuthRecordAnyIncludeP2P)
// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
// is not available locally for A or AAAA question respectively
#define QuerySuppressed(Q) ((Q)->SuppressUnusable && (Q)->SuppressQuery)
#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel)
// Normally we always lookup the cache and /etc/hosts before sending the query on the wire. For single label
// queries (A and AAAA) that are unqualified (indicated by AppendSearchDomains), we want to append search
// domains before we try them as such
#define ApplySearchDomainsFirst(q) ((q)->AppendSearchDomains && (CountLabels(&((q)->qname))) == 1)
// Wrapper struct for Auth Records for higher-level code that cannot use the AuthRecord's ->next pointer field
typedef struct ARListElem {
struct ARListElem *next;
AuthRecord ar; // Note: Must be last element of structure, to accomodate oversized AuthRecords
} ARListElem;
struct CacheGroup_struct { // Header object for a list of CacheRecords with the same name
CacheGroup *next; // Next CacheGroup object in this hash table bucket
mDNSu32 namehash; // Name-based (i.e. case insensitive) hash of name
CacheRecord *members; // List of CacheRecords with this same name
CacheRecord **rrcache_tail; // Tail end of that list
domainname *name; // Common name for all CacheRecords in this list
// Size to here is 20 bytes when compiling 32-bit; 40 bytes when compiling 64-bit
mDNSu8 namestorage[InlineCacheGroupNameSize];
};
struct CacheRecord_struct {
CacheRecord *next; // Next in list; first element of structure for efficiency reasons
ResourceRecord resrec; // 36 bytes when compiling for 32-bit; 48 when compiling for 64-bit
// Transient state for Cache Records
CacheRecord *NextInKAList; // Link to the next element in the chain of known answers to send
mDNSs32 TimeRcvd; // In platform time units
mDNSs32 DelayDelivery; // Set if we want to defer delivery of this answer to local clients
mDNSs32 NextRequiredQuery; // In platform time units
mDNSs32 LastUsed; // In platform time units
DNSQuestion *CRActiveQuestion; // Points to an active question referencing this answer. Can never point to a NewQuestion.
mDNSu32 UnansweredQueries; // Number of times we've issued a query for this record without getting an answer
mDNSs32 LastUnansweredTime; // In platform time units; last time we incremented UnansweredQueries
#if ENABLE_MULTI_PACKET_QUERY_SNOOPING
mDNSu32 MPUnansweredQ; // Multi-packet query handling: Number of times we've seen a query for this record
mDNSs32 MPLastUnansweredQT; // Multi-packet query handling: Last time we incremented MPUnansweredQ
mDNSu32 MPUnansweredKA; // Multi-packet query handling: Number of times we've seen this record in a KA list
mDNSBool MPExpectingKA; // Multi-packet query handling: Set when we increment MPUnansweredQ; allows one KA
#endif
CacheRecord *NextInCFList; // Set if this is in the list of records we just received with the cache flush bit set
// Size to here is 76 bytes when compiling 32-bit; 104 bytes when compiling 64-bit
RData_small smallrdatastorage; // Storage for small records is right here (4 bytes header + 68 bytes data = 72 bytes)
};
// Storage sufficient to hold either a CacheGroup header or a CacheRecord
// -- for best efficiency (to avoid wasted unused storage) they should be the same size
typedef union CacheEntity_union CacheEntity;
union CacheEntity_union {
CacheEntity *next;
CacheGroup cg;
CacheRecord cr;
};
typedef struct {
CacheRecord r;
mDNSu8 _extradata[MaximumRDSize - InlineCacheRDSize]; // Glue on the necessary number of extra bytes
domainname namestorage; // Needs to go *after* the extra rdata bytes
} LargeCacheRecord;
typedef struct HostnameInfo {
struct HostnameInfo *next;
NATTraversalInfo natinfo;
domainname fqdn;
AuthRecord arv4; // registered IPv4 address record
AuthRecord arv6; // registered IPv6 address record
mDNSRecordCallback *StatusCallback; // callback to deliver success or error code to client layer
const void *StatusContext; // Client Context
} HostnameInfo;
typedef struct ExtraResourceRecord_struct ExtraResourceRecord;
struct ExtraResourceRecord_struct {
ExtraResourceRecord *next;
mDNSu32 ClientID; // Opaque ID field to be used by client to map an AddRecord call to a set of Extra records
AuthRecord r;
// Note: Add any additional fields *before* the AuthRecord in this structure, not at the end.
// In some cases clients can allocate larger chunks of memory and set r->rdata->MaxRDLength to indicate
// that this extra memory is available, which would result in any fields after the AuthRecord getting smashed
};
// Note: Within an mDNSServiceCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
typedef void mDNSServiceCallback(mDNS *const m, ServiceRecordSet *const sr, mStatus result);
// A ServiceRecordSet has no special meaning to the core code of the Multicast DNS protocol engine;
// it is just a convenience structure to group together the records that make up a standard service
// registration so that they can be allocted and deallocted together as a single memory object.
// It contains its own ServiceCallback+ServiceContext to report aggregate results up to the next layer of software above.
// It also contains:
// * the basic PTR/SRV/TXT triplet used to represent any DNS-SD service
// * the "_services" PTR record for service enumeration
// * the optional list of SubType PTR records
// * the optional list of additional records attached to the service set (e.g. iChat pictures)
struct ServiceRecordSet_struct {
// These internal state fields are used internally by mDNSCore; the client layer needn't be concerned with them.
// No fields need to be set up by the client prior to calling mDNS_RegisterService();
// all required data is passed as parameters to that function.
mDNSServiceCallback *ServiceCallback;
void *ServiceContext;
mDNSBool Conflict; // Set if this record set was forcibly deregistered because of a conflict
ExtraResourceRecord *Extras; // Optional list of extra AuthRecords attached to this service registration
mDNSu32 NumSubTypes;
AuthRecord *SubTypes;
AuthRecord RR_ADV; // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
AuthRecord RR_PTR; // e.g. _printer._tcp.local. PTR Name._printer._tcp.local.
AuthRecord RR_SRV; // e.g. Name._printer._tcp.local. SRV 0 0 port target
AuthRecord RR_TXT; // e.g. Name._printer._tcp.local. TXT PrintQueueName
// Don't add any fields after AuthRecord RR_TXT.
// This is where the implicit extra space goes if we allocate a ServiceRecordSet containing an oversized RR_TXT record
};
// ***************************************************************************
// We record the last eight instances of each duplicate query
// This gives us v4/v6 on each of Ethernet, AirPort and Firewire, and two free slots "for future expansion"
// If the host has more active interfaces that this it is not fatal -- duplicate question suppression will degrade gracefully.
// Since we will still remember the last eight, the busiest interfaces will still get the effective duplicate question suppression.
#define DupSuppressInfoSize 8
typedef struct {
mDNSs32 Time;
mDNSInterfaceID InterfaceID;
mDNSs32 Type; // v4 or v6?
} DupSuppressInfo;
typedef enum {
LLQ_InitialRequest = 1,
LLQ_SecondaryRequest = 2,
LLQ_Established = 3,
LLQ_Poll = 4
} LLQ_State;
// LLQ constants
#define kLLQ_Vers 1
#define kLLQ_DefLease 7200 // 2 hours
#define kLLQ_MAX_TRIES 3 // retry an operation 3 times max
#define kLLQ_INIT_RESEND 2 // resend an un-ack'd packet after 2 seconds, then double for each additional
// LLQ Operation Codes
#define kLLQOp_Setup 1
#define kLLQOp_Refresh 2
#define kLLQOp_Event 3
// LLQ Errror Codes
enum {
LLQErr_NoError = 0,
LLQErr_ServFull = 1,
LLQErr_Static = 2,
LLQErr_FormErr = 3,
LLQErr_NoSuchLLQ = 4,
LLQErr_BadVers = 5,
LLQErr_UnknownErr = 6
};
enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
#define HMAC_LEN 64
#define HMAC_IPAD 0x36
#define HMAC_OPAD 0x5c
#define MD5_LEN 16
#define AutoTunnelUnregistered(X) ( \
(X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnelService. resrec.RecordType == kDNSRecordTypeUnregistered && \
(X)->AutoTunnel6Record. resrec.RecordType == kDNSRecordTypeUnregistered )
// Internal data structure to maintain authentication information
typedef struct DomainAuthInfo {
struct DomainAuthInfo *next;
mDNSs32 deltime; // If we're planning to delete this DomainAuthInfo, the time we want it deleted
const char *AutoTunnel; // If NULL, this is not an AutoTunnel DAI. Otherwise, this is prepended to the IPSec identifier
AuthRecord AutoTunnelHostRecord; // User-visible hostname; used as SRV target for AutoTunnel services
AuthRecord AutoTunnelTarget; // Opaque hostname of tunnel endpoint; used as SRV target for AutoTunnelService record
AuthRecord AutoTunnelDeviceInfo; // Device info of tunnel endpoint
AuthRecord AutoTunnelService; // Service record (possibly NAT-Mapped) of IKE daemon implementing tunnel endpoint
AuthRecord AutoTunnel6Record; // AutoTunnel AAAA Record obtained from Connectivityd
NATTraversalInfo AutoTunnelNAT;
domainname domain;
domainname keyname;
domainname hostname;
mDNSIPPort port;
char b64keydata[32];
mDNSu8 keydata_ipad[HMAC_LEN]; // padded key for inner hash rounds
mDNSu8 keydata_opad[HMAC_LEN]; // padded key for outer hash rounds
} DomainAuthInfo;
// Note: Within an mDNSQuestionCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
typedef enum { QC_rmv = 0, QC_add = 1, QC_addnocache = 2 } QC_result;
typedef void mDNSQuestionCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
#define NextQSendTime(Q) ((Q)->LastQTime + (Q)->ThisQInterval)
#define ActiveQuestion(Q) ((Q)->ThisQInterval > 0 && !(Q)->DuplicateOf)
#define TimeToSendThisQuestion(Q,time) (ActiveQuestion(Q) && (time) - NextQSendTime(Q) >= 0)
struct DNSQuestion_struct {
// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
DNSQuestion *next;
mDNSu32 qnamehash;
mDNSs32 DelayAnswering; // Set if we want to defer answering this question until the cache settles
mDNSs32 LastQTime; // Last scheduled transmission of this Q on *all* applicable interfaces
mDNSs32 ThisQInterval; // LastQTime + ThisQInterval is the next scheduled transmission of this Q
// ThisQInterval > 0 for an active question;
// ThisQInterval = 0 for a suspended question that's still in the list
// ThisQInterval = -1 for a cancelled question (should not still be in list)
mDNSs32 ExpectUnicastResp;// Set when we send a query with the kDNSQClass_UnicastResponse bit set
mDNSs32 LastAnswerPktNum; // The sequence number of the last response packet containing an answer to this Q
mDNSu32 RecentAnswerPkts; // Number of answers since the last time we sent this query
mDNSu32 CurrentAnswers; // Number of records currently in the cache that answer this question
mDNSu32 LargeAnswers; // Number of answers with rdata > 1024 bytes
mDNSu32 UniqueAnswers; // Number of answers received with kDNSClass_UniqueRRSet bit set
mDNSInterfaceID FlappingInterface1;// Set when an interface goes away, to flag if remove events are delivered for this Q
mDNSInterfaceID FlappingInterface2;// Set when an interface goes away, to flag if remove events are delivered for this Q
DomainAuthInfo *AuthInfo; // Non-NULL if query is currently being done using Private DNS
DNSQuestion *DuplicateOf;
DNSQuestion *NextInDQList;
DupSuppressInfo DupSuppress[DupSuppressInfoSize];
mDNSInterfaceID SendQNow; // The interface this query is being sent on right now
mDNSBool SendOnAll; // Set if we're sending this question on all active interfaces
mDNSu32 RequestUnicast; // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
mDNSs32 LastQTxTime; // Last time this Q was sent on one (but not necessarily all) interfaces
mDNSu32 CNAMEReferrals; // Count of how many CNAME redirections we've done
mDNSBool SuppressQuery; // This query should be suppressed and not sent on the wire
mDNSu8 LOAddressAnswers; // Number of answers from the local only auth records that are
// answering A, AAAA and CNAME (/etc/hosts)
mDNSu8 WakeOnResolveCount; // Number of wakes that should be sent on resolve
mDNSs32 StopTime; // Time this question should be stopped by giving them a negative answer
// Wide Area fields. These are used internally by the uDNS core
UDPSocket *LocalSocket;
mDNSBool deliverAddEvents; // Change in DNSSserver requiring to deliver ADD events
DNSServer *qDNSServer; // Caching server for this query (in the absence of an SRV saying otherwise)
mDNSOpaque64 validDNSServers; // Valid DNSServers for this question
mDNSu16 noServerResponse; // At least one server did not respond.
mDNSu16 triedAllServersOnce; // Tried all DNS servers once
mDNSu8 unansweredQueries;// The number of unanswered queries to this server
ZoneData *nta; // Used for getting zone data for private or LLQ query
mDNSAddr servAddr; // Address and port learned from _dns-llq, _dns-llq-tls or _dns-query-tls SRV query
mDNSIPPort servPort;
struct tcpInfo_t *tcp;
mDNSIPPort tcpSrcPort; // Local Port TCP packet received on;need this as tcp struct is disposed
// by tcpCallback before calling into mDNSCoreReceive
mDNSu8 NoAnswer; // Set if we want to suppress answers until tunnel setup has completed
// LLQ-specific fields. These fields are only meaningful when LongLived flag is set
LLQ_State state;
mDNSu32 ReqLease; // seconds (relative)
mDNSs32 expire; // ticks (absolute)
mDNSs16 ntries; // for UDP: the number of packets sent for this LLQ state
// for TCP: there is some ambiguity in the use of this variable, but in general, it is
// the number of TCP/TLS connection attempts for this LLQ state, or
// the number of packets sent for this TCP/TLS connection
mDNSOpaque64 id;
// Client API fields: The client must set up these fields *before* calling mDNS_StartQuery()
mDNSInterfaceID InterfaceID; // Non-zero if you want to issue queries only on a single specific IP interface
mDNSAddr Target; // Non-zero if you want to direct queries to a specific unicast target address
mDNSIPPort TargetPort; // Must be set if Target is set
mDNSOpaque16 TargetQID; // Must be set if Target is set
domainname qname;
mDNSu16 qtype;
mDNSu16 qclass;
mDNSBool LongLived; // Set by client for calls to mDNS_StartQuery to indicate LLQs to unicast layer.
mDNSBool ExpectUnique; // Set by client if it's expecting unique RR(s) for this question, not shared RRs
mDNSBool ForceMCast; // Set by client to force mDNS query, even for apparently uDNS names
mDNSBool ReturnIntermed; // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
mDNSBool SuppressUnusable; // Set by client to suppress unusable queries to be sent on the wire
mDNSBool RetryWithSearchDomains; // Retry with search domains if there is no entry in the cache or AuthRecords
mDNSu8 TimeoutQuestion; // Timeout this question if there is no reply in configured time
mDNSu8 WakeOnResolve; // Send wakeup on resolve
mDNSs8 SearchListIndex; // Index into SearchList; Used by the client layer but not touched by core
mDNSs8 AppendSearchDomains; // Search domains can be appended for this query
mDNSs8 AppendLocalSearchDomains; // Search domains ending in .local can be appended for this query
domainname *qnameOrig; // Copy of the original question name if it is not fully qualified
mDNSQuestionCallback *QuestionCallback;
void *QuestionContext;
};
typedef struct {
// Client API fields: The client must set up name and InterfaceID *before* calling mDNS_StartResolveService()
// When the callback is invoked, ip, port, TXTlen and TXTinfo will have been filled in with the results learned from the network.
domainname name;
mDNSInterfaceID InterfaceID; // ID of the interface the response was received on
mDNSAddr ip; // Remote (destination) IP address where this service can be accessed
mDNSIPPort port; // Port where this service can be accessed
mDNSu16 TXTlen;
mDNSu8 TXTinfo[2048]; // Additional demultiplexing information (e.g. LPR queue name)
} ServiceInfo;
// Note: Within an mDNSServiceInfoQueryCallback mDNS all API calls are legal except mDNS_Init(), mDNS_Exit(), mDNS_Execute()
typedef struct ServiceInfoQuery_struct ServiceInfoQuery;
typedef void mDNSServiceInfoQueryCallback(mDNS *const m, ServiceInfoQuery *query);
struct ServiceInfoQuery_struct {
// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
// No fields need to be set up by the client prior to calling mDNS_StartResolveService();
// all required data is passed as parameters to that function.
// The ServiceInfoQuery structure memory is working storage for mDNSCore to discover the requested information
// and place it in the ServiceInfo structure. After the client has called mDNS_StopResolveService(), it may
// dispose of the ServiceInfoQuery structure while retaining the results in the ServiceInfo structure.
DNSQuestion qSRV;
DNSQuestion qTXT;
DNSQuestion qAv4;
DNSQuestion qAv6;
mDNSu8 GotSRV;
mDNSu8 GotTXT;
mDNSu8 GotADD;
mDNSu32 Answers;
ServiceInfo *info;
mDNSServiceInfoQueryCallback *ServiceInfoQueryCallback;
void *ServiceInfoQueryContext;
};
typedef enum { ZoneServiceUpdate, ZoneServiceQuery, ZoneServiceLLQ } ZoneService;
typedef void ZoneDataCallback(mDNS *const m, mStatus err, const ZoneData *result);
struct ZoneData_struct {
domainname ChildName; // Name for which we're trying to find the responsible server
ZoneService ZoneService; // Which service we're seeking for this zone (update, query, or LLQ)
domainname *CurrentSOA; // Points to somewhere within ChildName
domainname ZoneName; // Discovered result: Left-hand-side of SOA record
mDNSu16 ZoneClass; // Discovered result: DNS Class from SOA record
domainname Host; // Discovered result: Target host from SRV record
mDNSIPPort Port; // Discovered result: Update port, query port, or LLQ port from SRV record
mDNSAddr Addr; // Discovered result: Address of Target host from SRV record
mDNSBool ZonePrivate; // Discovered result: Does zone require encrypted queries?
ZoneDataCallback *ZoneDataCallback; // Caller-specified function to be called upon completion
void *ZoneDataContext;
DNSQuestion question; // Storage for any active question
};
extern ZoneData *StartGetZoneData(mDNS *const m, const domainname *const name, const ZoneService target, ZoneDataCallback callback, void *callbackInfo);
extern void CancelGetZoneData(mDNS *const m, ZoneData *nta);
extern mDNSBool IsGetZoneDataQuestion(DNSQuestion *q);
typedef struct DNameListElem {
struct DNameListElem *next;
mDNSu32 uid;
domainname name;
} DNameListElem;
#if APPLE_OSX_mDNSResponder
// Different states that we go through locating the peer
#define TC_STATE_AAAA_PEER 0x000000001 /* Peer's BTMM IPv6 address */
#define TC_STATE_AAAA_PEER_RELAY 0x000000002 /* Peer's IPv6 Relay address */
#define TC_STATE_SRV_PEER 0x000000003 /* Peer's SRV Record corresponding to IPv4 address */
#define TC_STATE_ADDR_PEER 0x000000004 /* Peer's IPv4 address */
typedef struct ClientTunnel {
struct ClientTunnel *next;
const char *prefix;
domainname dstname;
mDNSBool MarkedForDeletion;
mDNSv6Addr loc_inner;
mDNSv4Addr loc_outer;
mDNSv6Addr loc_outer6;
mDNSv6Addr rmt_inner;
mDNSv4Addr rmt_outer;
mDNSv6Addr rmt_outer6;
mDNSIPPort rmt_outer_port;
mDNSu16 tc_state;
DNSQuestion q;
} ClientTunnel;
#endif
typedef struct NetworkInterfaceInfo_struct NetworkInterfaceInfo;
// A NetworkInterfaceInfo_struct serves two purposes:
// 1. It holds the address, PTR and HINFO records to advertise a given IP address on a given physical interface
// 2. It tells mDNSCore which physical interfaces are available; each physical interface has its own unique InterfaceID.
// Since there may be multiple IP addresses on a single physical interface,
// there may be multiple NetworkInterfaceInfo_structs with the same InterfaceID.
// In this case, to avoid sending the same packet n times, when there's more than one
// struct with the same InterfaceID, mDNSCore picks one member of the set to be the
// active representative of the set; all others have the 'InterfaceActive' flag unset.
struct NetworkInterfaceInfo_struct {
// Internal state fields. These are used internally by mDNSCore; the client layer needn't be concerned with them.
NetworkInterfaceInfo *next;
mDNSu8 InterfaceActive; // Set if interface is sending & receiving packets (see comment above)
mDNSu8 IPv4Available; // If InterfaceActive, set if v4 available on this InterfaceID
mDNSu8 IPv6Available; // If InterfaceActive, set if v6 available on this InterfaceID
DNSQuestion NetWakeBrowse;
DNSQuestion NetWakeResolve[3]; // For fault-tolerance, we try up to three Sleep Proxies
mDNSAddr SPSAddr[3];
mDNSIPPort SPSPort[3];
mDNSs32 NextSPSAttempt; // -1 if we're not currently attempting to register with any Sleep Proxy
mDNSs32 NextSPSAttemptTime;
// Standard AuthRecords that every Responder host should have (one per active IP address)
AuthRecord RR_A; // 'A' or 'AAAA' (address) record for our ".local" name
AuthRecord RR_PTR; // PTR (reverse lookup) record
AuthRecord RR_HINFO;
// Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
mDNSInterfaceID InterfaceID; // Identifies physical interface; MUST NOT be 0, -1, or -2
mDNSAddr ip; // The IPv4 or IPv6 address to advertise
mDNSAddr mask;
mDNSEthAddr MAC;
char ifname[64]; // Windows uses a GUID string for the interface name, which doesn't fit in 16 bytes
mDNSu8 Advertise; // False if you are only searching on this interface
mDNSu8 McastTxRx; // Send/Receive multicast on this { InterfaceID, address family } ?
mDNSu8 NetWake; // Set if Wake-On-Magic-Packet is enabled on this interface
mDNSu8 Loopback; // Set if this is the loopback interface
};
#define SLE_DELETE 0x00000001
#define SLE_WAB_QUERY_STARTED 0x00000002
typedef struct SearchListElem {
struct SearchListElem *next;
domainname domain;
int flag;
mDNSInterfaceID InterfaceID;
DNSQuestion BrowseQ;
DNSQuestion DefBrowseQ;
DNSQuestion AutomaticBrowseQ;
DNSQuestion RegisterQ;
DNSQuestion DefRegisterQ;
int numCfAnswers;
ARListElem *AuthRecs;
} SearchListElem;
// For domain enumeration and automatic browsing
// This is the user's DNS search list.
// In each of these domains we search for our special pointer records (lb._dns-sd._udp.<domain>, etc.)
// to discover recommended domains for domain enumeration (browse, default browse, registration,
// default registration) and possibly one or more recommended automatic browsing domains.
extern SearchListElem *mDNS_SearchList; // This really ought to be part of mDNS_struct -- SC
// ***************************************************************************
typedef void mDNSCallback(mDNS *const m, mStatus result);
#define CACHE_HASH_SLOTS 499
enum { // Bit flags -- i.e. values should be 1, 2, 4, 8, etc.
mDNS_KnownBug_LimitedIPv6 = 1,
mDNS_KnownBug_LossySyslog = 2 // <rdar://problem/6561888>
};
enum {
SleepState_Awake = 0,
SleepState_Transferring = 1,
SleepState_Sleeping = 2
};
struct mDNS_struct {
// Internal state fields. These hold the main internal state of mDNSCore;
// the client layer needn't be concerned with them.
// No fields need to be set up by the client prior to calling mDNS_Init();
// all required data is passed as parameters to that function.
mDNS_PlatformSupport *p; // Pointer to platform-specific data of indeterminite size
mDNSu32 KnownBugs;
mDNSBool CanReceiveUnicastOn5353;
mDNSBool AdvertiseLocalAddresses;
mDNSBool DivertMulticastAdvertisements; // from interfaces that do not advertise local addresses to local-only
mStatus mDNSPlatformStatus;
mDNSIPPort UnicastPort4;
mDNSIPPort UnicastPort6;
mDNSEthAddr PrimaryMAC; // Used as unique host ID
mDNSCallback *MainCallback;
void *MainContext;
// For debugging: To catch and report locking failures
mDNSu32 mDNS_busy; // Incremented between mDNS_Lock/mDNS_Unlock section
mDNSu32 mDNS_reentrancy; // Incremented when calling a client callback
mDNSu8 lock_rrcache; // For debugging: Set at times when these lists may not be modified
mDNSu8 lock_Questions;
mDNSu8 lock_Records;
#ifndef MaxMsg
#define MaxMsg 160
#endif
char MsgBuffer[MaxMsg]; // Temp storage used while building error log messages
// Task Scheduling variables
mDNSs32 timenow_adjust; // Correction applied if we ever discover time went backwards
mDNSs32 timenow; // The time that this particular activation of the mDNS code started
mDNSs32 timenow_last; // The time the last time we ran
mDNSs32 NextScheduledEvent; // Derived from values below
mDNSs32 ShutdownTime; // Set when we're shutting down; allows us to skip some unnecessary steps
mDNSs32 SuppressSending; // Don't send local-link mDNS packets during this time
mDNSs32 NextCacheCheck; // Next time to refresh cache record before it expires
mDNSs32 NextScheduledQuery; // Next time to send query in its exponential backoff sequence
mDNSs32 NextScheduledProbe; // Next time to probe for new authoritative record
mDNSs32 NextScheduledResponse; // Next time to send authoritative record(s) in responses
mDNSs32 NextScheduledNATOp; // Next time to send NAT-traversal packets
mDNSs32 NextScheduledSPS; // Next time to purge expiring Sleep Proxy records
mDNSs32 RandomQueryDelay; // For de-synchronization of query packets on the wire
mDNSu32 RandomReconfirmDelay; // For de-synchronization of reconfirmation queries on the wire
mDNSs32 PktNum; // Unique sequence number assigned to each received packet
mDNSu8 LocalRemoveEvents; // Set if we may need to deliver remove events for local-only questions and/or local-only records
mDNSu8 SleepState; // Set if we're sleeping
mDNSu8 SleepSeqNum; // "Epoch number" of our current period of wakefulness
mDNSu8 SystemWakeOnLANEnabled; // Set if we want to register with a Sleep Proxy before going to sleep
mDNSu8 SentSleepProxyRegistration;// Set if we registered (or tried to register) with a Sleep Proxy
mDNSu8 SystemSleepOnlyIfWakeOnLAN;// Set if we may only sleep if we managed to register with a Sleep Proxy
mDNSs32 AnnounceOwner; // After waking from sleep, include OWNER option in packets until this time
mDNSs32 DelaySleep; // To inhibit re-sleeping too quickly right after wake
mDNSs32 SleepLimit; // Time window to allow deregistrations, etc.,
// during which underying platform layer should inhibit system sleep
mDNSs32 NextScheduledSPRetry; // Time next sleep proxy registration action is required.
// Only valid if SleepLimit is nonzero and DelaySleep is zero.
mDNSs32 NextScheduledStopTime; // Next time to stop a question
// These fields only required for mDNS Searcher...
DNSQuestion *Questions; // List of all registered questions, active and inactive
DNSQuestion *NewQuestions; // Fresh questions not yet answered from cache
DNSQuestion *CurrentQuestion; // Next question about to be examined in AnswerLocalQuestions()
DNSQuestion *LocalOnlyQuestions; // Questions with InterfaceID set to mDNSInterface_LocalOnly or mDNSInterface_P2P
DNSQuestion *NewLocalOnlyQuestions; // Fresh local-only or P2P questions not yet answered
DNSQuestion *RestartQuestion; // Questions that are being restarted (stop followed by start)
mDNSu32 rrcache_size; // Total number of available cache entries
mDNSu32 rrcache_totalused; // Number of cache entries currently occupied
mDNSu32 rrcache_active; // Number of cache entries currently occupied by records that answer active questions
mDNSu32 rrcache_report;
CacheEntity *rrcache_free;
CacheGroup *rrcache_hash[CACHE_HASH_SLOTS];
mDNSs32 rrcache_nextcheck[CACHE_HASH_SLOTS];
AuthHash rrauth;
// Fields below only required for mDNS Responder...
domainlabel nicelabel; // Rich text label encoded using canonically precomposed UTF-8
domainlabel hostlabel; // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules
domainname MulticastHostname; // Fully Qualified "dot-local" Host Name, e.g. "Foo.local."
UTF8str255 HIHardware;
UTF8str255 HISoftware;
AuthRecord DeviceInfo;
AuthRecord *ResourceRecords;
AuthRecord *DuplicateRecords; // Records currently 'on hold' because they are duplicates of existing records
AuthRecord *NewLocalRecords; // Fresh AuthRecords (public) not yet delivered to our local-only questions
AuthRecord *CurrentRecord; // Next AuthRecord about to be examined
mDNSBool NewLocalOnlyRecords; // Fresh AuthRecords (local only) not yet delivered to our local questions
NetworkInterfaceInfo *HostInterfaces;
mDNSs32 ProbeFailTime;
mDNSu32 NumFailedProbes;
mDNSs32 SuppressProbes;
// Unicast-specific data
mDNSs32 NextuDNSEvent; // uDNS next event
mDNSs32 NextSRVUpdate; // Time to perform delayed update
DNSServer *DNSServers; // list of DNS servers
McastResolver *McastResolvers; // list of Mcast Resolvers
mDNSAddr Router;
mDNSAddr AdvertisedV4; // IPv4 address pointed to by hostname
mDNSAddr AdvertisedV6; // IPv6 address pointed to by hostname
DomainAuthInfo *AuthInfoList; // list of domains requiring authentication for updates
DNSQuestion ReverseMap; // Reverse-map query to find static hostname for service target
DNSQuestion AutomaticBrowseDomainQ;
domainname StaticHostname; // Current answer to reverse-map query
domainname FQDN;
HostnameInfo *Hostnames; // List of registered hostnames + hostname metadata
mDNSv6Addr AutoTunnelHostAddr; // IPv6 address advertised for AutoTunnel services on this machine
mDNSBool AutoTunnelHostAddrActive;
// AutoTunnel Relay address has two distinct uses
// AutoTunnelRelayAddrIn: If non-zero, it means that this host can be reached (inbound connection) through the relay
// AutoTunnelRelayAddrOut: If non-zero, it means that this host can use the relay to reach (outbound connection) the
// other hosts through the relay
mDNSv6Addr AutoTunnelRelayAddrIn;
mDNSv6Addr AutoTunnelRelayAddrOut;
domainlabel AutoTunnelLabel; // Used to construct hostname for *IPv4* address of tunnel endpoints
mDNSBool StartWABQueries; // Start WAB queries for the purpose of domain enumeration
mDNSBool RegisterAutoTunnel6;
// NAT-Traversal fields
NATTraversalInfo LLQNAT; // Single shared NAT Traversal to receive inbound LLQ notifications
NATTraversalInfo *NATTraversals;
NATTraversalInfo *CurrentNATTraversal;
mDNSs32 retryIntervalGetAddr; // delta between time sent and retry
mDNSs32 retryGetAddr; // absolute time when we retry
mDNSv4Addr ExternalAddress;
UDPSocket *NATMcastRecvskt; // For receiving NAT-PMP AddrReply multicasts from router on port 5350
mDNSu32 LastNATupseconds; // NAT engine uptime in seconds, from most recent NAT packet
mDNSs32 LastNATReplyLocalTime; // Local time in ticks when most recent NAT packet was received
mDNSu16 LastNATMapResultCode; // Most recent error code for mappings
tcpLNTInfo tcpAddrInfo; // legacy NAT traversal TCP connection info for external address
tcpLNTInfo tcpDeviceInfo; // legacy NAT traversal TCP connection info for device info
tcpLNTInfo *tcpInfoUnmapList; // list of pending unmap requests
mDNSInterfaceID UPnPInterfaceID;
UDPSocket *SSDPSocket; // For SSDP request/response
mDNSBool SSDPWANPPPConnection; // whether we should send the SSDP query for WANIPConnection or WANPPPConnection
mDNSIPPort UPnPRouterPort; // port we send discovery messages to
mDNSIPPort UPnPSOAPPort; // port we send SOAP messages to
mDNSu8 *UPnPRouterURL; // router's URL string
mDNSBool UPnPWANPPPConnection; // whether we're using WANIPConnection or WANPPPConnection
mDNSu8 *UPnPSOAPURL; // router's SOAP control URL string
mDNSu8 *UPnPRouterAddressString; // holds both the router's address and port
mDNSu8 *UPnPSOAPAddressString; // holds both address and port for SOAP messages
// Sleep Proxy Server fields
mDNSu8 SPSType; // 0 = off, 10-99 encodes desirability metric
mDNSu8 SPSPortability; // 10-99
mDNSu8 SPSMarginalPower; // 10-99
mDNSu8 SPSTotalPower; // 10-99
mDNSu8 SPSState; // 0 = off, 1 = running, 2 = shutting down, 3 = suspended during sleep
mDNSInterfaceID SPSProxyListChanged;
UDPSocket *SPSSocket;
ServiceRecordSet SPSRecords;
mDNSQuestionCallback *SPSBrowseCallback; // So the platform layer can do something useful with SPS browse results
int ProxyRecords; // Total number of records we're holding as proxy
#define MAX_PROXY_RECORDS 10000 /* DOS protection: 400 machines at 25 records each */
#if APPLE_OSX_mDNSResponder
ClientTunnel *TunnelClients;
uuid_t asl_uuid; // uuid for ASL logging
void *WCF;
#endif
// Fixed storage, to avoid creating large objects on the stack
// The imsg is declared as a union with a pointer type to enforce CPU-appropriate alignment
union {
DNSMessage m;
void *p;
} imsg; // Incoming message received from wire
DNSMessage omsg; // Outgoing message we're building
LargeCacheRecord rec; // Resource Record extracted from received message
};
#define FORALL_CACHERECORDS(SLOT,CG,CR) \
for ((SLOT) = 0; (SLOT) < CACHE_HASH_SLOTS; (SLOT)++) \
for ((CG)=m->rrcache_hash[(SLOT)]; (CG); (CG)=(CG)->next) \
for ((CR) = (CG)->members; (CR); (CR)=(CR)->next)
// ***************************************************************************
extern const mDNSInterfaceID mDNSInterface_Any; // Zero
extern const mDNSInterfaceID mDNSInterface_LocalOnly; // Special value
extern const mDNSInterfaceID mDNSInterface_Unicast; // Special value
extern const mDNSInterfaceID mDNSInterfaceMark; // Special value
extern const mDNSInterfaceID mDNSInterface_P2P; // Special value
extern const mDNSIPPort DiscardPort;
extern const mDNSIPPort SSHPort;
extern const mDNSIPPort UnicastDNSPort;
extern const mDNSIPPort SSDPPort;
extern const mDNSIPPort IPSECPort;
extern const mDNSIPPort NSIPCPort;
extern const mDNSIPPort NATPMPAnnouncementPort;
extern const mDNSIPPort NATPMPPort;
extern const mDNSIPPort DNSEXTPort;
extern const mDNSIPPort MulticastDNSPort;
extern const mDNSIPPort LoopbackIPCPort;
extern const mDNSIPPort PrivateDNSPort;
extern const OwnerOptData zeroOwner;
extern const mDNSIPPort zeroIPPort;
extern const mDNSv4Addr zerov4Addr;
extern const mDNSv6Addr zerov6Addr;
extern const mDNSEthAddr zeroEthAddr;
extern const mDNSv4Addr onesIPv4Addr;
extern const mDNSv6Addr onesIPv6Addr;
extern const mDNSEthAddr onesEthAddr;
extern const mDNSAddr zeroAddr;
extern const mDNSv4Addr AllDNSAdminGroup;
extern const mDNSv4Addr AllHosts_v4;
extern const mDNSv6Addr AllHosts_v6;
extern const mDNSv6Addr NDP_prefix;
extern const mDNSEthAddr AllHosts_v6_Eth;
extern const mDNSAddr AllDNSLinkGroup_v4;
extern const mDNSAddr AllDNSLinkGroup_v6;
extern const mDNSOpaque16 zeroID;
extern const mDNSOpaque16 onesID;
extern const mDNSOpaque16 QueryFlags;
extern const mDNSOpaque16 uQueryFlags;
extern const mDNSOpaque16 ResponseFlags;
extern const mDNSOpaque16 UpdateReqFlags;
extern const mDNSOpaque16 UpdateRespFlags;
extern const mDNSOpaque64 zeroOpaque64;
extern mDNSBool StrictUnicastOrdering;
extern mDNSu8 NumUnicastDNSServers;
#define localdomain (*(const domainname *)"\x5" "local")
#define DeviceInfoName (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
#define SleepProxyServiceType (*(const domainname *)"\xC" "_sleep-proxy" "\x4" "_udp")
// ***************************************************************************
#if (defined(_MSC_VER))
#define mDNSinline static __inline
#elif ((__GNUC__ > 2) || ((__GNUC__ == 2) && (__GNUC_MINOR__ >= 9)))
#define mDNSinline static inline
#endif
// If we're not doing inline functions, then this header needs to have the extern declarations
#if !defined(mDNSinline)
extern mDNSs32 NonZeroTime(mDNSs32 t);
extern mDNSu16 mDNSVal16(mDNSOpaque16 x);
extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
#endif
// If we're compiling the particular C file that instantiates our inlines, then we
// define "mDNSinline" (to empty string) so that we generate code in the following section
#if (!defined(mDNSinline) && mDNS_InstantiateInlines)
#define mDNSinline
#endif
#ifdef mDNSinline
mDNSinline mDNSs32 NonZeroTime(mDNSs32 t)
{
if (t) {
return (t);
} else {
return (1);
}
}
mDNSinline mDNSu16 mDNSVal16(mDNSOpaque16 x)
{
return ((mDNSu16)((mDNSu16)x.b[0] << 8 | (mDNSu16)x.b[1]));
}
mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
{
mDNSOpaque16 x;
x.b[0] = (mDNSu8)(v >> 8);
x.b[1] = (mDNSu8)(v & 0xFF);
return (x);
}
#endif
// ***************************************************************************
// Every client should call mDNS_Init, passing in storage for the mDNS object and the mDNS_PlatformSupport object.
//
// Clients that are only advertising services should use mDNS_Init_NoCache and mDNS_Init_ZeroCacheSize.
// Clients that plan to perform queries (mDNS_StartQuery, mDNS_StartBrowse, mDNS_StartResolveService, etc.)
// need to provide storage for the resource record cache, or the query calls will return 'mStatus_NoCache'.
// The rrcachestorage parameter is the address of memory for the resource record cache, and
// the rrcachesize parameter is the number of entries in the CacheRecord array passed in.
// (i.e. the size of the cache memory needs to be sizeof(CacheRecord) * rrcachesize).
// OS X 10.3 Panther uses an initial cache size of 64 entries, and then mDNSCore sends an
// mStatus_GrowCache message if it needs more.
//
// Most clients should use mDNS_Init_AdvertiseLocalAddresses. This causes mDNSCore to automatically
// create the correct address records for all the hosts interfaces. If you plan to advertise
// services being offered by the local machine, this is almost always what you want.
// There are two cases where you might use mDNS_Init_DontAdvertiseLocalAddresses:
// 1. A client-only device, that browses for services but doesn't advertise any of its own.
// 2. A proxy-registration service, that advertises services being offered by other machines, and takes
// the appropriate steps to manually create the correct address records for those other machines.
// In principle, a proxy-like registration service could manually create address records for its own machine too,
// but this would be pointless extra effort when using mDNS_Init_AdvertiseLocalAddresses does that for you.
//
// Note that a client-only device that wishes to prohibit multicast advertisements (e.g. from
// higher-layer API calls) must also set DivertMulticastAdvertisements in the mDNS structure and
// advertise local address(es) on a loopback interface.
//
// When mDNS has finished setting up the client's callback is called
// A client can also spin and poll the mDNSPlatformStatus field to see when it changes from mStatus_Waiting to mStatus_NoError
//
// Call mDNS_StartExit to tidy up before exiting
// Because exiting may be an asynchronous process (e.g. if unicast records need to be deregistered)
// client layer may choose to wait until mDNS_ExitNow() returns true before calling mDNS_FinalExit().
//
// Call mDNS_Register with a completed AuthRecord object to register a resource record
// If the resource record type is kDNSRecordTypeUnique (or kDNSknownunique) then if a conflicting resource record is discovered,
// the resource record's mDNSRecordCallback will be called with error code mStatus_NameConflict. The callback should deregister
// the record, and may then try registering the record again after picking a new name (e.g. by automatically appending a number).
// Following deregistration, the RecordCallback will be called with result mStatus_MemFree to signal that it is safe to deallocate
// the record's storage (memory must be freed asynchronously to allow for goodbye packets and dynamic update deregistration).
//
// Call mDNS_StartQuery to initiate a query. mDNS will proceed to issue Multicast DNS query packets, and any time a response
// is received containing a record which matches the question, the DNSQuestion's mDNSAnswerCallback function will be called
// Call mDNS_StopQuery when no more answers are required
//
// Care should be taken on multi-threaded or interrupt-driven environments.
// The main mDNS routines call mDNSPlatformLock() on entry and mDNSPlatformUnlock() on exit;
// each platform layer needs to implement these appropriately for its respective platform.
// For example, if the support code on a particular platform implements timer callbacks at interrupt time, then
// mDNSPlatformLock/Unlock need to disable interrupts or do similar concurrency control to ensure that the mDNS
// code is not entered by an interrupt-time timer callback while in the middle of processing a client call.
extern mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
mDNSBool AdvertiseLocalAddresses,
mDNSCallback *Callback, void *Context);
// See notes above on use of NoCache/ZeroCacheSize
#define mDNS_Init_NoCache mDNSNULL
#define mDNS_Init_ZeroCacheSize 0
// See notes above on use of Advertise/DontAdvertiseLocalAddresses
#define mDNS_Init_AdvertiseLocalAddresses mDNStrue
#define mDNS_Init_DontAdvertiseLocalAddresses mDNSfalse
#define mDNS_Init_NoInitCallback mDNSNULL
#define mDNS_Init_NoInitCallbackContext mDNSNULL
extern void mDNS_ConfigChanged(mDNS *const m);
extern void mDNS_GrowCache(mDNS *const m, CacheEntity *storage, mDNSu32 numrecords);
extern void mDNS_GrowAuth(mDNS *const m, AuthEntity *storage, mDNSu32 numrecords);
extern void mDNS_StartExit(mDNS *const m);
extern void mDNS_FinalExit(mDNS *const m);
#define mDNS_Close(m) do { mDNS_StartExit(m); mDNS_FinalExit(m); } while(0)
#define mDNS_ExitNow(m, now) ((now) - (m)->ShutdownTime >= 0 || (!(m)->ResourceRecords))
extern mDNSs32 mDNS_Execute(mDNS *const m);
extern mStatus mDNS_Register(mDNS *const m, AuthRecord *const rr);
extern mStatus mDNS_Update(mDNS *const m, AuthRecord *const rr, mDNSu32 newttl,
const mDNSu16 newrdlength, RData *const newrdata, mDNSRecordUpdateCallback *Callback);
extern mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr);
extern mStatus mDNS_StartQuery(mDNS *const m, DNSQuestion *const question);
extern mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question);
extern mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const question);
extern mStatus mDNS_Reconfirm(mDNS *const m, CacheRecord *const cacherr);
extern mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr);
extern void mDNS_PurgeCacheResourceRecord(mDNS *const m, CacheRecord *rr);
extern mDNSs32 mDNS_TimeNow(const mDNS *const m);
extern mStatus mDNS_StartNATOperation(mDNS *const m, NATTraversalInfo *traversal);
extern mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traversal);
extern mStatus mDNS_StopNATOperation_internal(mDNS *m, NATTraversalInfo *traversal);
extern DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const name);
extern void mDNS_UpdateAllowSleep(mDNS *const m);
// ***************************************************************************
#if 0
#pragma mark -
#pragma mark - Platform support functions that are accessible to the client layer too
#endif
extern mDNSs32 mDNSPlatformOneSecond;
// ***************************************************************************
// mDNS_Dereg_normal is used for most calls to mDNS_Deregister_internal
// mDNS_Dereg_rapid is used to send one goodbye instead of three, when we want the memory available for reuse sooner
// mDNS_Dereg_conflict is used to indicate that this record is being forcibly deregistered because of a conflict
// mDNS_Dereg_repeat is used when cleaning up, for records that may have already been forcibly deregistered
typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_Dereg_repeat } mDNS_Dereg_type;
// mDNS_RegisterService is a single call to register the set of resource records associated with a given named service.
//
// mDNS_StartResolveService is single call which is equivalent to multiple calls to mDNS_StartQuery,
// to find the IP address, port number, and demultiplexing information for a given named service.
// As with mDNS_StartQuery, it executes asynchronously, and calls the ServiceInfoQueryCallback when the answer is
// found. After the service is resolved, the client should call mDNS_StopResolveService to complete the transaction.
// The client can also call mDNS_StopResolveService at any time to abort the transaction.
//
// mDNS_AddRecordToService adds an additional record to a Service Record Set. This record may be deregistered
// via mDNS_RemoveRecordFromService, or by deregistering the service. mDNS_RemoveRecordFromService is passed a
// callback to free the memory associated with the extra RR when it is safe to do so. The ExtraResourceRecord
// object can be found in the record's context pointer.
// mDNS_GetBrowseDomains is a special case of the mDNS_StartQuery call, where the resulting answers
// are a list of PTR records indicating (in the rdata) domains that are recommended for browsing.
// After getting the list of domains to browse, call mDNS_StopQuery to end the search.
// mDNS_GetDefaultBrowseDomain returns the name of the domain that should be highlighted by default.
//
// mDNS_GetRegistrationDomains and mDNS_GetDefaultRegistrationDomain are the equivalent calls to get the list
// of one or more domains that should be offered to the user as choices for where they may register their service,
// and the default domain in which to register in the case where the user has made no selection.
extern void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context);
// mDNS_RegisterService() flags parameter bit definitions
enum {
regFlagIncludeP2P = 0x1, // include P2P interfaces when using mDNSInterface_Any
regFlagKnownUnique = 0x2 // client guarantees that SRV and TXT record names are unique
};
extern mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host, mDNSIPPort port, const mDNSu8 txtinfo[], mDNSu16 txtlen,
AuthRecord *SubTypes, mDNSu32 NumSubTypes,
mDNSInterfaceID InterfaceID, mDNSServiceCallback Callback, void *Context, mDNSu32 flags);
extern mStatus mDNS_AddRecordToService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, RData *rdata, mDNSu32 ttl, mDNSu32 includeP2P);
extern mStatus mDNS_RemoveRecordFromService(mDNS *const m, ServiceRecordSet *sr, ExtraResourceRecord *extra, mDNSRecordCallback MemFreeCallback, void *Context);
extern mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordSet *const sr, const domainlabel *newname);
extern mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *sr, mDNS_Dereg_type drt);
#define mDNS_DeregisterService(M,S) mDNS_DeregisterService_drt((M), (S), mDNS_Dereg_normal)
extern mStatus mDNS_RegisterNoSuchService(mDNS *const m, AuthRecord *const rr,
const domainlabel *const name, const domainname *const type, const domainname *const domain,
const domainname *const host,
const mDNSInterfaceID InterfaceID, mDNSRecordCallback Callback, void *Context, mDNSBool includeP2P);
#define mDNS_DeregisterNoSuchService mDNS_Deregister
extern void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID InterfaceID, const domainname *const name,
const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context);
extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
const domainname *const srv, const domainname *const domain,
const mDNSInterfaceID InterfaceID, mDNSBool ForceMCast, mDNSQuestionCallback *Callback, void *Context);
#define mDNS_StopBrowse mDNS_StopQuery
extern mStatus mDNS_StartResolveService(mDNS *const m, ServiceInfoQuery *query, ServiceInfo *info, mDNSServiceInfoQueryCallback *Callback, void *Context);
extern void mDNS_StopResolveService(mDNS *const m, ServiceInfoQuery *query);
typedef enum {
mDNS_DomainTypeBrowse = 0,
mDNS_DomainTypeBrowseDefault = 1,
mDNS_DomainTypeBrowseAutomatic = 2,
mDNS_DomainTypeRegistration = 3,
mDNS_DomainTypeRegistrationDefault = 4,
mDNS_DomainTypeMax = 4
} mDNS_DomainType;
extern const char *const mDNS_DomainTypeNames[];
extern mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, mDNS_DomainType DomainType, const domainname *dom,
const mDNSInterfaceID InterfaceID, mDNSQuestionCallback *Callback, void *Context);
#define mDNS_StopGetDomains mDNS_StopQuery
extern mStatus mDNS_AdvertiseDomains(mDNS *const m, AuthRecord *rr, mDNS_DomainType DomainType, const mDNSInterfaceID InterfaceID, char *domname);
#define mDNS_StopAdvertiseDomains mDNS_Deregister
extern mDNSOpaque16 mDNS_NewMessageID(mDNS *const m);
extern mDNSBool mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr);
extern DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInterfaceID InterfaceID);
extern DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question);
extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question);
// ***************************************************************************
// In order to expose the full capabilities of the DNS protocol (which allows any arbitrary eight-bit values
// in domain name labels, including unlikely characters like ascii nulls and even dots) all the mDNS APIs
// work with DNS's native length-prefixed strings. For convenience in C, the following utility functions
// are provided for converting between C's null-terminated strings and DNS's length-prefixed strings.
// Assignment
// A simple C structure assignment of a domainname can cause a protection fault by accessing unmapped memory,
// because that object is defined to be 256 bytes long, but not all domainname objects are truly the full size.
// This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
#define AssignDomainName(DST, SRC) do { mDNSu16 len__ = DomainNameLength((SRC)); \
if (len__ <= MAX_DOMAIN_NAME) mDNSPlatformMemCopy((DST)->c, (SRC)->c, len__); else (DST)->c[0] = 0; } while(0)
// Comparison functions
#define SameDomainLabelCS(A,B) ((A)[0] == (B)[0] && mDNSPlatformMemSame((A)+1, (B)+1, (A)[0]))
extern mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b);
extern mDNSBool SameDomainName(const domainname *const d1, const domainname *const d2);
extern mDNSBool SameDomainNameCS(const domainname *const d1, const domainname *const d2);
typedef mDNSBool DomainNameComparisonFn(const domainname *const d1, const domainname *const d2);
extern mDNSBool IsLocalDomain(const domainname *d); // returns true for domains that by default should be looked up using link-local multicast
#define StripFirstLabel(X) ((const domainname *)&(X)->c[(X)->c[0] ? 1 + (X)->c[0] : 0])
#define FirstLabel(X) ((const domainlabel *)(X))
#define SecondLabel(X) ((const domainlabel *)StripFirstLabel(X))
#define ThirdLabel(X) ((const domainlabel *)StripFirstLabel(StripFirstLabel(X)))
extern const mDNSu8 *LastLabel(const domainname *d);
// Get total length of domain name, in native DNS format, including terminal root label
// (e.g. length of "com." is 5 (length byte, three data bytes, final zero)
extern mDNSu16 DomainNameLengthLimit(const domainname *const name, const mDNSu8 *limit);
#define DomainNameLength(name) DomainNameLengthLimit((name), (name)->c + MAX_DOMAIN_NAME)
// Append functions to append one or more labels to an existing native format domain name:
// AppendLiteralLabelString adds a single label from a literal C string, with no escape character interpretation.
// AppendDNSNameString adds zero or more labels from a C string using conventional DNS dots-and-escaping interpretation
// AppendDomainLabel adds a single label from a native format domainlabel
// AppendDomainName adds zero or more labels from a native format domainname
extern mDNSu8 *AppendLiteralLabelString(domainname *const name, const char *cstr);
extern mDNSu8 *AppendDNSNameString(domainname *const name, const char *cstr);
extern mDNSu8 *AppendDomainLabel(domainname *const name, const domainlabel *const label);
extern mDNSu8 *AppendDomainName(domainname *const name, const domainname *const append);
// Convert from null-terminated string to native DNS format:
// The DomainLabel form makes a single label from a literal C string, with no escape character interpretation.
// The DomainName form makes native format domain name from a C string using conventional DNS interpretation:
// dots separate labels, and within each label, '\.' represents a literal dot, '\\' represents a literal
// backslash and backslash with three decimal digits (e.g. \000) represents an arbitrary byte value.
extern mDNSBool MakeDomainLabelFromLiteralString(domainlabel *const label, const char *cstr);
extern mDNSu8 *MakeDomainNameFromDNSNameString(domainname *const name, const char *cstr);
// Convert native format domainlabel or domainname back to C string format
// IMPORTANT:
// When using ConvertDomainLabelToCString, the target buffer must be MAX_ESCAPED_DOMAIN_LABEL (254) bytes long
// to guarantee there will be no buffer overrun. It is only safe to use a buffer shorter than this in rare cases
// where the label is known to be constrained somehow (for example, if the label is known to be either "_tcp" or "_udp").
// Similarly, when using ConvertDomainNameToCString, the target buffer must be MAX_ESCAPED_DOMAIN_NAME (1009) bytes long.
// See definitions of MAX_ESCAPED_DOMAIN_LABEL and MAX_ESCAPED_DOMAIN_NAME for more detailed explanation.
extern char *ConvertDomainLabelToCString_withescape(const domainlabel *const name, char *cstr, char esc);
#define ConvertDomainLabelToCString_unescaped(D,C) ConvertDomainLabelToCString_withescape((D), (C), 0)
#define ConvertDomainLabelToCString(D,C) ConvertDomainLabelToCString_withescape((D), (C), '\\')
extern char *ConvertDomainNameToCString_withescape(const domainname *const name, char *cstr, char esc);
#define ConvertDomainNameToCString_unescaped(D,C) ConvertDomainNameToCString_withescape((D), (C), 0)
#define ConvertDomainNameToCString(D,C) ConvertDomainNameToCString_withescape((D), (C), '\\')
extern void ConvertUTF8PstringToRFC1034HostLabel(const mDNSu8 UTF8Name[], domainlabel *const hostlabel);
extern mDNSu8 *ConstructServiceName(domainname *const fqdn, const domainlabel *name, const domainname *type, const domainname *const domain);
extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel *const name, domainname *const type, domainname *const domain);
// Note: Some old functions have been replaced by more sensibly-named versions.
// You can uncomment the hash-defines below if you don't want to have to change your source code right away.
// When updating your code, note that (unlike the old versions) *all* the new routines take the target object
// as their first parameter.
//#define ConvertCStringToDomainName(SRC,DST) MakeDomainNameFromDNSNameString((DST),(SRC))
//#define ConvertCStringToDomainLabel(SRC,DST) MakeDomainLabelFromLiteralString((DST),(SRC))
//#define AppendStringLabelToName(DST,SRC) AppendLiteralLabelString((DST),(SRC))
//#define AppendStringNameToName(DST,SRC) AppendDNSNameString((DST),(SRC))
//#define AppendDomainLabelToName(DST,SRC) AppendDomainLabel((DST),(SRC))
//#define AppendDomainNameToName(DST,SRC) AppendDomainName((DST),(SRC))
// ***************************************************************************
// mDNS_vsnprintf/snprintf return the number of characters written, excluding the final terminating null.
// The output is always null-terminated: for example, if the output turns out to be exactly buflen long,
// then the output will be truncated by one character to allow space for the terminating null.
// Unlike standard C vsnprintf/snprintf, they return the number of characters *actually* written,
// not the number of characters that *would* have been printed were buflen unlimited.
extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg);
extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3, 4);
extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id);
extern char *DNSTypeName(mDNSu16 rrtype);
extern char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer);
#define RRDisplayString(m, rr) GetRRDisplayString_rdb(rr, &(rr)->rdata->u, (m)->MsgBuffer)
#define ARDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
#define CRDisplayString(m, rr) GetRRDisplayString_rdb(&(rr)->resrec, &(rr)->resrec.rdata->u, (m)->MsgBuffer)
extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
extern mDNSBool mDNSv4AddrIsRFC1918(mDNSv4Addr *addr); // returns true for RFC1918 private addresses
#define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4))
#define mDNSSameIPPort(A,B) ((A).NotAnInteger == (B).NotAnInteger)
#define mDNSSameOpaque16(A,B) ((A).NotAnInteger == (B).NotAnInteger)
#define mDNSSameOpaque32(A,B) ((A).NotAnInteger == (B).NotAnInteger)
#define mDNSSameOpaque64(A,B) ((A)->l[0] == (B)->l[0] && (A)->l[1] == (B)->l[1])
#define mDNSSameIPv4Address(A,B) ((A).NotAnInteger == (B).NotAnInteger)
#define mDNSSameIPv6Address(A,B) ((A).l[0] == (B).l[0] && (A).l[1] == (B).l[1] && (A).l[2] == (B).l[2] && (A).l[3] == (B).l[3])
#define mDNSSameEthAddress(A,B) ((A)->w[0] == (B)->w[0] && (A)->w[1] == (B)->w[1] && (A)->w[2] == (B)->w[2])
#define mDNSIPPortIsZero(A) ((A).NotAnInteger == 0)
#define mDNSOpaque16IsZero(A) ((A).NotAnInteger == 0)
#define mDNSOpaque64IsZero(A) (((A)->l[0] | (A)->l[1] ) == 0)
#define mDNSIPv4AddressIsZero(A) ((A).NotAnInteger == 0)
#define mDNSIPv6AddressIsZero(A) (((A).l[0] | (A).l[1] | (A).l[2] | (A).l[3]) == 0)
#define mDNSEthAddressIsZero(A) (((A).w[0] | (A).w[1] | (A).w[2] ) == 0)
#define mDNSIPv4AddressIsOnes(A) ((A).NotAnInteger == 0xFFFFFFFF)
#define mDNSIPv6AddressIsOnes(A) (((A).l[0] & (A).l[1] & (A).l[2] & (A).l[3]) == 0xFFFFFFFF)
#define mDNSAddressIsAllDNSLinkGroup(X) ( \
((X)->type == mDNSAddrType_IPv4 && mDNSSameIPv4Address((X)->ip.v4, AllDNSLinkGroup_v4.ip.v4)) || \
((X)->type == mDNSAddrType_IPv6 && mDNSSameIPv6Address((X)->ip.v6, AllDNSLinkGroup_v6.ip.v6)) )
#define mDNSAddressIsZero(X) ( \
((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero((X)->ip.v4)) || \
((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsZero((X)->ip.v6)) )
#define mDNSAddressIsValidNonZero(X) ( \
((X)->type == mDNSAddrType_IPv4 && !mDNSIPv4AddressIsZero((X)->ip.v4)) || \
((X)->type == mDNSAddrType_IPv6 && !mDNSIPv6AddressIsZero((X)->ip.v6)) )
#define mDNSAddressIsOnes(X) ( \
((X)->type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes((X)->ip.v4)) || \
((X)->type == mDNSAddrType_IPv6 && mDNSIPv6AddressIsOnes((X)->ip.v6)) )
#define mDNSAddressIsValid(X) ( \
((X)->type == mDNSAddrType_IPv4) ? !(mDNSIPv4AddressIsZero((X)->ip.v4) || mDNSIPv4AddressIsOnes((X)->ip.v4)) : \
((X)->type == mDNSAddrType_IPv6) ? !(mDNSIPv6AddressIsZero((X)->ip.v6) || mDNSIPv6AddressIsOnes((X)->ip.v6)) : mDNSfalse)
#define mDNSv4AddressIsLinkLocal(X) ((X)->b[0] == 169 && (X)->b[1] == 254)
#define mDNSv6AddressIsLinkLocal(X) ((X)->b[0] == 0xFE && ((X)->b[1] & 0xC0) == 0x80)
#define mDNSAddressIsLinkLocal(X) ( \
((X)->type == mDNSAddrType_IPv4) ? mDNSv4AddressIsLinkLocal(&(X)->ip.v4) : \
((X)->type == mDNSAddrType_IPv6) ? mDNSv6AddressIsLinkLocal(&(X)->ip.v6) : mDNSfalse)
#define mDNSv4AddressIsLoopback(X) ((X)->b[0] == 127 && (X)->b[1] == 0 && (X)->b[2] == 0 && (X)->b[3] == 1)
#define mDNSv6AddressIsLoopback(X) ((((X)->l[0] | (X)->l[1] | (X)->l[2]) == 0) && ((X)->b[12] == 0 && (X)->b[13] == 0 && (X)->b[14] == 0 && (X)->b[15] == 1))
// ***************************************************************************
#if 0
#pragma mark -
#pragma mark - Authentication Support
#endif
// Unicast DNS and Dynamic Update specific Client Calls
//
// mDNS_SetSecretForDomain tells the core to authenticate (via TSIG with an HMAC_MD5 hash of the shared secret)
// when dynamically updating a given zone (and its subdomains). The key used in authentication must be in
// domain name format. The shared secret must be a null-terminated base64 encoded string. A minimum size of
// 16 bytes (128 bits) is recommended for an MD5 hash as per RFC 2485.
// Calling this routine multiple times for a zone replaces previously entered values. Call with a NULL key
// to disable authentication for the zone. A non-NULL autoTunnelPrefix means this is an AutoTunnel domain,
// and the value is prepended to the IPSec identifier (used for key lookup)
extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, const char *autoTunnelPrefix);
extern void RecreateNATMappings(mDNS *const m);
// Hostname/Unicast Interface Configuration
// All hostnames advertised point to one IPv4 address and/or one IPv6 address, set via SetPrimaryInterfaceInfo. Invoking this routine
// updates all existing hostnames to point to the new address.
// A hostname is added via AddDynDNSHostName, which points to the primary interface's v4 and/or v6 addresss
// The status callback is invoked to convey success or failure codes - the callback should not modify the AuthRecord or free memory.
// Added hostnames may be removed (deregistered) via mDNS_RemoveDynDNSHostName.
// Host domains added prior to specification of the primary interface address and computer name will be deferred until
// these values are initialized.
// DNS servers used to resolve unicast queries are specified by mDNS_AddDNSServer.
// For "split" DNS configurations, in which queries for different domains are sent to different servers (e.g. VPN and external),
// a domain may be associated with a DNS server. For standard configurations, specify the root label (".") or NULL.
extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext);
extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, const mDNSAddr *v6addr, const mDNSAddr *router);
extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSAddr *addr, const mDNSIPPort port, mDNSBool scoped, mDNSu32 timeout, mDNSBool cellIntf);
extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q);
extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
extern McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSu32 timeout);
// We use ((void *)0) here instead of mDNSNULL to avoid compile warnings on gcc 4.2
#define mDNS_AddSearchDomain_CString(X, I) \
do { domainname d__; if (((X) != (void*)0) && MakeDomainNameFromDNSNameString(&d__, (X)) && d__.c[0]) mDNS_AddSearchDomain(&d__, I); } while(0)
// Routines called by the core, exported by DNSDigest.c
// Convert an arbitrary base64 encoded key key into an HMAC key (stored in AuthInfo struct)
extern mDNSs32 DNSDigest_ConstructHMACKeyfromBase64(DomainAuthInfo *info, const char *b64key);
// sign a DNS message. The message must be complete, with all values in network byte order. end points to the end
// of the message, and is modified by this routine. numAdditionals is a pointer to the number of additional
// records in HOST byte order, which is incremented upon successful completion of this routine. The function returns
// the new end pointer on success, and NULL on failure.
extern void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo *info, mDNSu16 tcode);
#define SwapDNSHeaderBytes(M) do { \
(M)->h.numQuestions = (mDNSu16)((mDNSu8 *)&(M)->h.numQuestions )[0] << 8 | ((mDNSu8 *)&(M)->h.numQuestions )[1]; \
(M)->h.numAnswers = (mDNSu16)((mDNSu8 *)&(M)->h.numAnswers )[0] << 8 | ((mDNSu8 *)&(M)->h.numAnswers )[1]; \
(M)->h.numAuthorities = (mDNSu16)((mDNSu8 *)&(M)->h.numAuthorities)[0] << 8 | ((mDNSu8 *)&(M)->h.numAuthorities)[1]; \
(M)->h.numAdditionals = (mDNSu16)((mDNSu8 *)&(M)->h.numAdditionals)[0] << 8 | ((mDNSu8 *)&(M)->h.numAdditionals)[1]; \
} while (0)
#define DNSDigest_SignMessageHostByteOrder(M,E,INFO) \
do { SwapDNSHeaderBytes(M); DNSDigest_SignMessage((M), (E), (INFO), 0); SwapDNSHeaderBytes(M); } while (0)
// verify a DNS message. The message must be complete, with all values in network byte order. end points to the
// end of the record. tsig is a pointer to the resource record that contains the TSIG OPT record. info is
// the matching key to use for verifying the message. This function expects that the additionals member
// of the DNS message header has already had one subtracted from it.
extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCacheRecord *tsig, DomainAuthInfo *info, mDNSu16 *rcode, mDNSu16 *tcode);
// ***************************************************************************
// This section defines the interface to the Platform Support layer.
// Normal client code should not use any of types defined here, or directly call any of the functions defined here.
// The definitions are placed here because sometimes clients do use these calls indirectly, via other supported client operations.
// For example, AssignDomainName is a macro defined using mDNSPlatformMemCopy()
// Every platform support module must provide the following functions.
// mDNSPlatformInit() typically opens a communication endpoint, and starts listening for mDNS packets.
// When Setup is complete, the platform support layer calls mDNSCoreInitComplete().
// mDNSPlatformSendUDP() sends one UDP packet
// When a packet is received, the PlatformSupport code calls mDNSCoreReceive()
// mDNSPlatformClose() tidies up on exit
//
// Note: mDNSPlatformMemAllocate/mDNSPlatformMemFree are only required for handling oversized resource records and unicast DNS.
// If your target platform has a well-defined specialized application, and you know that all the records it uses
// are InlineCacheRDSize or less, then you can just make a simple mDNSPlatformMemAllocate() stub that always returns
// NULL. InlineCacheRDSize is a compile-time constant, which is set by default to 68. If you need to handle records
// a little larger than this and you don't want to have to implement run-time allocation and freeing, then you
// can raise the value of this constant to a suitable value (at the expense of increased memory usage).
//
// USE CAUTION WHEN CALLING mDNSPlatformRawTime: The m->timenow_adjust correction factor needs to be added
// Generally speaking:
// Code that's protected by the main mDNS lock should just use the m->timenow value
// Code outside the main mDNS lock should use mDNS_TimeNow(m) to get properly adjusted time
// In certain cases there may be reasons why it's necessary to get the time without taking the lock first
// (e.g. inside the routines that are doing the locking and unlocking, where a call to get the lock would result in a
// recursive loop); in these cases use mDNS_TimeNow_NoLock(m) to get mDNSPlatformRawTime with the proper correction factor added.
//
// mDNSPlatformUTC returns the time, in seconds, since Jan 1st 1970 UTC and is required for generating TSIG records
extern mStatus mDNSPlatformInit(mDNS *const m);
extern void mDNSPlatformClose(mDNS *const m);
extern mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, mDNSIPPort dstport);
extern void mDNSPlatformLock(const mDNS *const m);
extern void mDNSPlatformUnlock(const mDNS *const m);
extern void mDNSPlatformStrCopy(void *dst, const void *src);
extern mDNSu32 mDNSPlatformStrLen(const void *src);
extern void mDNSPlatformMemCopy(void *dst, const void *src, mDNSu32 len);
extern mDNSBool mDNSPlatformMemSame(const void *dst, const void *src, mDNSu32 len);
extern void mDNSPlatformMemZero(void *dst, mDNSu32 len);
#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
#define mDNSPlatformMemAllocate(X) mallocL(#X, X)
#else
extern void *mDNSPlatformMemAllocate(mDNSu32 len);
#endif
extern void mDNSPlatformMemFree(void *mem);
#define _PLATFORM_HAS_STRONG_PRNG_ 1 //modify
// If the platform doesn't have a strong PRNG, we define a naive multiply-and-add based on a seed
// from the platform layer. Long-term, we should embed an arc4 implementation, but the strength
// will still depend on the randomness of the seed.
#if !defined(_PLATFORM_HAS_STRONG_PRNG_) && (_BUILDING_XCODE_PROJECT_ || defined(_WIN32))
#define _PLATFORM_HAS_STRONG_PRNG_ 1
#endif
#if _PLATFORM_HAS_STRONG_PRNG_
extern mDNSu32 mDNSPlatformRandomNumber(void);
#else
extern mDNSu32 mDNSPlatformRandomSeed(void);
#endif // _PLATFORM_HAS_STRONG_PRNG_
extern mStatus mDNSPlatformTimeInit(void);
extern mDNSs32 mDNSPlatformRawTime(void);
extern mDNSs32 mDNSPlatformUTC(void);
#define mDNS_TimeNow_NoLock(m) (mDNSPlatformRawTime() + (m)->timenow_adjust)
#if MDNS_DEBUGMSGS
extern void mDNSPlatformWriteDebugMsg(const char *msg);
#endif
extern void mDNSPlatformWriteLogMsg(const char *ident, const char *msg, mDNSLogLevel_t loglevel);
#if APPLE_OSX_mDNSResponder
// Utility function for ASL logging
mDNSexport void mDNSASLLog(uuid_t *uuid, const char *subdomain, const char *result, const char *signature, const char *fmt, ...);
#endif
// Platform support modules should provide the following functions to map between opaque interface IDs
// and interface indexes in order to support the DNS-SD API. If your target platform does not support
// multiple interfaces and/or does not support the DNS-SD API, these functions can be empty.
extern mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex);
extern mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNSInterfaceID id, mDNSBool suppressNetworkChange);
// Every platform support module must provide the following functions if it is to support unicast DNS
// and Dynamic Update.
// All TCP socket operations implemented by the platform layer MUST NOT BLOCK.
// mDNSPlatformTCPConnect initiates a TCP connection with a peer, adding the socket descriptor to the
// main event loop. The return value indicates whether the connection succeeded, failed, or is pending
// (i.e. the call would block.) On return, the descriptor parameter is set to point to the connected socket.
// The TCPConnectionCallback is subsequently invoked when the connection
// completes (in which case the ConnectionEstablished parameter is true), or data is available for
// reading on the socket (indicated by the ConnectionEstablished parameter being false.) If the connection
// asynchronously fails, the TCPConnectionCallback should be invoked as usual, with the error being
// returned in subsequent calls to PlatformReadTCP or PlatformWriteTCP. (This allows for platforms
// with limited asynchronous error detection capabilities.) PlatformReadTCP and PlatformWriteTCP must
// return the number of bytes read/written, 0 if the call would block, and -1 if an error. PlatformReadTCP
// should set the closed argument if the socket has been closed.
// PlatformTCPCloseConnection must close the connection to the peer and remove the descriptor from the
// event loop. CloseConnectin may be called at any time, including in a ConnectionCallback.
typedef enum {
kTCPSocketFlags_Zero = 0,
kTCPSocketFlags_UseTLS = (1 << 0)
} TCPSocketFlags;
typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err);
extern TCPSocket *mDNSPlatformTCPSocket(mDNS *const m, TCPSocketFlags flags, mDNSIPPort *port); // creates a TCP socket
extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
extern int mDNSPlatformTCPGetFD(TCPSocket *sock);
extern mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname,
mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context);
extern void mDNSPlatformTCPCloseConnection(TCPSocket *sock);
extern long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool *closed);
extern long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len);
extern UDPSocket *mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport);
extern void mDNSPlatformUDPClose(UDPSocket *sock);
extern void mDNSPlatformReceiveBPF_fd(mDNS *const m, int fd);
extern void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID);
extern void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID);
extern void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID);
extern void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst);
// mDNSPlatformTLSSetupCerts/mDNSPlatformTLSTearDownCerts used by dnsextd
extern mStatus mDNSPlatformTLSSetupCerts(void);
extern void mDNSPlatformTLSTearDownCerts(void);
// Platforms that support unicast browsing and dynamic update registration for clients who do not specify a domain
// in browse/registration calls must implement these routines to get the "default" browse/registration list.
extern void mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains, DNameListElem **BrowseDomains);
extern mStatus mDNSPlatformGetPrimaryInterface(mDNS *const m, mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
extern void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
extern void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason);
extern void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration);
extern mDNSBool mDNSPlatformValidRecordForInterface(AuthRecord *rr, const NetworkInterfaceInfo *intf);
#ifdef _LEGACY_NAT_TRAVERSAL_
// Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
extern void LNT_SendDiscoveryMsg(mDNS *m);
extern void LNT_ConfigureRouterInfo(mDNS *m, const mDNSInterfaceID InterfaceID, const mDNSu8 *const data, const mDNSu16 len);
extern mStatus LNT_GetExternalAddress(mDNS *m);
extern mStatus LNT_MapPort(mDNS *m, NATTraversalInfo *const n);
extern mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n);
extern void LNT_ClearState(mDNS *const m);
#endif // _LEGACY_NAT_TRAVERSAL_
// The core mDNS code provides these functions, for the platform support code to call at appropriate times
//
// mDNS_SetFQDN() is called once on startup (typically from mDNSPlatformInit())
// and then again on each subsequent change of the host name.
//
// mDNS_RegisterInterface() is used by the platform support layer to inform mDNSCore of what
// physical and/or logical interfaces are available for sending and receiving packets.
// Typically it is called on startup for each available interface, but register/deregister may be
// called again later, on multiple occasions, to inform the core of interface configuration changes.
// If set->Advertise is set non-zero, then mDNS_RegisterInterface() also registers the standard
// resource records that should be associated with every publicised IP address/interface:
// -- Name-to-address records (A/AAAA)
// -- Address-to-name records (PTR)
// -- Host information (HINFO)
// IMPORTANT: The specified mDNSInterfaceID MUST NOT be 0, -1, or -2; these values have special meaning
// mDNS_RegisterInterface does not result in the registration of global hostnames via dynamic update -
// see mDNS_SetPrimaryInterfaceInfo, mDNS_AddDynDNSHostName, etc. for this purpose.
// Note that the set may be deallocated immediately after it is deregistered via mDNS_DeegisterInterface.
//
// mDNS_RegisterDNS() is used by the platform support layer to provide the core with the addresses of
// available domain name servers for unicast queries/updates. RegisterDNS() should be called once for
// each name server, typically at startup, or when a new name server becomes available. DeregiterDNS()
// must be called whenever a registered name server becomes unavailable. DeregisterDNSList deregisters
// all registered servers. mDNS_DNSRegistered() returns true if one or more servers are registered in the core.
//
// mDNSCoreInitComplete() is called when the platform support layer is finished.
// Typically this is at the end of mDNSPlatformInit(), but may be later
// (on platforms like OT that allow asynchronous initialization of the networking stack).
//
// mDNSCoreReceive() is called when a UDP packet is received
//
// mDNSCoreMachineSleep() is called when the machine sleeps or wakes
// (This refers to heavyweight laptop-style sleep/wake that disables network access,
// not lightweight second-by-second CPU power management modes.)
extern void mDNS_SetFQDN(mDNS *const m);
extern void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set);
extern void mDNS_DeactivateNetWake_internal(mDNS *const m, NetworkInterfaceInfo *set);
extern mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
extern void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool flapping);
extern void mDNSCoreInitComplete(mDNS *const m, mStatus result);
extern void mDNSCoreReceive(mDNS *const m, void *const msg, const mDNSu8 *const end,
const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
extern void mDNSCoreRestartQueries(mDNS *const m);
typedef void (*FlushCache)(mDNS *const m);
typedef void (*CallbackBeforeStartQuery)(mDNS *const m, void *context);
extern void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDomainsChanged, FlushCache flushCacheRecords,
CallbackBeforeStartQuery beforeQueryStart, void *context);
extern mDNSBool mDNSCoreHaveAdvertisedMulticastServices(mDNS *const m);
extern void mDNSCoreMachineSleep(mDNS *const m, mDNSBool wake);
extern mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now);
extern mDNSs32 mDNSCoreIntervalToNextWake(mDNS *const m, mDNSs32 now);
extern void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, const mDNSu8 *const end, const mDNSInterfaceID InterfaceID);
extern mDNSBool mDNSAddrIsDNSMulticast(const mDNSAddr *ip);
extern CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, CacheGroup *cg, mDNSs32 delay);
extern void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event);
extern void GrantCacheExtensions(mDNS *const m, DNSQuestion *q, mDNSu32 lease);
extern void MakeNegativeCacheRecord(mDNS *const m, CacheRecord *const cr,
const domainname *const name, const mDNSu32 namehash, const mDNSu16 rrtype, const mDNSu16 rrclass, mDNSu32 ttl_seconds,
mDNSInterfaceID InterfaceID, DNSServer *dnsserver);
extern void CompleteDeregistration(mDNS *const m, AuthRecord *rr);
extern void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheRecord *const rr, const QC_result AddRecord);
extern char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID InterfaceID);
extern void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *newServer);
extern void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr);
extern void CheckSuppressUnusableQuestions(mDNS *const m);
extern void RetrySearchDomainQuestions(mDNS *const m);
extern mDNSBool DomainEnumQuery(const domainname *qname);
// Used only in logging to restrict the number of /etc/hosts entries printed
extern void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result);
// exported for using the hash for /etc/hosts AuthRecords
extern AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 slot, const mDNSu32 namehash, const domainname *const name);
extern AuthGroup *AuthGroupForRecord(AuthHash *r, const mDNSu32 slot, const ResourceRecord *const rr);
extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
// For now this AutoTunnel stuff is specific to Mac OS X.
// In the future, if there's demand, we may see if we can abstract it out cleanly into the platform layer
#if APPLE_OSX_mDNSResponder
extern void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
extern void AddNewClientTunnel(mDNS *const m, DNSQuestion *const q);
extern void SetupLocalAutoTunnelInterface_internal(mDNS *const m, mDNSBool servicesStarting);
extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
extern mStatus ActivateLocalProxy(mDNS *const m, char *ifname);
extern void RemoveAutoTunnel6Record(mDNS *const m);
extern mDNSBool RecordReadyForSleep(mDNS *const m, AuthRecord *rr);
#endif
// ***************************************************************************
#if 0
#pragma mark -
#pragma mark - Sleep Proxy
#endif
// Sleep Proxy Server Property Encoding
//
// Sleep Proxy Servers are advertised using a structured service name, consisting of four
// metrics followed by a human-readable name. The metrics assist clients in deciding which
// Sleep Proxy Server(s) to use when multiple are available on the network. Each metric
// is a two-digit decimal number in the range 10-99. Lower metrics are generally better.
//
// AA-BB-CC-DD Name
//
// Metrics:
//
// AA = Intent
// BB = Portability
// CC = Marginal Power
// DD = Total Power
//
//
// ** Intent Metric **
//
// 20 = Dedicated Sleep Proxy Server -- a device, permanently powered on,
// installed for the express purpose of providing Sleep Proxy Service.
//
// 30 = Primary Network Infrastructure Hardware -- a router, DHCP server, NAT gateway,
// or similar permanently installed device which is permanently powered on.
// This is hardware designed for the express purpose of being network
// infrastructure, and for most home users is typically a single point
// of failure for the local network -- e.g. most home users only have
// a single NAT gateway / DHCP server. Even though in principle the
// hardware might technically be capable of running different software,
// a typical user is unlikely to do that. e.g. AirPort base station.
//
// 40 = Primary Network Infrastructure Software -- a general-purpose computer
// (e.g. Mac, Windows, Linux, etc.) which is currently running DHCP server
// or NAT gateway software, but the user could choose to turn that off
// fairly easily. e.g. iMac running Internet Sharing
//
// 50 = Secondary Network Infrastructure Hardware -- like primary infrastructure
// hardware, except not a single point of failure for the entire local network.
// For example, an AirPort base station in bridge mode. This may have clients
// associated with it, and if it goes away those clients will be inconvenienced,
// but unlike the NAT gateway / DHCP server, the entire local network is not
// dependent on it.
//
// 60 = Secondary Network Infrastructure Software -- like 50, but in a general-
// purpose CPU.
//
// 70 = Incidentally Available Hardware -- a device which has no power switch
// and is generally left powered on all the time. Even though it is not a
// part of what we conventionally consider network infrastructure (router,
// DHCP, NAT, DNS, etc.), and the rest of the network can operate fine
// without it, since it's available and unlikely to be turned off, it is a
// reasonable candidate for providing Sleep Proxy Service e.g. Apple TV,
// or an AirPort base station in client mode, associated with an existing
// wireless network (e.g. AirPort Express connected to a music system, or
// being used to share a USB printer).
//
// 80 = Incidentally Available Software -- a general-purpose computer which
// happens at this time to be set to "never sleep", and as such could be
// useful as a Sleep Proxy Server, but has not been intentionally provided
// for this purpose. Of all the Intent Metric categories this is the
// one most likely to be shut down or put to sleep without warning.
// However, if nothing else is availalable, it may be better than nothing.
// e.g. Office computer in the workplace which has been set to "never sleep"
//
//
// ** Portability Metric **
//
// Inversely related to mass of device, on the basis that, all other things
// being equal, heavier devices are less likely to be moved than lighter devices.
// E.g. A MacBook running Internet Sharing is probably more likely to be
// put to sleep and taken away than a Mac Pro running Internet Sharing.
// The Portability Metric is a logarithmic decibel scale, computed by taking the
// (approximate) mass of the device in milligrammes, taking the base 10 logarithm
// of that, multiplying by 10, and subtracting the result from 100:
//
// Portability Metric = 100 - (log10(mg) * 10)
//
// The Portability Metric is not necessarily computed literally from the actual
// mass of the device; the intent is just that lower numbers indicate more
// permanent devices, and higher numbers indicate devices more likely to be
// removed from the network, e.g., in order of increasing portability:
//
// Mac Pro < iMac < Laptop < iPhone
//
// Example values:
//
// 10 = 1 metric tonne
// 40 = 1kg
// 70 = 1g
// 90 = 10mg
//
//
// ** Marginal Power and Total Power Metrics **
//
// The Marginal Power Metric is the power difference between sleeping and staying awake
// to be a Sleep Proxy Server.
//
// The Total Power Metric is the total power consumption when being Sleep Proxy Server.
//
// The Power Metrics use a logarithmic decibel scale, computed as ten times the
// base 10 logarithm of the (approximate) power in microwatts:
//
// Power Metric = log10(uW) * 10
//
// Higher values indicate higher power consumption. Example values:
//
// 10 = 10 uW
// 20 = 100 uW
// 30 = 1 mW
// 60 = 1 W
// 90 = 1 kW
typedef enum {
mDNSSleepProxyMetric_Dedicated = 20,
mDNSSleepProxyMetric_PrimaryHardware = 30,
mDNSSleepProxyMetric_PrimarySoftware = 40,
mDNSSleepProxyMetric_SecondaryHardware = 50,
mDNSSleepProxyMetric_SecondarySoftware = 60,
mDNSSleepProxyMetric_IncidentalHardware = 70,
mDNSSleepProxyMetric_IncidentalSoftware = 80
} mDNSSleepProxyMetric;
extern void mDNSCoreBeSleepProxyServer_internal(mDNS *const m, mDNSu8 sps, mDNSu8 port, mDNSu8 marginalpower, mDNSu8 totpower);
#define mDNSCoreBeSleepProxyServer(M,S,P,MP,TP) \
do { mDNS_Lock(m); mDNSCoreBeSleepProxyServer_internal((M),(S),(P),(MP),(TP)); mDNS_Unlock(m); } while(0)
extern void FindSPSInCache(mDNS *const m, const DNSQuestion *const q, const CacheRecord *sps[3]);
#define PrototypeSPSName(X) ((X)[0] >= 11 && (X)[3] == '-' && (X)[ 4] == '9' && (X)[ 5] == '9' && \
(X)[6] == '-' && (X)[ 7] == '9' && (X)[ 8] == '9' && \
(X)[9] == '-' && (X)[10] == '9' && (X)[11] == '9' )
#define ValidSPSName(X) ((X)[0] >= 5 && mDNSIsDigit((X)[1]) && mDNSIsDigit((X)[2]) && mDNSIsDigit((X)[4]) && mDNSIsDigit((X)[5]))
#define SPSMetric(X) (!ValidSPSName(X) || PrototypeSPSName(X) ? 1000000 : \
((X)[1]-'0') * 100000 + ((X)[2]-'0') * 10000 + ((X)[4]-'0') * 1000 + ((X)[5]-'0') * 100 + ((X)[7]-'0') * 10 + ((X)[8]-'0'))
// ***************************************************************************
// Some C compiler cleverness. We can make the compiler check certain things for
// us, and report compile-time errors if anything is wrong. The usual way to do
// this would be to use a run-time "if" statement, but then you don't find out
// what's wrong until you run the software. This way, if the assertion condition
// is false, the array size is negative, and the complier complains immediately.
struct CompileTimeAssertionChecks_mDNS {
// Check that the compiler generated our on-the-wire packet format structure definitions
// properly packed, without adding padding bytes to align fields on 32-bit or 64-bit boundaries.
char assert0[(sizeof(rdataSRV) == 262) ? 1 : -1];
char assert1[(sizeof(DNSMessageHeader) == 12) ? 1 : -1];
char assert2[(sizeof(DNSMessage) == 12 + AbsoluteMaxDNSMessageData) ? 1 : -1];
char assert3[(sizeof(mDNSs8) == 1) ? 1 : -1];
char assert4[(sizeof(mDNSu8) == 1) ? 1 : -1];
char assert5[(sizeof(mDNSs16) == 2) ? 1 : -1];
char assert6[(sizeof(mDNSu16) == 2) ? 1 : -1];
char assert7[(sizeof(mDNSs32) == 4) ? 1 : -1];
char assert8[(sizeof(mDNSu32) == 4) ? 1 : -1];
char assert9[(sizeof(mDNSOpaque16) == 2) ? 1 : -1];
char assertA[(sizeof(mDNSOpaque32) == 4) ? 1 : -1];
char assertB[(sizeof(mDNSOpaque128) == 16) ? 1 : -1];
char assertC[(sizeof(CacheRecord) == sizeof(CacheGroup)) ? 1 : -1];
char assertD[(sizeof(int) >= 4) ? 1 : -1];
char assertE[(StandardAuthRDSize >= 256) ? 1 : -1];
char assertF[(sizeof(EthernetHeader) == 14) ? 1 : 0];
char assertG[(sizeof(ARP_EthIP) == 28) ? 1 : 0];
char assertH[(sizeof(IPv4Header) == 20) ? 1 : -1];
char assertI[(sizeof(IPv6Header) == 40) ? 1 : -1];
char assertJ[(sizeof(IPv6NDP) == 24) ? 1 : -1];
char assertK[(sizeof(UDPHeader) == 8) ? 1 : -1];
char assertL[(sizeof(IKEHeader) == 28) ? 1 : -1];
char assertM[(sizeof(TCPHeader) == 20) ? 1 : -1];
// Check our structures are reasonable sizes. Including overly-large buffers, or embedding
// other overly-large structures instead of having a pointer to them, can inadvertently
// cause structure sizes (and therefore memory usage) to balloon unreasonably.
char sizecheck_RDataBody [(sizeof(RDataBody) == 264) ? 1 : -1];
char sizecheck_ResourceRecord [(sizeof(ResourceRecord) <= 64) ? 1 : -1];
char sizecheck_AuthRecord [(sizeof(AuthRecord) <= 1208) ? 1 : -1];
char sizecheck_CacheRecord [(sizeof(CacheRecord) <= 184) ? 1 : -1];
char sizecheck_CacheGroup [(sizeof(CacheGroup) <= 184) ? 1 : -1];
char sizecheck_DNSQuestion [(sizeof(DNSQuestion) <= 786) ? 1 : -1];
char sizecheck_ZoneData [(sizeof(ZoneData) <= 1624) ? 1 : -1];
char sizecheck_NATTraversalInfo [(sizeof(NATTraversalInfo) <= 192) ? 1 : -1];
char sizecheck_HostnameInfo [(sizeof(HostnameInfo) <= 3050) ? 1 : -1];
char sizecheck_DNSServer [(sizeof(DNSServer) <= 328) ? 1 : -1];
char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <= 6850) ? 1 : -1];
char sizecheck_ServiceRecordSet [(sizeof(ServiceRecordSet) <= 5500) ? 1 : -1];
char sizecheck_DomainAuthInfo [(sizeof(DomainAuthInfo) <= 7808) ? 1 : -1];
char sizecheck_ServiceInfoQuery [(sizeof(ServiceInfoQuery) <= 3200) ? 1 : -1];
#if APPLE_OSX_mDNSResponder
char sizecheck_ClientTunnel [(sizeof(ClientTunnel) <= 1148) ? 1 : -1];
#endif
};
// ***************************************************************************
#endif