]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSPosix/Identify.c
mDNSResponder-58.3.tar.gz
[apple/mdnsresponder.git] / mDNSPosix / Identify.c
1 /*
2 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * Formatting notes:
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.)
35
36 Change History (most recent first):
37
38 $Log: Identify.c,v $
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.
42
43 Revision 1.11 2003/10/30 19:26:38 cheshire
44 Fix warnings on certain compilers
45
46 Revision 1.10 2003/09/02 20:38:57 cheshire
47 #include <signal.h> for Linux
48
49 Revision 1.9 2003/08/14 23:57:46 cheshire
50 Report if there is no answer at all from the target host
51
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
54
55 Revision 1.7 2003/08/12 19:56:26 cheshire
56 Update to APSL 2.0
57
58 Revision 1.6 2003/08/06 01:46:18 cheshire
59 Distinguish no answer from partial answer
60
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)
64
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
67
68 Revision 1.3 2003/08/04 17:14:08 cheshire
69 Do both AAAA queries in parallel
70
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
73
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
76
77 */
78
79 //*************************************************************************************************************
80 // Incorporate mDNS.c functionality
81
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
85 #include "mDNS.c"
86 #undef mDNSCoreReceive
87
88 //*************************************************************************************************************
89 // Headers
90
91 #include <unistd.h>
92 #include <stdio.h>
93 #include <string.h>
94 #include <errno.h>
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>
100 #include <signal.h>
101
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"
105
106 //*************************************************************************************************************
107 // Globals
108
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];
113
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;
118
119 //*************************************************************************************************************
120 // Utilities
121
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, ...)
125 {
126 mDNSu32 length;
127 unsigned char buffer[512];
128 va_list ptr;
129 va_start(ptr,format);
130 length = mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr);
131 va_end(ptr);
132 printf("%s", buffer);
133 return(length);
134 }
135
136 //*************************************************************************************************************
137 // Main code
138
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)
142 {
143 // Snag copy of header ID, then call through
144 lastid = msg->h.id;
145 __MDNS__mDNSCoreReceive(m, msg, end, srcaddr, srcport, dstaddr, dstport, InterfaceID, ttl);
146 }
147
148 static void NameCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
149 {
150 (void)m; // Unused
151 (void)question; // Unused
152 (void)AddRecord;// Unused
153 if (!id.NotAnInteger) id = lastid;
154 ConvertDomainNameToCString(&answer->rdata->u.name, hostname);
155 StopNow = 1;
156 mprintf("%##s %s %##s\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.name.c);
157 }
158
159 static void InfoCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord)
160 {
161 (void)m; // Unused
162 (void)question; // Unused
163 (void)AddRecord;// Unused
164 if (answer->rrtype == kDNSType_A)
165 {
166 if (!id.NotAnInteger) id = lastid;
167 NumAnswers++;
168 NumAddr++;
169 mprintf("%##s %s %.4a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ip);
170 }
171 else if (answer->rrtype == kDNSType_AAAA)
172 {
173 if (!id.NotAnInteger) id = lastid;
174 NumAnswers++;
175 NumAAAA++;
176 mprintf("%##s %s %.16a\n", answer->name.c, DNSTypeName(answer->rrtype), &answer->rdata->u.ipv6);
177 }
178 else if (answer->rrtype == kDNSType_HINFO)
179 {
180 mDNSu8 *p = answer->rdata->u.data;
181 strncpy(hardware, (char*)(p+1), p[0]);
182 hardware[p[0]] = 0;
183 p += 1 + p[0];
184 strncpy(software, (char*)(p+1), p[0]);
185 software[p[0]] = 0;
186 NumAnswers++;
187 NumHINFO++;
188 }
189 }
190
191 mDNSexport void WaitForAnswer(mDNS *const m, int seconds)
192 {
193 struct timeval end;
194 gettimeofday(&end, NULL);
195 end.tv_sec += seconds;
196 StopNow = 0;
197 NumAnswers = 0;
198 while (!StopNow)
199 {
200 int nfds = 0;
201 fd_set readfds;
202 struct timeval now, remain = end;
203 int result;
204
205 FD_ZERO(&readfds);
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;
215 }
216 }
217
218 mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, mDNSQuestionCallback callback)
219 {
220 if (qname) MakeDomainNameFromDNSNameString(&q->qname, qname);
221
222 q->InterfaceID = mDNSInterface_Any;
223 q->qtype = qtype;
224 q->qclass = kDNSClass_IN;
225 q->QuestionCallback = callback;
226 q->QuestionContext = NULL;
227
228 //mprintf("%##s %s ?\n", q->qname.c, DNSTypeName(qtype));
229 return(mDNS_StartQuery(&mDNSStorage, q));
230 }
231
232 mDNSlocal int DoQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, mDNSQuestionCallback callback)
233 {
234 mStatus status = StartQuery(q, qname, qtype, callback);
235 if (status != mStatus_NoError)
236 StopNow = 2;
237 else
238 {
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));
243 }
244 return(StopNow);
245 }
246
247 mDNSlocal void HandleSIG(int signal)
248 {
249 (void)signal; // Unused
250 debugf("");
251 debugf("HandleSIG");
252 StopNow = 2;
253 }
254
255 mDNSexport int main(int argc, char **argv)
256 {
257 mStatus status;
258 struct in_addr s4;
259 struct in6_addr s6;
260 char buffer[256];
261 DNSQuestion q;
262
263 if (argc < 2) goto usage;
264
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); }
271
272 signal(SIGINT, HandleSIG); // SIGINT is what you get for a Ctrl-C
273 signal(SIGTERM, HandleSIG);
274
275 if (inet_pton(AF_INET, argv[1], &s4) == 1)
276 {
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;
281 }
282 else if (inet_pton(AF_INET6, argv[1], &s6) == 1)
283 {
284 DNSQuestion q1, q2;
285 int i;
286 mDNSu8 *p = (mDNSu8 *)&s6;
287 for (i = 0; i < 16; i++)
288 {
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] = '.';
294 }
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; }
305 }
306 else
307 strcpy(hostname, argv[1]);
308
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
311
312 if (hardware[0] || software[0])
313 {
314 printf("HINFO Hardware: %s\n", hardware);
315 printf("HINFO Software: %s\n", software);
316 }
317 else if (NumAnswers)
318 {
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");
323 }
324 else
325 printf("Incorrect dot-local hostname, address, or no mDNSResponder running on that machine\n");
326
327 exit:
328 mDNS_Close(&mDNSStorage);
329 return(0);
330
331 usage:
332 fprintf(stderr, "%s <dot-local hostname> or <IPv4 address> or <IPv6 address>\n", argv[0]);
333 return(-1);
334 }