2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
25 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
26 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
27 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
28 * therefore common sense dictates that if they are part of a compound statement then they
29 * should be indented to the same level as everything else in that compound statement.
30 * Indenting curly braces at the same level as the "if" implies that curly braces are
31 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
32 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
33 * understand why variable y is not of type "char*" just proves the point that poor code
34 * layout leads people to unfortunate misunderstandings about how the C language really works.)
36 Change History (most recent first):
39 Revision 1.12 2003/11/14 21:27:09 cheshire
40 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
41 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1005) instead of 256-byte buffers.
43 Revision 1.11 2003/10/30 19:26:38 cheshire
44 Fix warnings on certain compilers
46 Revision 1.10 2003/09/02 20:38:57 cheshire
47 #include <signal.h> for Linux
49 Revision 1.9 2003/08/14 23:57:46 cheshire
50 Report if there is no answer at all from the target host
52 Revision 1.8 2003/08/14 02:19:55 cheshire
53 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
55 Revision 1.7 2003/08/12 19:56:26 cheshire
58 Revision 1.6 2003/08/06 01:46:18 cheshire
59 Distinguish no answer from partial answer
61 Revision 1.5 2003/08/05 23:56:26 cheshire
62 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
63 (Right now mDNSPosix.c just reports 255 -- we should fix this)
65 Revision 1.4 2003/08/04 17:24:48 cheshire
66 Combine the three separate A/AAAA/HINFO queries into a single qtype "ANY" query
68 Revision 1.3 2003/08/04 17:14:08 cheshire
69 Do both AAAA queries in parallel
71 Revision 1.2 2003/08/02 02:25:13 cheshire
72 Multiple improvements: Now displays host's name, and all v4 and v6 addresses, as well as HINFO record
74 Revision 1.1 2003/08/01 02:20:02 cheshire
75 Add mDNSIdentify tool, used to discover what version of mDNSResponder a particular host is running
79 //*************************************************************************************************************
80 // Incorporate mDNS.c functionality
82 // We want to use the functionality provided by "mDNS.c",
83 // except we'll sneak a peek at the packets before forwarding them to the normal mDNSCoreReceive() routine
84 #define mDNSCoreReceive __MDNS__mDNSCoreReceive
86 #undef mDNSCoreReceive
88 //*************************************************************************************************************
95 #include <sys/socket.h>
96 #include <netinet/in.h>
97 #include <netinet/in_systm.h> // For n_long, required by <netinet/ip.h> below
98 #include <netinet/ip.h> // For IPTOS_LOWDELAY etc.
99 #include <arpa/inet.h>
102 #include "mDNSClientAPI.h"// Defines the interface to the mDNS core code
103 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
104 #include "ExampleClientApp.h"
106 //*************************************************************************************************************
109 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
110 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
111 #define RR_CACHE_SIZE 500
112 static CacheRecord gRRCache
[RR_CACHE_SIZE
];
114 static volatile int StopNow
; // 0 means running, 1 means stop because we got an answer, 2 means stop because of Ctrl-C
115 static volatile int NumAnswers
, NumAddr
, NumAAAA
, NumHINFO
;
116 static char hostname
[MAX_ESCAPED_DOMAIN_NAME
], hardware
[256], software
[256];
117 static mDNSOpaque16 lastid
, id
;
119 //*************************************************************************************************************
122 // Special version of printf that knows how to print IP addresses, DNS-format name strings, etc.
123 mDNSlocal mDNSu32
mprintf(const char *format
, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
124 mDNSlocal mDNSu32
mprintf(const char *format
, ...)
127 unsigned char buffer
[512];
129 va_start(ptr
,format
);
130 length
= mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
);
132 printf("%s", buffer
);
136 //*************************************************************************************************************
139 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
140 const mDNSAddr
*const srcaddr
, const mDNSIPPort srcport
, const mDNSAddr
*const dstaddr
, const mDNSIPPort dstport
,
141 const mDNSInterfaceID InterfaceID
, mDNSu8 ttl
)
143 // Snag copy of header ID, then call through
145 __MDNS__mDNSCoreReceive(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, dstport
, InterfaceID
, ttl
);
148 static void NameCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
151 (void)question
; // Unused
152 (void)AddRecord
;// Unused
153 if (!id
.NotAnInteger
) id
= lastid
;
154 ConvertDomainNameToCString(&answer
->rdata
->u
.name
, hostname
);
156 mprintf("%##s %s %##s\n", answer
->name
.c
, DNSTypeName(answer
->rrtype
), &answer
->rdata
->u
.name
.c
);
159 static void InfoCallback(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, mDNSBool AddRecord
)
162 (void)question
; // Unused
163 (void)AddRecord
;// Unused
164 if (answer
->rrtype
== kDNSType_A
)
166 if (!id
.NotAnInteger
) id
= lastid
;
169 mprintf("%##s %s %.4a\n", answer
->name
.c
, DNSTypeName(answer
->rrtype
), &answer
->rdata
->u
.ip
);
171 else if (answer
->rrtype
== kDNSType_AAAA
)
173 if (!id
.NotAnInteger
) id
= lastid
;
176 mprintf("%##s %s %.16a\n", answer
->name
.c
, DNSTypeName(answer
->rrtype
), &answer
->rdata
->u
.ipv6
);
178 else if (answer
->rrtype
== kDNSType_HINFO
)
180 mDNSu8
*p
= answer
->rdata
->u
.data
;
181 strncpy(hardware
, (char*)(p
+1), p
[0]);
184 strncpy(software
, (char*)(p
+1), p
[0]);
191 mDNSexport
void WaitForAnswer(mDNS
*const m
, int seconds
)
194 gettimeofday(&end
, NULL
);
195 end
.tv_sec
+= seconds
;
202 struct timeval now
, remain
= end
;
206 gettimeofday(&now
, NULL
);
207 if (remain
.tv_usec
< now
.tv_usec
) { remain
.tv_usec
+= 1000000; remain
.tv_sec
--; }
208 if (remain
.tv_sec
< now
.tv_sec
) return;
209 remain
.tv_usec
-= now
.tv_usec
;
210 remain
.tv_sec
-= now
.tv_sec
;
211 mDNSPosixGetFDSet(m
, &nfds
, &readfds
, &remain
);
212 result
= select(nfds
, &readfds
, NULL
, NULL
, &remain
);
213 if (result
>= 0) mDNSPosixProcessFDSet(m
, &readfds
);
214 else if (errno
!= EINTR
) StopNow
= 2;
218 mDNSlocal mStatus
StartQuery(DNSQuestion
*q
, char *qname
, mDNSu16 qtype
, mDNSQuestionCallback callback
)
220 if (qname
) MakeDomainNameFromDNSNameString(&q
->qname
, qname
);
222 q
->InterfaceID
= mDNSInterface_Any
;
224 q
->qclass
= kDNSClass_IN
;
225 q
->QuestionCallback
= callback
;
226 q
->QuestionContext
= NULL
;
228 //mprintf("%##s %s ?\n", q->qname.c, DNSTypeName(qtype));
229 return(mDNS_StartQuery(&mDNSStorage
, q
));
232 mDNSlocal
int DoQuery(DNSQuestion
*q
, char *qname
, mDNSu16 qtype
, mDNSQuestionCallback callback
)
234 mStatus status
= StartQuery(q
, qname
, qtype
, callback
);
235 if (status
!= mStatus_NoError
)
239 WaitForAnswer(&mDNSStorage
, 4);
240 mDNS_StopQuery(&mDNSStorage
, q
);
241 if (StopNow
== 0 && NumAnswers
== 0)
242 printf("%s %s *** No Answer ***\n", qname
, DNSTypeName(qtype
));
247 mDNSlocal
void HandleSIG(int signal
)
249 (void)signal
; // Unused
255 mDNSexport
int main(int argc
, char **argv
)
263 if (argc
< 2) goto usage
;
265 // Initialise the mDNS core.
266 status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
267 gRRCache
, RR_CACHE_SIZE
,
268 mDNS_Init_DontAdvertiseLocalAddresses
,
269 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
270 if (status
) { fprintf(stderr
, "Daemon start: mDNS_Init failed %ld\n", status
); return(status
); }
272 signal(SIGINT
, HandleSIG
); // SIGINT is what you get for a Ctrl-C
273 signal(SIGTERM
, HandleSIG
);
275 if (inet_pton(AF_INET
, argv
[1], &s4
) == 1)
277 mDNSu8
*p
= (mDNSu8
*)&s4
;
278 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.", p
[3], p
[2], p
[1], p
[0]);
279 printf("%s\n", buffer
);
280 if (DoQuery(&q
, buffer
, kDNSType_PTR
, NameCallback
) != 1) goto exit
;
282 else if (inet_pton(AF_INET6
, argv
[1], &s6
) == 1)
286 mDNSu8
*p
= (mDNSu8
*)&s6
;
287 for (i
= 0; i
< 16; i
++)
289 static const char hexValues
[] = "0123456789ABCDEF";
290 buffer
[i
* 4 ] = hexValues
[p
[15-i
] & 0x0F];
291 buffer
[i
* 4 + 1] = '.';
292 buffer
[i
* 4 + 2] = hexValues
[p
[15-i
] >> 4];
293 buffer
[i
* 4 + 3] = '.';
295 mDNS_snprintf(&buffer
[64], sizeof(buffer
)-64, "ip6.arpa.");
296 MakeDomainNameFromDNSNameString(&q1
.qname
, buffer
);
297 mDNS_snprintf(&buffer
[32], sizeof(buffer
)-32, "ip6.arpa."); // Workaround for WWDC bug
298 MakeDomainNameFromDNSNameString(&q2
.qname
, buffer
);
299 StartQuery(&q1
, NULL
, kDNSType_PTR
, NameCallback
);
300 StartQuery(&q2
, NULL
, kDNSType_PTR
, NameCallback
);
301 WaitForAnswer(&mDNSStorage
, 4);
302 mDNS_StopQuery(&mDNSStorage
, &q1
);
303 mDNS_StopQuery(&mDNSStorage
, &q2
);
304 if (StopNow
!= 1) { mprintf("%##s %s *** No Answer ***\n", q1
.qname
.c
, DNSTypeName(q1
.qtype
)); goto exit
; }
307 strcpy(hostname
, argv
[1]);
309 // Now we have the host name; get its A, AAAA, and HINFO
310 if (DoQuery(&q
, hostname
, kDNSQType_ANY
, InfoCallback
) == 2) goto exit
; // Interrupted with Ctrl-C
312 if (hardware
[0] || software
[0])
314 printf("HINFO Hardware: %s\n", hardware
);
315 printf("HINFO Software: %s\n", software
);
319 printf("Host has no HINFO record; Best guess is ");
320 if (id
.b
[1]) printf("mDNSResponder-%d\n", id
.b
[1]);
321 else if (NumAAAA
) printf("very early Panther build (mDNSResponder-33 or earlier)\n");
322 else printf("Jaguar version of mDNSResponder with no IPv6 support\n");
325 printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n");
328 mDNS_Close(&mDNSStorage
);
332 fprintf(stderr
, "%s <dot-local hostname> or <IPv4 address> or <IPv6 address>\n", argv
[0]);