1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
26 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
27 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
28 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
29 * therefore common sense dictates that if they are part of a compound statement then they
30 * should be indented to the same level as everything else in that compound statement.
31 * Indenting curly braces at the same level as the "if" implies that curly braces are
32 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
33 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
34 * understand why variable y is not of type "char*" just proves the point that poor code
35 * layout leads people to unfortunate misunderstandings about how the C language really works.)
37 Change History (most recent first):
39 $Log: NetMonitor.c,v $
40 Revision 1.74 2005/12/02 20:08:39 cheshire
41 Update "No HINFO" message
43 Revision 1.73 2005/12/02 19:19:53 cheshire
44 <rdar://problem/4331590> Include interface index and name in mDNSNetMonitor output
46 Revision 1.72 2005/11/07 01:47:45 cheshire
47 <rdar://problem/4331590> Include interface index in mDNSNetMonitor output
49 Revision 1.71 2004/12/16 20:17:11 cheshire
50 <rdar://problem/3324626> Cache memory management improvements
52 Revision 1.70 2004/12/04 02:13:20 cheshire
53 Pass proper record type in GetLargeResourceRecord() calls
55 Revision 1.69 2004/11/30 22:37:01 cheshire
56 Update copyright dates and add "Mode: C; tab-width: 4" headers
58 Revision 1.68 2004/10/23 01:16:01 cheshire
59 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
61 Revision 1.67 2004/10/16 00:17:00 cheshire
62 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
64 Revision 1.66 2004/09/17 00:31:52 cheshire
65 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
67 Revision 1.65 2004/09/16 01:58:22 cheshire
70 Revision 1.64 2004/06/15 02:39:47 cheshire
71 When displaying error message, only show command name, not entire path
73 Revision 1.63 2004/05/18 23:51:26 cheshire
74 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
76 Revision 1.62 2004/03/16 18:24:25 cheshire
77 If packet destination was not multicast, then display it
79 Revision 1.61 2004/02/20 09:36:46 cheshire
80 Also show TTL in packet header, if it's not 255
82 Revision 1.60 2004/02/07 02:11:35 cheshire
83 Make mDNSNetMonitor smarter about sending targeted unicast HINFO queries
85 Revision 1.59 2004/02/03 21:42:55 cheshire
86 Add constants kReportTopServices and kReportTopHosts
88 Revision 1.58 2004/01/27 20:15:23 cheshire
89 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
91 Revision 1.57 2004/01/24 23:59:42 cheshire
92 Change to use mDNSVal16() instead of shifting and ORing
94 Revision 1.56 2004/01/24 05:25:34 cheshire
95 mDNSNetMonitor now uses the new ability to send unicast queries so that
96 it causes less perturbation of the network traffic it's monitoring.
98 Revision 1.55 2003/12/23 00:21:31 cheshire
99 Send HINFO queries to determine the mDNSResponder version of each host
101 Revision 1.54 2003/12/17 01:06:39 cheshire
102 Also show host name along with HINFO data
104 Revision 1.53 2003/12/17 00:51:22 cheshire
105 Changed mDNSNetMonitor and mDNSIdentify to link the object files
106 instead of #including the "DNSCommon.c" "uDNS.c" and source files
108 Revision 1.52 2003/12/17 00:21:51 cheshire
109 If we received one, display host's HINFO record in final summary
111 Revision 1.51 2003/12/13 03:05:28 ksekar
112 <rdar://problem/3192548>: DynDNS: Unicast query of service records
114 Revision 1.50 2003/12/08 20:47:02 rpantos
115 Add support for mDNSResponder on Linux.
117 Revision 1.49 2003/10/30 19:38:56 cheshire
118 Fix warning on certain compilers
120 Revision 1.48 2003/10/30 19:30:00 cheshire
121 Fix warnings on certain compilers
123 Revision 1.47 2003/09/05 18:49:57 cheshire
124 Add total packet size to display
126 Revision 1.46 2003/09/05 02:33:48 cheshire
127 Set output to be line buffered, so you can redirect to a file and "tail -f" the file in another window
129 Revision 1.45 2003/09/04 00:16:20 cheshire
130 Only show count of unique source addresses seen on network if we're not filtering
132 Revision 1.44 2003/09/02 22:13:28 cheshire
133 Show total host count in final summary table
135 Revision 1.43 2003/09/02 21:42:52 cheshire
136 Improved alignment of final summary table with v6 addresses
138 Revision 1.42 2003/09/02 20:59:24 cheshire
139 Use bcopy() instead of non-portable "__u6_addr.__u6_addr32" fields.
141 Revision 1.41 2003/08/29 22:05:44 cheshire
142 Also count subsequent KA packets for the purposes of statistics counting
144 Revision 1.40 2003/08/29 16:43:24 cheshire
145 Also display breakdown of Probe/Goodbye/BrowseQ etc. for each host
147 Revision 1.39 2003/08/28 02:07:48 vlubet
148 Added "per hosts" statistics
150 Revision 1.38 2003/08/20 22:41:42 cheshire
151 Also display total multicast packet count
153 Revision 1.37 2003/08/20 22:32:08 cheshire
154 Error in DisplayQuery: Authorities come *after* Answers, not before
156 Revision 1.36 2003/08/18 23:20:10 cheshire
157 RDLength moved from the RData to the ResourceRecord object.
159 Revision 1.35 2003/08/15 20:17:28 cheshire
160 "LargeResourceRecord" changed to "LargeCacheRecord"
162 Revision 1.34 2003/08/14 02:19:55 cheshire
163 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
165 Revision 1.33 2003/08/12 19:56:26 cheshire
168 Revision 1.32 2003/08/06 18:57:01 cheshire
171 Revision 1.31 2003/08/06 02:05:12 cheshire
172 Add ability to give a list of hosts to monitor
174 Revision 1.30 2003/08/05 23:56:26 cheshire
175 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
176 (Right now mDNSPosix.c just reports 255 -- we should fix this)
178 Revision 1.29 2003/08/05 00:43:12 cheshire
179 Report errors encountered while processing authority section
181 Revision 1.28 2003/07/29 22:51:08 cheshire
182 Added hexdump for packets we can't decode, so we can find out *why* we couldn't decode them
184 Revision 1.27 2003/07/29 22:48:04 cheshire
185 Completed support for decoding packets containing oversized resource records
187 Revision 1.26 2003/07/19 03:25:23 cheshire
188 Change to make use of new GetLargeResourceRecord() call, for handling larger records
190 Revision 1.25 2003/07/18 00:13:23 cheshire
191 Remove erroneous trailing '\' from TXT record display
193 Revision 1.24 2003/07/17 17:10:51 cheshire
194 <rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
195 Further work: distinguish between PM and PU
197 Revision 1.23 2003/07/16 22:20:23 cheshire
198 <rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
199 Made mDNSNetMonitor distinguish between QM and QU in its logging output
201 Revision 1.22 2003/07/02 21:19:58 cheshire
202 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
204 Revision 1.21 2003/06/18 05:48:41 cheshire
207 Revision 1.20 2003/06/06 22:18:22 cheshire
208 Add extra space in Q output to line it up with RR output
210 Revision 1.19 2003/06/06 21:05:04 cheshire
211 Display state of cache-flush bit on additional records
213 Revision 1.18 2003/06/06 20:01:30 cheshire
214 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
215 (Global search-and-replace; no functional change to code execution.)
217 Revision 1.17 2003/06/06 14:26:50 cheshire
218 Explicitly #include <time.h> for the benefit of certain Linux distributions
220 Revision 1.16 2003/05/29 21:56:36 cheshire
222 Distinguish modern multicast queries from legacy multicast queries
223 In addition to record counts, display packet counts of queries, legacy queries, and responses
224 Include TTL in RR display
226 Revision 1.15 2003/05/29 20:03:57 cheshire
227 Various improvements:
228 Display start and end time, average rates in packets-per-minute,
229 show legacy queries as -LQ-, improve display of TXT and unknown records
231 Revision 1.14 2003/05/26 04:45:42 cheshire
232 Limit line length when printing super-long TXT records
234 Revision 1.13 2003/05/26 03:21:29 cheshire
235 Tidy up address structure naming:
236 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
237 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
238 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
240 Revision 1.12 2003/05/26 03:01:28 cheshire
241 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
243 Revision 1.11 2003/05/26 00:48:13 cheshire
244 If mDNS packet contains a non-zero message ID, then display it.
246 Revision 1.10 2003/05/22 01:10:32 cheshire
247 Indicate when the TC bit is set on a query packet
249 Revision 1.9 2003/05/21 03:56:00 cheshire
250 Improve display of Probe queries
252 Revision 1.8 2003/05/09 21:41:56 cheshire
253 Track deletion/goodbye packets as separate category
255 Revision 1.7 2003/05/07 00:16:01 cheshire
256 More detailed decoding of Resource Records
258 Revision 1.6 2003/05/05 21:16:16 cheshire
259 <rdar://problem/3241281> Change timenow from a local variable to a structure member
261 Revision 1.5 2003/04/19 01:16:22 cheshire
262 Add filter option, to monitor only packets from a single specified source address
264 Revision 1.4 2003/04/18 00:45:21 cheshire
265 Distinguish announcements (AN) from deletions (DE)
267 Revision 1.3 2003/04/15 18:26:01 cheshire
268 Added timestamps and help information
270 Revision 1.2 2003/04/04 20:42:02 cheshire
271 Fix broken statistics counting
273 Revision 1.1 2003/04/04 01:37:14 cheshire
278 //*************************************************************************************************************
279 // Incorporate mDNS.c functionality
281 // We want to use much of the functionality provided by "mDNS.c",
282 // except we'll steal the packets that would be sent to normal mDNSCoreReceive() routine
283 #define mDNSCoreReceive __NOT__mDNSCoreReceive__NOT__
285 #undef mDNSCoreReceive
287 //*************************************************************************************************************
290 #include <stdio.h> // For printf()
291 #include <stdlib.h> // For malloc()
292 #include <string.h> // For bcopy()
293 #include <time.h> // For "struct tm" etc.
294 #include <signal.h> // For SIGINT, SIGTERM
295 #include <netdb.h> // For gethostbyname()
296 #include <sys/socket.h> // For AF_INET, AF_INET6, etc.
297 #include <arpa/inet.h> // For inet_addr()
298 #include <net/if.h> // For IF_NAMESIZE
299 #include <netinet/in.h> // For INADDR_NONE
301 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
302 #include "ExampleClientApp.h"
304 //*************************************************************************************************************
305 // Types and structures
309 // Primitive operations
313 // These are meta-categories;
314 // Query and Answer operations are actually subdivided into two classes:
315 // Browse query/answer and
316 // Resolve query/answer
320 // The "Browse" variants of query/answer
325 // The "Resolve" variants of query/answer
333 typedef struct ActivityStat_struct ActivityStat
;
334 struct ActivityStat_struct
340 int stat
[OP_NumTypes
];
343 typedef struct FilterList_struct FilterList
;
344 struct FilterList_struct
350 //*************************************************************************************************************
353 #define kReportTopServices 15
354 #define kReportTopHosts 15
356 //*************************************************************************************************************
359 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
360 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
362 struct timeval tv_start
, tv_end
, tv_interval
;
364 static FilterList
*Filters
;
365 #define ExactlyOneFilter (Filters && !Filters->next)
367 static int NumPktQ
, NumPktL
, NumPktR
, NumPktB
; // Query/Legacy/Response/Bad
368 static int NumProbes
, NumGoodbyes
, NumQuestions
, NumLegacy
, NumAnswers
, NumAdditionals
;
370 static ActivityStat
*stats
;
372 #define OPBanner "Total Ops Probe Goodbye BrowseQ BrowseA ResolveQ ResolveA"
374 //*************************************************************************************************************
377 // Special version of printf that knows how to print IP addresses, DNS-format name strings, etc.
378 mDNSlocal mDNSu32
mprintf(const char *format
, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
379 mDNSlocal mDNSu32
mprintf(const char *format
, ...)
382 unsigned char buffer
[512];
384 va_start(ptr
,format
);
385 length
= mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
);
387 printf("%s", buffer
);
391 //*************************************************************************************************************
394 // Would benefit from a hash
398 HostPkt_Q
= 0, // Query
399 HostPkt_L
= 1, // Legacy Query
400 HostPkt_R
= 2, // Response
401 HostPkt_B
= 3, // Bad
408 unsigned long pkts
[HostPkt_NumTypes
];
409 unsigned long totalops
;
410 unsigned long stat
[OP_NumTypes
];
413 UTF8str255 HIHardware
;
414 UTF8str255 HISoftware
;
419 #define HostEntryTotalPackets(H) ((H)->pkts[HostPkt_Q] + (H)->pkts[HostPkt_L] + (H)->pkts[HostPkt_R] + (H)->pkts[HostPkt_B])
428 static HostList IPv4HostList
= { 0, 0, 0 };
429 static HostList IPv6HostList
= { 0, 0, 0 };
431 mDNSlocal HostEntry
*FindHost(const mDNSAddr
*addr
, HostList
* list
)
435 for (i
= 0; i
< list
->num
; i
++)
437 HostEntry
*entry
= list
->hosts
+ i
;
438 if (mDNSSameAddress(addr
, &entry
->addr
))
445 mDNSlocal HostEntry
*AddHost(const mDNSAddr
*addr
, HostList
* list
)
449 if (list
->num
>= list
->max
)
451 long newMax
= list
->max
+ 64;
452 HostEntry
*newHosts
= realloc(list
->hosts
, newMax
* sizeof(HostEntry
));
453 if (newHosts
== NULL
)
456 list
->hosts
= newHosts
;
459 entry
= list
->hosts
+ list
->num
++;
462 for (i
=0; i
<HostPkt_NumTypes
; i
++) entry
->pkts
[i
] = 0;
464 for (i
=0; i
<OP_NumTypes
; i
++) entry
->stat
[i
] = 0;
465 entry
->hostname
.c
[0] = 0;
466 entry
->revname
.c
[0] = 0;
467 entry
->HIHardware
.c
[0] = 0;
468 entry
->HISoftware
.c
[0] = 0;
469 entry
->NumQueries
= 0;
471 if (entry
->addr
.type
== mDNSAddrType_IPv4
)
473 mDNSv4Addr ip
= entry
->addr
.ip
.v4
;
475 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.", ip
.b
[3], ip
.b
[2], ip
.b
[1], ip
.b
[0]);
476 MakeDomainNameFromDNSNameString(&entry
->revname
, buffer
);
482 mDNSlocal HostEntry
*GotPacketFromHost(const mDNSAddr
*addr
, HostPkt_Type t
, mDNSOpaque16 id
)
484 if (ExactlyOneFilter
) return(NULL
);
487 HostList
*list
= (addr
->type
== mDNSAddrType_IPv4
) ? &IPv4HostList
: &IPv6HostList
;
488 HostEntry
*entry
= FindHost(addr
, list
);
489 if (!entry
) entry
= AddHost(addr
, list
);
490 if (!entry
) return(NULL
);
491 // Don't count our own interrogation packets
492 if (id
.NotAnInteger
!= 0xFFFF) entry
->pkts
[t
]++;
497 mDNSlocal
void RecordHostInfo(HostEntry
*entry
, const ResourceRecord
*const pktrr
)
499 if (!entry
->hostname
.c
[0])
501 if (pktrr
->rrtype
== kDNSType_A
|| pktrr
->rrtype
== kDNSType_AAAA
)
503 // Should really check that the rdata in the address record matches the source address of this packet
504 entry
->NumQueries
= 0;
505 AssignDomainName(&entry
->hostname
, pktrr
->name
);
508 if (pktrr
->rrtype
== kDNSType_PTR
)
509 if (SameDomainName(&entry
->revname
, pktrr
->name
))
511 entry
->NumQueries
= 0;
512 AssignDomainName(&entry
->hostname
, &pktrr
->rdata
->u
.name
);
515 else if (pktrr
->rrtype
== kDNSType_HINFO
)
517 RDataBody
*rd
= &pktrr
->rdata
->u
;
518 mDNSu8
*rdend
= (mDNSu8
*)rd
+ pktrr
->rdlength
;
519 mDNSu8
*hw
= rd
->txt
.c
;
520 mDNSu8
*sw
= hw
+ 1 + (mDNSu32
)hw
[0];
521 if (sw
+ 1 + sw
[0] <= rdend
)
523 AssignDomainName(&entry
->hostname
, pktrr
->name
);
524 mDNSPlatformMemCopy(hw
, entry
->HIHardware
.c
, 1 + (mDNSu32
)hw
[0]);
525 mDNSPlatformMemCopy(sw
, entry
->HISoftware
.c
, 1 + (mDNSu32
)sw
[0]);
530 mDNSlocal
void SendUnicastQuery(mDNS
*const m
, HostEntry
*entry
, domainname
*name
, mDNSu16 rrtype
, mDNSInterfaceID InterfaceID
)
532 const mDNSOpaque16 id
= { { 0xFF, 0xFF } };
534 mDNSu8
*qptr
= query
.data
;
535 const mDNSu8
*const limit
= query
.data
+ sizeof(query
.data
);
536 const mDNSAddr
*target
= &entry
->addr
;
537 InitializeDNSMessage(&query
.h
, id
, QueryFlags
);
538 qptr
= putQuestion(&query
, qptr
, limit
, name
, rrtype
, kDNSClass_IN
);
539 entry
->LastQuery
= m
->timenow
;
542 // Note: When there are multiple mDNSResponder agents running on a single machine
543 // (e.g. Apple mDNSResponder plus a SliMP3 server with embedded mDNSResponder)
544 // it is possible that unicast queries may not go to the primary system responder.
545 // We try the first query using unicast, but if that doesn't work we try again via multicast.
546 if (entry
->NumQueries
> 2)
548 target
= &AllDNSLinkGroup_v4
;
552 //mprintf("%#a Q\n", target);
553 InterfaceID
= mDNSInterface_Any
; // Send query from our unicast reply socket
554 m
->ExpectUnicastResponse
= m
->timenow
;
557 mDNSSendDNSMessage(&mDNSStorage
, &query
, qptr
, InterfaceID
, target
, MulticastDNSPort
, -1, mDNSNULL
);
560 mDNSlocal
void AnalyseHost(mDNS
*const m
, HostEntry
*entry
, const mDNSInterfaceID InterfaceID
)
562 // If we've done four queries without answer, give up
563 if (entry
->NumQueries
>= 4) return;
565 // If we've done a query in the last second, give the host a chance to reply before trying again
566 if (entry
->NumQueries
&& m
->timenow
- entry
->LastQuery
< mDNSPlatformOneSecond
) return;
568 // If we don't know the host name, try to find that first
569 if (!entry
->hostname
.c
[0])
571 if (entry
->revname
.c
[0])
573 SendUnicastQuery(m
, entry
, &entry
->revname
, kDNSType_PTR
, InterfaceID
);
574 //mprintf("%##s PTR %d\n", entry->revname.c, entry->NumQueries);
577 // If we have the host name but no HINFO, now ask for that
578 else if (!entry
->HIHardware
.c
[0])
580 SendUnicastQuery(m
, entry
, &entry
->hostname
, kDNSType_HINFO
, InterfaceID
);
581 //mprintf("%##s HINFO %d\n", entry->hostname.c, entry->NumQueries);
585 mDNSlocal
int CompareHosts(const void *p1
, const void *p2
)
587 return (int)(HostEntryTotalPackets((HostEntry
*)p2
) - HostEntryTotalPackets((HostEntry
*)p1
));
590 mDNSlocal
void ShowSortedHostList(HostList
*list
, int max
)
592 HostEntry
*e
, *end
= &list
->hosts
[(max
< list
->num
) ? max
: list
->num
];
593 qsort(list
->hosts
, list
->num
, sizeof(HostEntry
), CompareHosts
);
594 if (list
->num
) mprintf("\n%-25s%s%s\n", "Source Address", OPBanner
, " Pkts Query LegacyQ Response");
595 for (e
= &list
->hosts
[0]; e
< end
; e
++)
597 int len
= mprintf("%#-25a", &e
->addr
);
598 if (len
> 25) mprintf("\n%25s", "");
599 mprintf("%8lu %8lu %8lu %8lu %8lu %8lu %8lu", e
->totalops
,
600 e
->stat
[OP_probe
], e
->stat
[OP_goodbye
],
601 e
->stat
[OP_browseq
], e
->stat
[OP_browsea
],
602 e
->stat
[OP_resolveq
], e
->stat
[OP_resolvea
]);
603 mprintf(" %8lu %8lu %8lu %8lu",
604 HostEntryTotalPackets(e
), e
->pkts
[HostPkt_Q
], e
->pkts
[HostPkt_L
], e
->pkts
[HostPkt_R
]);
605 if (e
->pkts
[HostPkt_B
]) mprintf("Bad: %8lu", e
->pkts
[HostPkt_B
]);
607 if (!e
->HISoftware
.c
[0] && e
->NumQueries
> 2)
608 mDNSPlatformMemCopy("\x27*** Unknown (Jaguar, Windows, etc.) ***", &e
->HISoftware
, 0x28);
609 if (e
->hostname
.c
[0] || e
->HIHardware
.c
[0] || e
->HISoftware
.c
[0])
610 mprintf("%##-45s %#-14s %#s\n", e
->hostname
.c
, e
->HIHardware
.c
, e
->HISoftware
.c
);
614 //*************************************************************************************************************
615 // Receive and process packets
617 mDNSexport mDNSBool
ExtractServiceType(const domainname
*const fqdn
, domainname
*const srvtype
)
620 const mDNSu8
*src
= fqdn
->c
;
621 mDNSu8
*dst
= srvtype
->c
;
624 if (len
== 0 || len
>= 0x40) return(mDNSfalse
);
625 if (src
[1] != '_') src
+= 1 + len
;
628 if (len
== 0 || len
>= 0x40 || src
[1] != '_') return(mDNSfalse
);
629 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
632 if (len
== 0 || len
>= 0x40 || src
[1] != '_') return(mDNSfalse
);
633 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
635 *dst
++ = 0; // Put the null root label on the end of the service type
640 mDNSlocal
void recordstat(HostEntry
*entry
, domainname
*fqdn
, int op
, mDNSu16 rrtype
)
642 ActivityStat
**s
= &stats
;
647 if (rrtype
== kDNSType_SRV
|| rrtype
== kDNSType_TXT
) op
= op
- OP_browsegroup
+ OP_resolvegroup
;
648 else if (rrtype
!= kDNSType_PTR
) return;
651 if (!ExtractServiceType(fqdn
, &srvtype
)) return;
653 while (*s
&& !SameDomainName(&(*s
)->srvtype
, &srvtype
)) s
= &(*s
)->next
;
657 *s
= malloc(sizeof(ActivityStat
));
660 (*s
)->srvtype
= srvtype
;
663 for (i
=0; i
<OP_NumTypes
; i
++) (*s
)->stat
[i
] = 0;
675 mDNSlocal
void printstats(int max
)
679 for (i
=0; i
<max
; i
++)
682 ActivityStat
*s
, *m
= NULL
;
683 for (s
= stats
; s
; s
=s
->next
)
684 if (!s
->printed
&& max
< s
->totalops
)
685 { m
= s
; max
= s
->totalops
; }
687 m
->printed
= mDNStrue
;
688 if (i
==0) mprintf("%-25s%s\n", "Service Type", OPBanner
);
689 mprintf("%##-25s%8d %8d %8d %8d %8d %8d %8d\n", m
->srvtype
.c
, m
->totalops
, m
->stat
[OP_probe
],
690 m
->stat
[OP_goodbye
], m
->stat
[OP_browseq
], m
->stat
[OP_browsea
], m
->stat
[OP_resolveq
], m
->stat
[OP_resolvea
]);
694 mDNSlocal
const mDNSu8
*FindUpdate(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*ptr
, const mDNSu8
*const end
,\
695 DNSQuestion
*q
, LargeCacheRecord
*pkt
)
698 for (i
= 0; i
< query
->h
.numAuthorities
; i
++)
700 const mDNSu8
*p2
= ptr
;
701 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, q
->InterfaceID
, kDNSRecordTypePacketAuth
, pkt
);
703 if (ResourceRecordAnswersQuestion(&pkt
->r
.resrec
, q
)) return(p2
);
708 mDNSlocal
void DisplayPacketHeader(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
, const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSInterfaceID InterfaceID
)
710 const char *const ptype
= (msg
->h
.flags
.b
[0] & kDNSFlag0_QR_Response
) ? "-R- " :
711 (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) ? "-Q- " : "-LQ-";
715 const mDNSu32 index
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
);
716 char if_name
[IF_NAMESIZE
];
717 if_indextoname(index
, if_name
);
718 gettimeofday(&tv
, NULL
);
719 localtime_r((time_t*)&tv
.tv_sec
, &tm
);
720 mprintf("\n%d:%02d:%02d.%06d Interface %d/%s\n", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, tv
.tv_usec
, index
, if_name
);
722 mprintf("%#-16a %s Q:%3d Ans:%3d Auth:%3d Add:%3d Size:%5d bytes",
723 srcaddr
, ptype
, msg
->h
.numQuestions
, msg
->h
.numAnswers
, msg
->h
.numAuthorities
, msg
->h
.numAdditionals
, end
- (mDNSu8
*)msg
);
725 if (msg
->h
.id
.NotAnInteger
) mprintf(" ID:%u", mDNSVal16(msg
->h
.id
));
727 if (!mDNSAddrIsDNSMulticast(dstaddr
)) mprintf(" To: %#a", dstaddr
);
729 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
)
731 if (msg
->h
.flags
.b
[0] & kDNSFlag0_QR_Response
) mprintf(" Truncated");
732 else mprintf(" Truncated (KA list continues in next packet)");
737 mDNSlocal
void DisplayResourceRecord(const mDNSAddr
*const srcaddr
, const char *const op
, const ResourceRecord
*const pktrr
)
739 static const char hexchars
[16] = "0123456789ABCDEF";
741 char buffer
[MaxWidth
+8];
744 RDataBody
*rd
= &pktrr
->rdata
->u
;
745 mDNSu8
*rdend
= (mDNSu8
*)rd
+ pktrr
->rdlength
;
746 int n
= mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr
, op
, DNSTypeName(pktrr
->rrtype
), pktrr
->rroriginalttl
, pktrr
->name
->c
);
748 switch(pktrr
->rrtype
)
750 case kDNSType_A
: n
+= mprintf("%.4a", &rd
->ipv4
); break;
751 case kDNSType_PTR
: n
+= mprintf("%##.*s", MaxWidth
- n
, rd
->name
.c
); break;
752 case kDNSType_HINFO
:// same as kDNSType_TXT below
754 mDNSu8
*t
= rd
->txt
.c
;
755 while (t
< rdend
&& t
[0] && p
< buffer
+MaxWidth
)
758 for (i
=1; i
<=t
[0] && p
< buffer
+MaxWidth
; i
++)
760 if (t
[i
] == '\\') *p
++ = '\\';
761 if (t
[i
] >= ' ') *p
++ = t
[i
];
767 *p
++ = hexchars
[t
[i
] >> 4];
768 *p
++ = hexchars
[t
[i
] & 0xF];
772 if (t
< rdend
&& t
[0]) { *p
++ = '\\'; *p
++ = ' '; }
775 n
+= mprintf("%.*s", MaxWidth
- n
, buffer
);
777 case kDNSType_AAAA
: n
+= mprintf("%.16a", &rd
->ipv6
); break;
778 case kDNSType_SRV
: n
+= mprintf("%##s:%d", rd
->srv
.target
.c
, mDNSVal16(rd
->srv
.port
)); break;
780 mDNSu8
*s
= rd
->data
;
781 while (s
< rdend
&& p
< buffer
+MaxWidth
)
783 if (*s
== '\\') *p
++ = '\\';
784 if (*s
>= ' ') *p
++ = *s
;
790 *p
++ = hexchars
[*s
>> 4];
791 *p
++ = hexchars
[*s
& 0xF];
796 n
+= mprintf("%.*s", MaxWidth
- n
, buffer
);
803 mDNSlocal
void HexDump(const mDNSu8
*ptr
, const mDNSu8
*const end
)
809 if (&ptr
[i
] < end
) mprintf("%02X ", ptr
[i
]);
812 if (&ptr
[i
] < end
) mprintf("%c", ptr
[i
] <= ' ' || ptr
[i
] >= 126 ? '.' : ptr
[i
]);
818 mDNSlocal
void DisplayError(const mDNSAddr
*srcaddr
, const mDNSu8
*ptr
, const mDNSu8
*const end
, char *msg
)
820 mprintf("%#-16a **** ERROR: FAILED TO READ %s **** \n", srcaddr
, msg
);
824 mDNSlocal
void DisplayQuery(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
825 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSInterfaceID InterfaceID
)
828 const mDNSu8
*ptr
= msg
->data
;
829 const mDNSu8
*auth
= LocateAuthorities(msg
, end
);
830 mDNSBool MQ
= (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
831 HostEntry
*entry
= GotPacketFromHost(srcaddr
, MQ
? HostPkt_Q
: HostPkt_L
, msg
->h
.id
);
832 LargeCacheRecord pkt
;
834 DisplayPacketHeader(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
835 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF)
837 if (MQ
) NumPktQ
++; else NumPktL
++;
840 for (i
=0; i
<msg
->h
.numQuestions
; i
++)
843 mDNSu8
*p2
= (mDNSu8
*)getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
844 mDNSu16 ucbit
= q
.qclass
& kDNSQClass_UnicastResponse
;
845 q
.qclass
&= ~kDNSQClass_UnicastResponse
;
846 if (!p2
) { DisplayError(srcaddr
, ptr
, end
, "QUESTION"); return; }
848 p2
= (mDNSu8
*)FindUpdate(m
, msg
, auth
, end
, &q
, &pkt
);
852 DisplayResourceRecord(srcaddr
, ucbit
? "(PU)" : "(PM)", &pkt
.r
.resrec
);
853 recordstat(entry
, &q
.qname
, OP_probe
, q
.qtype
);
854 p2
= (mDNSu8
*)skipDomainName(msg
, p2
, end
);
855 // Having displayed this update record, clear type and class so we don't display the same one again.
856 p2
[0] = p2
[1] = p2
[2] = p2
[3] = 0;
860 const char *ptype
= ucbit
? "(QU)" : "(QM)";
861 if (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) NumQuestions
++;
862 else { NumLegacy
++; ptype
= "(LQ)"; }
863 mprintf("%#-16a %-5s %-5s %##s\n", srcaddr
, ptype
, DNSTypeName(q
.qtype
), q
.qname
.c
);
864 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) recordstat(entry
, &q
.qname
, OP_query
, q
.qtype
);
868 for (i
=0; i
<msg
->h
.numAnswers
; i
++)
870 const mDNSu8
*ep
= ptr
;
871 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
872 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "KNOWN ANSWER"); return; }
873 DisplayResourceRecord(srcaddr
, "(KA)", &pkt
.r
.resrec
);
875 // In the case of queries with long multi-packet KA lists, we count each subsequent KA packet
876 // the same as a single query, to more accurately reflect the burden on the network
877 // (A query with a six-packet KA list is *at least* six times the burden on the network as a single-packet query.)
878 if (msg
->h
.numQuestions
== 0 && i
== 0)
879 recordstat(entry
, pkt
.r
.resrec
.name
, OP_query
, pkt
.r
.resrec
.rrtype
);
882 for (i
=0; i
<msg
->h
.numAuthorities
; i
++)
884 const mDNSu8
*ep
= ptr
;
885 ptr
= skipResourceRecord(msg
, ptr
, end
);
886 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "AUTHORITY"); return; }
889 if (entry
) AnalyseHost(m
, entry
, InterfaceID
);
892 mDNSlocal
void DisplayResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
,
893 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSInterfaceID InterfaceID
)
896 const mDNSu8
*ptr
= msg
->data
;
897 HostEntry
*entry
= GotPacketFromHost(srcaddr
, HostPkt_R
, msg
->h
.id
);
898 LargeCacheRecord pkt
;
900 DisplayPacketHeader(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
901 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) NumPktR
++;
903 for (i
=0; i
<msg
->h
.numQuestions
; i
++)
906 const mDNSu8
*ep
= ptr
;
907 ptr
= getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
908 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "QUESTION"); return; }
909 if (mDNSAddrIsDNSMulticast(dstaddr
))
910 mprintf("%#-16a (?) **** ERROR: SHOULD NOT HAVE Q IN mDNS RESPONSE **** %-5s %##s\n", srcaddr
, DNSTypeName(q
.qtype
), q
.qname
.c
);
912 mprintf("%#-16a (Q) %-5s %##s\n", srcaddr
, DNSTypeName(q
.qtype
), q
.qname
.c
);
915 for (i
=0; i
<msg
->h
.numAnswers
; i
++)
917 const mDNSu8
*ep
= ptr
;
918 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
919 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "ANSWER"); return; }
920 if (pkt
.r
.resrec
.rroriginalttl
)
923 DisplayResourceRecord(srcaddr
, (pkt
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "(AN)" : "(AN+)", &pkt
.r
.resrec
);
924 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) recordstat(entry
, pkt
.r
.resrec
.name
, OP_answer
, pkt
.r
.resrec
.rrtype
);
925 if (entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
930 DisplayResourceRecord(srcaddr
, "(DE)", &pkt
.r
.resrec
);
931 recordstat(entry
, pkt
.r
.resrec
.name
, OP_goodbye
, pkt
.r
.resrec
.rrtype
);
935 for (i
=0; i
<msg
->h
.numAuthorities
; i
++)
937 const mDNSu8
*ep
= ptr
;
938 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &pkt
);
939 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "AUTHORITY"); return; }
940 mprintf("%#-16a (?) **** ERROR: SHOULD NOT HAVE AUTHORITY IN mDNS RESPONSE **** %-5s %##s\n",
941 srcaddr
, DNSTypeName(pkt
.r
.resrec
.rrtype
), pkt
.r
.resrec
.name
->c
);
944 for (i
=0; i
<msg
->h
.numAdditionals
; i
++)
946 const mDNSu8
*ep
= ptr
;
947 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAdd
, &pkt
);
948 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "ADDITIONAL"); return; }
950 DisplayResourceRecord(srcaddr
, (pkt
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "(AD)" : "(AD+)", &pkt
.r
.resrec
);
951 if (entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
954 if (entry
) AnalyseHost(m
, entry
, InterfaceID
);
957 mDNSlocal
void ProcessUnicastResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, const mDNSInterfaceID InterfaceID
)
960 const mDNSu8
*ptr
= LocateAnswers(msg
, end
);
961 HostEntry
*entry
= GotPacketFromHost(srcaddr
, HostPkt_R
, msg
->h
.id
);
962 //mprintf("%#a R\n", srcaddr);
964 for (i
=0; i
<msg
->h
.numAnswers
+ msg
->h
.numAuthorities
+ msg
->h
.numAdditionals
; i
++)
966 LargeCacheRecord pkt
;
967 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
968 if (pkt
.r
.resrec
.rroriginalttl
&& entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
972 mDNSlocal mDNSBool
AddressMatchesFilterList(const mDNSAddr
*srcaddr
)
975 if (!Filters
) return(srcaddr
->type
== mDNSAddrType_IPv4
);
976 for (f
=Filters
; f
; f
=f
->next
) if (mDNSSameAddress(srcaddr
, &f
->FilterAddr
)) return(mDNStrue
);
980 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
981 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
)
983 const mDNSu8 StdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
;
984 const mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
985 const mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
986 mDNSu8
*ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
988 (void)dstaddr
; // Unused
989 (void)dstport
; // Unused
991 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
992 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
993 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
994 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
995 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
997 // For now we're only interested in monitoring IPv4 traffic.
998 // All IPv6 packets should just be duplicates of the v4 packets.
999 if (AddressMatchesFilterList(srcaddr
))
1002 if (!mDNSAddrIsDNSMulticast(dstaddr
))
1004 if (QR_OP
== StdQ
) mprintf("Unicast query from %#a\n", srcaddr
);
1005 else if (QR_OP
== StdR
) ProcessUnicastResponse(m
, msg
, end
, srcaddr
, InterfaceID
);
1009 if (QR_OP
== StdQ
) DisplayQuery (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
1010 else if (QR_OP
== StdR
) DisplayResponse (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
1013 debugf("Unknown DNS packet type %02X%02X (ignored)", msg
->h
.flags
.b
[0], msg
->h
.flags
.b
[1]);
1014 GotPacketFromHost(srcaddr
, HostPkt_B
, msg
->h
.id
);
1022 mDNSlocal mStatus
mDNSNetMonitor(void)
1025 int h
, m
, s
, mul
, div
, TotPkt
;
1028 mStatus status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
1029 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
1030 mDNS_Init_DontAdvertiseLocalAddresses
,
1031 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
1032 if (status
) return(status
);
1034 gettimeofday(&tv_start
, NULL
);
1035 mDNSPosixListenForSignalInEventLoop(SIGINT
);
1036 mDNSPosixListenForSignalInEventLoop(SIGTERM
);
1040 struct timeval timeout
= { 0x3FFFFFFF, 0 }; // wait until SIGINT or SIGTERM
1041 mDNSBool gotSomething
;
1042 mDNSPosixRunEventLoopOnce(&mDNSStorage
, &timeout
, &signals
, &gotSomething
);
1044 while ( !( sigismember( &signals
, SIGINT
) || sigismember( &signals
, SIGTERM
)));
1046 // Now display final summary
1047 TotPkt
= NumPktQ
+ NumPktL
+ NumPktR
;
1048 gettimeofday(&tv_end
, NULL
);
1049 tv_interval
= tv_end
;
1050 if (tv_start
.tv_usec
> tv_interval
.tv_usec
)
1051 { tv_interval
.tv_usec
+= 1000000; tv_interval
.tv_sec
--; }
1052 tv_interval
.tv_sec
-= tv_start
.tv_sec
;
1053 tv_interval
.tv_usec
-= tv_start
.tv_usec
;
1054 h
= (tv_interval
.tv_sec
/ 3600);
1055 m
= (tv_interval
.tv_sec
% 3600) / 60;
1056 s
= (tv_interval
.tv_sec
% 60);
1057 if (tv_interval
.tv_sec
> 10)
1060 div
= tv_interval
.tv_sec
;
1065 div
= tv_interval
.tv_sec
* 1000 + tv_interval
.tv_usec
/ 1000;
1066 if (div
== 0) div
=1;
1070 localtime_r((time_t*)&tv_start
.tv_sec
, &tm
);
1071 mprintf("Started %3d:%02d:%02d.%06d\n", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, tv_start
.tv_usec
);
1072 localtime_r((time_t*)&tv_end
.tv_sec
, &tm
);
1073 mprintf("End %3d:%02d:%02d.%06d\n", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, tv_end
.tv_usec
);
1074 mprintf("Captured for %3d:%02d:%02d.%06d\n", h
, m
, s
, tv_interval
.tv_usec
);
1075 if (!Filters
) mprintf("Unique source addresses seen on network: %ld\n", IPv4HostList
.num
+ IPv6HostList
.num
);
1077 mprintf("Modern Query Packets: %7d (avg%5d/min)\n", NumPktQ
, NumPktQ
* mul
/ div
);
1078 mprintf("Legacy Query Packets: %7d (avg%5d/min)\n", NumPktL
, NumPktL
* mul
/ div
);
1079 mprintf("Multicast Response Packets: %7d (avg%5d/min)\n", NumPktR
, NumPktR
* mul
/ div
);
1080 mprintf("Total Multicast Packets: %7d (avg%5d/min)\n", TotPkt
, TotPkt
* mul
/ div
);
1082 mprintf("Total New Service Probes: %7d (avg%5d/min)\n", NumProbes
, NumProbes
* mul
/ div
);
1083 mprintf("Total Goodbye Announcements: %7d (avg%5d/min)\n", NumGoodbyes
, NumGoodbyes
* mul
/ div
);
1084 mprintf("Total Query Questions: %7d (avg%5d/min)\n", NumQuestions
, NumQuestions
* mul
/ div
);
1085 mprintf("Total Queries from Legacy Clients:%7d (avg%5d/min)\n", NumLegacy
, NumLegacy
* mul
/ div
);
1086 mprintf("Total Answers/Announcements: %7d (avg%5d/min)\n", NumAnswers
, NumAnswers
* mul
/ div
);
1087 mprintf("Total Additional Records: %7d (avg%5d/min)\n", NumAdditionals
, NumAdditionals
* mul
/ div
);
1089 printstats(kReportTopServices
);
1091 if (!ExactlyOneFilter
)
1093 ShowSortedHostList(&IPv4HostList
, kReportTopHosts
);
1094 ShowSortedHostList(&IPv6HostList
, kReportTopHosts
);
1097 mDNS_Close(&mDNSStorage
);
1101 mDNSexport
int main(int argc
, char **argv
)
1103 const char *progname
= strrchr(argv
[0], '/') ? strrchr(argv
[0], '/') + 1 : argv
[0];
1107 setlinebuf(stdout
); // Want to see lines as they appear, not block buffered
1109 for (i
=1; i
<argc
; i
++)
1115 a
.type
= mDNSAddrType_IPv4
;
1117 if (inet_pton(AF_INET
, argv
[i
], &s4
) == 1)
1118 a
.ip
.v4
.NotAnInteger
= s4
.s_addr
;
1119 else if (inet_pton(AF_INET6
, argv
[i
], &s6
) == 1)
1121 a
.type
= mDNSAddrType_IPv6
;
1122 bcopy(&s6
, &a
.ip
.v6
, sizeof(a
.ip
.v6
));
1126 struct hostent
*h
= gethostbyname(argv
[i
]);
1127 if (h
) a
.ip
.v4
.NotAnInteger
= *(long*)h
->h_addr
;
1131 f
= malloc(sizeof(*f
));
1137 status
= mDNSNetMonitor();
1138 if (status
) { fprintf(stderr
, "%s: mDNSNetMonitor failed %ld\n", progname
, status
); return(status
); }
1142 fprintf(stderr
, "\nmDNS traffic monitor\n");
1143 fprintf(stderr
, "Usage: %s (<host>)\n", progname
);
1144 fprintf(stderr
, "Optional <host> parameter displays only packets from that host\n");
1146 fprintf(stderr
, "\nPer-packet header output:\n");
1147 fprintf(stderr
, "-Q- Multicast Query from mDNS client that accepts multicast responses\n");
1148 fprintf(stderr
, "-R- Multicast Response packet containing answers/announcements\n");
1149 fprintf(stderr
, "-LQ- Multicast Query from legacy client that does *not* listen for multicast responses\n");
1150 fprintf(stderr
, "Q/Ans/Auth/Add Number of questions, answers, authority records and additional records in packet\n");
1152 fprintf(stderr
, "\nPer-record display:\n");
1153 fprintf(stderr
, "(PM) Probe Question (new service starting), requesting multicast response\n");
1154 fprintf(stderr
, "(PU) Probe Question (new service starting), requesting unicast response\n");
1155 fprintf(stderr
, "(DE) Deletion/Goodbye (service going away)\n");
1156 fprintf(stderr
, "(LQ) Legacy Query Question\n");
1157 fprintf(stderr
, "(QM) Query Question, requesting multicast response\n");
1158 fprintf(stderr
, "(QU) Query Question, requesting unicast response\n");
1159 fprintf(stderr
, "(KA) Known Answer (information querier already knows)\n");
1160 fprintf(stderr
, "(AN) Unique Answer to question (or periodic announcment) (entire RR Set)\n");
1161 fprintf(stderr
, "(AN+) Answer to question (or periodic announcment) (add to existing RR Set members)\n");
1162 fprintf(stderr
, "(AD) Unique Additional Record Set (entire RR Set)\n");
1163 fprintf(stderr
, "(AD+) Additional records (add to existing RR Set members)\n");
1165 fprintf(stderr
, "\nFinal summary, sorted by service type:\n");
1166 fprintf(stderr
, "Probe Probes for this service type starting up\n");
1167 fprintf(stderr
, "Goodbye Goodbye (deletion) packets for this service type shutting down\n");
1168 fprintf(stderr
, "BrowseQ Browse questions from clients browsing to find a list of instances of this service\n");
1169 fprintf(stderr
, "BrowseA Browse answers/announcments advertising instances of this service\n");
1170 fprintf(stderr
, "ResolveQ Resolve questions from clients actively connecting to an instance of this service\n");
1171 fprintf(stderr
, "ResolveA Resolve answers/announcments giving connection information for an instance of this service\n");
1172 fprintf(stderr
, "\n");