1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
19 * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
20 * but for the sake of brevity here I will say just this: Curly braces are not syntactially
21 * part of an "if" statement; they are the beginning and ending markers of a compound statement;
22 * therefore common sense dictates that if they are part of a compound statement then they
23 * should be indented to the same level as everything else in that compound statement.
24 * Indenting curly braces at the same level as the "if" implies that curly braces are
25 * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
26 * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
27 * understand why variable y is not of type "char*" just proves the point that poor code
28 * layout leads people to unfortunate misunderstandings about how the C language really works.)
30 Change History (most recent first):
32 $Log: NetMonitor.c,v $
33 Revision 1.82 2006/08/14 23:24:46 cheshire
34 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
36 Revision 1.81 2006/07/06 00:01:44 cheshire
37 <rdar://problem/4472014> Add Private DNS client functionality to mDNSResponder
38 Update mDNSSendDNSMessage() to use uDNS_TCPSocket type instead of "int"
40 Revision 1.80 2006/06/12 18:22:42 cheshire
41 <rdar://problem/4580067> mDNSResponder building warnings under Red Hat 64-bit (LP64) Linux
43 Revision 1.79 2006/04/26 20:48:33 cheshire
44 Make final count of unique source addresses show IPv4 and IPv6 counts separately
46 Revision 1.78 2006/04/25 00:42:24 cheshire
47 Add ability to specify a single interface index to capture on,
48 e.g. typically "-i 4" for Ethernet and "-i 5" for AirPort
50 Revision 1.77 2006/03/02 21:50:45 cheshire
51 Removed strange backslash at the end of a line
53 Revision 1.76 2006/02/23 23:38:43 cheshire
54 <rdar://problem/4427969> On FreeBSD 4 "arpa/inet.h" requires "netinet/in.h" be included first
56 Revision 1.75 2006/01/05 22:33:58 cheshire
57 Use IFNAMSIZ (more portable) instead of IF_NAMESIZE
59 Revision 1.74 2005/12/02 20:08:39 cheshire
60 Update "No HINFO" message
62 Revision 1.73 2005/12/02 19:19:53 cheshire
63 <rdar://problem/4331590> Include interface index and name in mDNSNetMonitor output
65 Revision 1.72 2005/11/07 01:47:45 cheshire
66 <rdar://problem/4331590> Include interface index in mDNSNetMonitor output
68 Revision 1.71 2004/12/16 20:17:11 cheshire
69 <rdar://problem/3324626> Cache memory management improvements
71 Revision 1.70 2004/12/04 02:13:20 cheshire
72 Pass proper record type in GetLargeResourceRecord() calls
74 Revision 1.69 2004/11/30 22:37:01 cheshire
75 Update copyright dates and add "Mode: C; tab-width: 4" headers
77 Revision 1.68 2004/10/23 01:16:01 cheshire
78 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
80 Revision 1.67 2004/10/16 00:17:00 cheshire
81 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
83 Revision 1.66 2004/09/17 00:31:52 cheshire
84 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
86 Revision 1.65 2004/09/16 01:58:22 cheshire
89 Revision 1.64 2004/06/15 02:39:47 cheshire
90 When displaying error message, only show command name, not entire path
92 Revision 1.63 2004/05/18 23:51:26 cheshire
93 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
95 Revision 1.62 2004/03/16 18:24:25 cheshire
96 If packet destination was not multicast, then display it
98 Revision 1.61 2004/02/20 09:36:46 cheshire
99 Also show TTL in packet header, if it's not 255
101 Revision 1.60 2004/02/07 02:11:35 cheshire
102 Make mDNSNetMonitor smarter about sending targeted unicast HINFO queries
104 Revision 1.59 2004/02/03 21:42:55 cheshire
105 Add constants kReportTopServices and kReportTopHosts
107 Revision 1.58 2004/01/27 20:15:23 cheshire
108 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
110 Revision 1.57 2004/01/24 23:59:42 cheshire
111 Change to use mDNSVal16() instead of shifting and ORing
113 Revision 1.56 2004/01/24 05:25:34 cheshire
114 mDNSNetMonitor now uses the new ability to send unicast queries so that
115 it causes less perturbation of the network traffic it's monitoring.
117 Revision 1.55 2003/12/23 00:21:31 cheshire
118 Send HINFO queries to determine the mDNSResponder version of each host
120 Revision 1.54 2003/12/17 01:06:39 cheshire
121 Also show host name along with HINFO data
123 Revision 1.53 2003/12/17 00:51:22 cheshire
124 Changed mDNSNetMonitor and mDNSIdentify to link the object files
125 instead of #including the "DNSCommon.c" "uDNS.c" and source files
127 Revision 1.52 2003/12/17 00:21:51 cheshire
128 If we received one, display host's HINFO record in final summary
130 Revision 1.51 2003/12/13 03:05:28 ksekar
131 <rdar://problem/3192548>: DynDNS: Unicast query of service records
133 Revision 1.50 2003/12/08 20:47:02 rpantos
134 Add support for mDNSResponder on Linux.
136 Revision 1.49 2003/10/30 19:38:56 cheshire
137 Fix warning on certain compilers
139 Revision 1.48 2003/10/30 19:30:00 cheshire
140 Fix warnings on certain compilers
142 Revision 1.47 2003/09/05 18:49:57 cheshire
143 Add total packet size to display
145 Revision 1.46 2003/09/05 02:33:48 cheshire
146 Set output to be line buffered, so you can redirect to a file and "tail -f" the file in another window
148 Revision 1.45 2003/09/04 00:16:20 cheshire
149 Only show count of unique source addresses seen on network if we're not filtering
151 Revision 1.44 2003/09/02 22:13:28 cheshire
152 Show total host count in final summary table
154 Revision 1.43 2003/09/02 21:42:52 cheshire
155 Improved alignment of final summary table with v6 addresses
157 Revision 1.42 2003/09/02 20:59:24 cheshire
158 Use bcopy() instead of non-portable "__u6_addr.__u6_addr32" fields.
160 Revision 1.41 2003/08/29 22:05:44 cheshire
161 Also count subsequent KA packets for the purposes of statistics counting
163 Revision 1.40 2003/08/29 16:43:24 cheshire
164 Also display breakdown of Probe/Goodbye/BrowseQ etc. for each host
166 Revision 1.39 2003/08/28 02:07:48 vlubet
167 Added "per hosts" statistics
169 Revision 1.38 2003/08/20 22:41:42 cheshire
170 Also display total multicast packet count
172 Revision 1.37 2003/08/20 22:32:08 cheshire
173 Error in DisplayQuery: Authorities come *after* Answers, not before
175 Revision 1.36 2003/08/18 23:20:10 cheshire
176 RDLength moved from the RData to the ResourceRecord object.
178 Revision 1.35 2003/08/15 20:17:28 cheshire
179 "LargeResourceRecord" changed to "LargeCacheRecord"
181 Revision 1.34 2003/08/14 02:19:55 cheshire
182 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
184 Revision 1.33 2003/08/12 19:56:26 cheshire
187 Revision 1.32 2003/08/06 18:57:01 cheshire
190 Revision 1.31 2003/08/06 02:05:12 cheshire
191 Add ability to give a list of hosts to monitor
193 Revision 1.30 2003/08/05 23:56:26 cheshire
194 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
195 (Right now mDNSPosix.c just reports 255 -- we should fix this)
197 Revision 1.29 2003/08/05 00:43:12 cheshire
198 Report errors encountered while processing authority section
200 Revision 1.28 2003/07/29 22:51:08 cheshire
201 Added hexdump for packets we can't decode, so we can find out *why* we couldn't decode them
203 Revision 1.27 2003/07/29 22:48:04 cheshire
204 Completed support for decoding packets containing oversized resource records
206 Revision 1.26 2003/07/19 03:25:23 cheshire
207 Change to make use of new GetLargeResourceRecord() call, for handling larger records
209 Revision 1.25 2003/07/18 00:13:23 cheshire
210 Remove erroneous trailing '\' from TXT record display
212 Revision 1.24 2003/07/17 17:10:51 cheshire
213 <rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
214 Further work: distinguish between PM and PU
216 Revision 1.23 2003/07/16 22:20:23 cheshire
217 <rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
218 Made mDNSNetMonitor distinguish between QM and QU in its logging output
220 Revision 1.22 2003/07/02 21:19:58 cheshire
221 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
223 Revision 1.21 2003/06/18 05:48:41 cheshire
226 Revision 1.20 2003/06/06 22:18:22 cheshire
227 Add extra space in Q output to line it up with RR output
229 Revision 1.19 2003/06/06 21:05:04 cheshire
230 Display state of cache-flush bit on additional records
232 Revision 1.18 2003/06/06 20:01:30 cheshire
233 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
234 (Global search-and-replace; no functional change to code execution.)
236 Revision 1.17 2003/06/06 14:26:50 cheshire
237 Explicitly #include <time.h> for the benefit of certain Linux distributions
239 Revision 1.16 2003/05/29 21:56:36 cheshire
241 Distinguish modern multicast queries from legacy multicast queries
242 In addition to record counts, display packet counts of queries, legacy queries, and responses
243 Include TTL in RR display
245 Revision 1.15 2003/05/29 20:03:57 cheshire
246 Various improvements:
247 Display start and end time, average rates in packets-per-minute,
248 show legacy queries as -LQ-, improve display of TXT and unknown records
250 Revision 1.14 2003/05/26 04:45:42 cheshire
251 Limit line length when printing super-long TXT records
253 Revision 1.13 2003/05/26 03:21:29 cheshire
254 Tidy up address structure naming:
255 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
256 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
257 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
259 Revision 1.12 2003/05/26 03:01:28 cheshire
260 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
262 Revision 1.11 2003/05/26 00:48:13 cheshire
263 If mDNS packet contains a non-zero message ID, then display it.
265 Revision 1.10 2003/05/22 01:10:32 cheshire
266 Indicate when the TC bit is set on a query packet
268 Revision 1.9 2003/05/21 03:56:00 cheshire
269 Improve display of Probe queries
271 Revision 1.8 2003/05/09 21:41:56 cheshire
272 Track deletion/goodbye packets as separate category
274 Revision 1.7 2003/05/07 00:16:01 cheshire
275 More detailed decoding of Resource Records
277 Revision 1.6 2003/05/05 21:16:16 cheshire
278 <rdar://problem/3241281> Change timenow from a local variable to a structure member
280 Revision 1.5 2003/04/19 01:16:22 cheshire
281 Add filter option, to monitor only packets from a single specified source address
283 Revision 1.4 2003/04/18 00:45:21 cheshire
284 Distinguish announcements (AN) from deletions (DE)
286 Revision 1.3 2003/04/15 18:26:01 cheshire
287 Added timestamps and help information
289 Revision 1.2 2003/04/04 20:42:02 cheshire
290 Fix broken statistics counting
292 Revision 1.1 2003/04/04 01:37:14 cheshire
297 //*************************************************************************************************************
298 // Incorporate mDNS.c functionality
300 // We want to use much of the functionality provided by "mDNS.c",
301 // except we'll steal the packets that would be sent to normal mDNSCoreReceive() routine
302 #define mDNSCoreReceive __NOT__mDNSCoreReceive__NOT__
304 #undef mDNSCoreReceive
306 //*************************************************************************************************************
309 #include <stdio.h> // For printf()
310 #include <stdlib.h> // For malloc()
311 #include <string.h> // For bcopy()
312 #include <time.h> // For "struct tm" etc.
313 #include <signal.h> // For SIGINT, SIGTERM
314 #include <netdb.h> // For gethostbyname()
315 #include <sys/socket.h> // For AF_INET, AF_INET6, etc.
316 #include <net/if.h> // For IF_NAMESIZE
317 #include <netinet/in.h> // For INADDR_NONE
318 #include <arpa/inet.h> // For inet_addr()
320 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
321 #include "ExampleClientApp.h"
323 //*************************************************************************************************************
324 // Types and structures
328 // Primitive operations
332 // These are meta-categories;
333 // Query and Answer operations are actually subdivided into two classes:
334 // Browse query/answer and
335 // Resolve query/answer
339 // The "Browse" variants of query/answer
344 // The "Resolve" variants of query/answer
352 typedef struct ActivityStat_struct ActivityStat
;
353 struct ActivityStat_struct
359 int stat
[OP_NumTypes
];
362 typedef struct FilterList_struct FilterList
;
363 struct FilterList_struct
369 //*************************************************************************************************************
372 #define kReportTopServices 15
373 #define kReportTopHosts 15
375 //*************************************************************************************************************
378 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
379 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
381 struct timeval tv_start
, tv_end
, tv_interval
;
382 static int FilterInterface
= 0;
383 static FilterList
*Filters
;
384 #define ExactlyOneFilter (Filters && !Filters->next)
386 static int NumPktQ
, NumPktL
, NumPktR
, NumPktB
; // Query/Legacy/Response/Bad
387 static int NumProbes
, NumGoodbyes
, NumQuestions
, NumLegacy
, NumAnswers
, NumAdditionals
;
389 static ActivityStat
*stats
;
391 #define OPBanner "Total Ops Probe Goodbye BrowseQ BrowseA ResolveQ ResolveA"
393 //*************************************************************************************************************
396 // Special version of printf that knows how to print IP addresses, DNS-format name strings, etc.
397 mDNSlocal mDNSu32
mprintf(const char *format
, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
398 mDNSlocal mDNSu32
mprintf(const char *format
, ...)
401 unsigned char buffer
[512];
403 va_start(ptr
,format
);
404 length
= mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
);
406 printf("%s", buffer
);
410 //*************************************************************************************************************
413 // Would benefit from a hash
417 HostPkt_Q
= 0, // Query
418 HostPkt_L
= 1, // Legacy Query
419 HostPkt_R
= 2, // Response
420 HostPkt_B
= 3, // Bad
427 unsigned long pkts
[HostPkt_NumTypes
];
428 unsigned long totalops
;
429 unsigned long stat
[OP_NumTypes
];
432 UTF8str255 HIHardware
;
433 UTF8str255 HISoftware
;
438 #define HostEntryTotalPackets(H) ((H)->pkts[HostPkt_Q] + (H)->pkts[HostPkt_L] + (H)->pkts[HostPkt_R] + (H)->pkts[HostPkt_B])
447 static HostList IPv4HostList
= { 0, 0, 0 };
448 static HostList IPv6HostList
= { 0, 0, 0 };
450 mDNSlocal HostEntry
*FindHost(const mDNSAddr
*addr
, HostList
* list
)
454 for (i
= 0; i
< list
->num
; i
++)
456 HostEntry
*entry
= list
->hosts
+ i
;
457 if (mDNSSameAddress(addr
, &entry
->addr
))
464 mDNSlocal HostEntry
*AddHost(const mDNSAddr
*addr
, HostList
* list
)
468 if (list
->num
>= list
->max
)
470 long newMax
= list
->max
+ 64;
471 HostEntry
*newHosts
= realloc(list
->hosts
, newMax
* sizeof(HostEntry
));
472 if (newHosts
== NULL
)
475 list
->hosts
= newHosts
;
478 entry
= list
->hosts
+ list
->num
++;
481 for (i
=0; i
<HostPkt_NumTypes
; i
++) entry
->pkts
[i
] = 0;
483 for (i
=0; i
<OP_NumTypes
; i
++) entry
->stat
[i
] = 0;
484 entry
->hostname
.c
[0] = 0;
485 entry
->revname
.c
[0] = 0;
486 entry
->HIHardware
.c
[0] = 0;
487 entry
->HISoftware
.c
[0] = 0;
488 entry
->NumQueries
= 0;
490 if (entry
->addr
.type
== mDNSAddrType_IPv4
)
492 mDNSv4Addr ip
= entry
->addr
.ip
.v4
;
494 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.", ip
.b
[3], ip
.b
[2], ip
.b
[1], ip
.b
[0]);
495 MakeDomainNameFromDNSNameString(&entry
->revname
, buffer
);
501 mDNSlocal HostEntry
*GotPacketFromHost(const mDNSAddr
*addr
, HostPkt_Type t
, mDNSOpaque16 id
)
503 if (ExactlyOneFilter
) return(NULL
);
506 HostList
*list
= (addr
->type
== mDNSAddrType_IPv4
) ? &IPv4HostList
: &IPv6HostList
;
507 HostEntry
*entry
= FindHost(addr
, list
);
508 if (!entry
) entry
= AddHost(addr
, list
);
509 if (!entry
) return(NULL
);
510 // Don't count our own interrogation packets
511 if (id
.NotAnInteger
!= 0xFFFF) entry
->pkts
[t
]++;
516 mDNSlocal
void RecordHostInfo(HostEntry
*entry
, const ResourceRecord
*const pktrr
)
518 if (!entry
->hostname
.c
[0])
520 if (pktrr
->rrtype
== kDNSType_A
|| pktrr
->rrtype
== kDNSType_AAAA
)
522 // Should really check that the rdata in the address record matches the source address of this packet
523 entry
->NumQueries
= 0;
524 AssignDomainName(&entry
->hostname
, pktrr
->name
);
527 if (pktrr
->rrtype
== kDNSType_PTR
)
528 if (SameDomainName(&entry
->revname
, pktrr
->name
))
530 entry
->NumQueries
= 0;
531 AssignDomainName(&entry
->hostname
, &pktrr
->rdata
->u
.name
);
534 else if (pktrr
->rrtype
== kDNSType_HINFO
)
536 RDataBody
*rd
= &pktrr
->rdata
->u
;
537 mDNSu8
*rdend
= (mDNSu8
*)rd
+ pktrr
->rdlength
;
538 mDNSu8
*hw
= rd
->txt
.c
;
539 mDNSu8
*sw
= hw
+ 1 + (mDNSu32
)hw
[0];
540 if (sw
+ 1 + sw
[0] <= rdend
)
542 AssignDomainName(&entry
->hostname
, pktrr
->name
);
543 mDNSPlatformMemCopy(hw
, entry
->HIHardware
.c
, 1 + (mDNSu32
)hw
[0]);
544 mDNSPlatformMemCopy(sw
, entry
->HISoftware
.c
, 1 + (mDNSu32
)sw
[0]);
549 mDNSlocal
void SendUnicastQuery(mDNS
*const m
, HostEntry
*entry
, domainname
*name
, mDNSu16 rrtype
, mDNSInterfaceID InterfaceID
)
551 const mDNSOpaque16 id
= { { 0xFF, 0xFF } };
553 mDNSu8
*qptr
= query
.data
;
554 const mDNSu8
*const limit
= query
.data
+ sizeof(query
.data
);
555 const mDNSAddr
*target
= &entry
->addr
;
556 InitializeDNSMessage(&query
.h
, id
, QueryFlags
);
557 qptr
= putQuestion(&query
, qptr
, limit
, name
, rrtype
, kDNSClass_IN
);
558 entry
->LastQuery
= m
->timenow
;
561 // Note: When there are multiple mDNSResponder agents running on a single machine
562 // (e.g. Apple mDNSResponder plus a SliMP3 server with embedded mDNSResponder)
563 // it is possible that unicast queries may not go to the primary system responder.
564 // We try the first query using unicast, but if that doesn't work we try again via multicast.
565 if (entry
->NumQueries
> 2)
567 target
= &AllDNSLinkGroup_v4
;
571 //mprintf("%#a Q\n", target);
572 InterfaceID
= mDNSInterface_Any
; // Send query from our unicast reply socket
573 m
->ExpectUnicastResponse
= m
->timenow
;
576 mDNSSendDNSMessage(&mDNSStorage
, &query
, qptr
, InterfaceID
, target
, MulticastDNSPort
, mDNSNULL
, mDNSNULL
);
579 mDNSlocal
void AnalyseHost(mDNS
*const m
, HostEntry
*entry
, const mDNSInterfaceID InterfaceID
)
581 // If we've done four queries without answer, give up
582 if (entry
->NumQueries
>= 4) return;
584 // If we've done a query in the last second, give the host a chance to reply before trying again
585 if (entry
->NumQueries
&& m
->timenow
- entry
->LastQuery
< mDNSPlatformOneSecond
) return;
587 // If we don't know the host name, try to find that first
588 if (!entry
->hostname
.c
[0])
590 if (entry
->revname
.c
[0])
592 SendUnicastQuery(m
, entry
, &entry
->revname
, kDNSType_PTR
, InterfaceID
);
593 //mprintf("%##s PTR %d\n", entry->revname.c, entry->NumQueries);
596 // If we have the host name but no HINFO, now ask for that
597 else if (!entry
->HIHardware
.c
[0])
599 SendUnicastQuery(m
, entry
, &entry
->hostname
, kDNSType_HINFO
, InterfaceID
);
600 //mprintf("%##s HINFO %d\n", entry->hostname.c, entry->NumQueries);
604 mDNSlocal
int CompareHosts(const void *p1
, const void *p2
)
606 return (int)(HostEntryTotalPackets((HostEntry
*)p2
) - HostEntryTotalPackets((HostEntry
*)p1
));
609 mDNSlocal
void ShowSortedHostList(HostList
*list
, int max
)
611 HostEntry
*e
, *end
= &list
->hosts
[(max
< list
->num
) ? max
: list
->num
];
612 qsort(list
->hosts
, list
->num
, sizeof(HostEntry
), CompareHosts
);
613 if (list
->num
) mprintf("\n%-25s%s%s\n", "Source Address", OPBanner
, " Pkts Query LegacyQ Response");
614 for (e
= &list
->hosts
[0]; e
< end
; e
++)
616 int len
= mprintf("%#-25a", &e
->addr
);
617 if (len
> 25) mprintf("\n%25s", "");
618 mprintf("%8lu %8lu %8lu %8lu %8lu %8lu %8lu", e
->totalops
,
619 e
->stat
[OP_probe
], e
->stat
[OP_goodbye
],
620 e
->stat
[OP_browseq
], e
->stat
[OP_browsea
],
621 e
->stat
[OP_resolveq
], e
->stat
[OP_resolvea
]);
622 mprintf(" %8lu %8lu %8lu %8lu",
623 HostEntryTotalPackets(e
), e
->pkts
[HostPkt_Q
], e
->pkts
[HostPkt_L
], e
->pkts
[HostPkt_R
]);
624 if (e
->pkts
[HostPkt_B
]) mprintf("Bad: %8lu", e
->pkts
[HostPkt_B
]);
626 if (!e
->HISoftware
.c
[0] && e
->NumQueries
> 2)
627 mDNSPlatformMemCopy("\x27*** Unknown (Jaguar, Windows, etc.) ***", &e
->HISoftware
, 0x28);
628 if (e
->hostname
.c
[0] || e
->HIHardware
.c
[0] || e
->HISoftware
.c
[0])
629 mprintf("%##-45s %#-14s %#s\n", e
->hostname
.c
, e
->HIHardware
.c
, e
->HISoftware
.c
);
633 //*************************************************************************************************************
634 // Receive and process packets
636 mDNSexport mDNSBool
ExtractServiceType(const domainname
*const fqdn
, domainname
*const srvtype
)
639 const mDNSu8
*src
= fqdn
->c
;
640 mDNSu8
*dst
= srvtype
->c
;
643 if (len
== 0 || len
>= 0x40) return(mDNSfalse
);
644 if (src
[1] != '_') src
+= 1 + len
;
647 if (len
== 0 || len
>= 0x40 || src
[1] != '_') return(mDNSfalse
);
648 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
651 if (len
== 0 || len
>= 0x40 || src
[1] != '_') return(mDNSfalse
);
652 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
654 *dst
++ = 0; // Put the null root label on the end of the service type
659 mDNSlocal
void recordstat(HostEntry
*entry
, domainname
*fqdn
, int op
, mDNSu16 rrtype
)
661 ActivityStat
**s
= &stats
;
666 if (rrtype
== kDNSType_SRV
|| rrtype
== kDNSType_TXT
) op
= op
- OP_browsegroup
+ OP_resolvegroup
;
667 else if (rrtype
!= kDNSType_PTR
) return;
670 if (!ExtractServiceType(fqdn
, &srvtype
)) return;
672 while (*s
&& !SameDomainName(&(*s
)->srvtype
, &srvtype
)) s
= &(*s
)->next
;
676 *s
= malloc(sizeof(ActivityStat
));
679 (*s
)->srvtype
= srvtype
;
682 for (i
=0; i
<OP_NumTypes
; i
++) (*s
)->stat
[i
] = 0;
694 mDNSlocal
void printstats(int max
)
698 for (i
=0; i
<max
; i
++)
701 ActivityStat
*s
, *m
= NULL
;
702 for (s
= stats
; s
; s
=s
->next
)
703 if (!s
->printed
&& max
< s
->totalops
)
704 { m
= s
; max
= s
->totalops
; }
706 m
->printed
= mDNStrue
;
707 if (i
==0) mprintf("%-25s%s\n", "Service Type", OPBanner
);
708 mprintf("%##-25s%8d %8d %8d %8d %8d %8d %8d\n", m
->srvtype
.c
, m
->totalops
, m
->stat
[OP_probe
],
709 m
->stat
[OP_goodbye
], m
->stat
[OP_browseq
], m
->stat
[OP_browsea
], m
->stat
[OP_resolveq
], m
->stat
[OP_resolvea
]);
713 mDNSlocal
const mDNSu8
*FindUpdate(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*ptr
, const mDNSu8
*const end
,
714 DNSQuestion
*q
, LargeCacheRecord
*pkt
)
717 for (i
= 0; i
< query
->h
.numAuthorities
; i
++)
719 const mDNSu8
*p2
= ptr
;
720 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, q
->InterfaceID
, kDNSRecordTypePacketAuth
, pkt
);
722 if (ResourceRecordAnswersQuestion(&pkt
->r
.resrec
, q
)) return(p2
);
727 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
)
729 const char *const ptype
= (msg
->h
.flags
.b
[0] & kDNSFlag0_QR_Response
) ? "-R- " :
730 (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) ? "-Q- " : "-LQ-";
734 const mDNSu32 index
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
);
735 char if_name
[IFNAMSIZ
]; // Older Linux distributions don't define IF_NAMESIZE
736 if_indextoname(index
, if_name
);
737 gettimeofday(&tv
, NULL
);
738 localtime_r((time_t*)&tv
.tv_sec
, &tm
);
739 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
);
741 mprintf("%#-16a %s Q:%3d Ans:%3d Auth:%3d Add:%3d Size:%5d bytes",
742 srcaddr
, ptype
, msg
->h
.numQuestions
, msg
->h
.numAnswers
, msg
->h
.numAuthorities
, msg
->h
.numAdditionals
, end
- (mDNSu8
*)msg
);
744 if (msg
->h
.id
.NotAnInteger
) mprintf(" ID:%u", mDNSVal16(msg
->h
.id
));
746 if (!mDNSAddrIsDNSMulticast(dstaddr
)) mprintf(" To: %#a", dstaddr
);
748 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
)
750 if (msg
->h
.flags
.b
[0] & kDNSFlag0_QR_Response
) mprintf(" Truncated");
751 else mprintf(" Truncated (KA list continues in next packet)");
756 mDNSlocal
void DisplayResourceRecord(const mDNSAddr
*const srcaddr
, const char *const op
, const ResourceRecord
*const pktrr
)
758 static const char hexchars
[16] = "0123456789ABCDEF";
760 char buffer
[MaxWidth
+8];
763 RDataBody
*rd
= &pktrr
->rdata
->u
;
764 mDNSu8
*rdend
= (mDNSu8
*)rd
+ pktrr
->rdlength
;
765 int n
= mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr
, op
, DNSTypeName(pktrr
->rrtype
), pktrr
->rroriginalttl
, pktrr
->name
->c
);
767 switch(pktrr
->rrtype
)
769 case kDNSType_A
: n
+= mprintf("%.4a", &rd
->ipv4
); break;
770 case kDNSType_PTR
: n
+= mprintf("%##.*s", MaxWidth
- n
, rd
->name
.c
); break;
771 case kDNSType_HINFO
:// same as kDNSType_TXT below
773 mDNSu8
*t
= rd
->txt
.c
;
774 while (t
< rdend
&& t
[0] && p
< buffer
+MaxWidth
)
777 for (i
=1; i
<=t
[0] && p
< buffer
+MaxWidth
; i
++)
779 if (t
[i
] == '\\') *p
++ = '\\';
780 if (t
[i
] >= ' ') *p
++ = t
[i
];
786 *p
++ = hexchars
[t
[i
] >> 4];
787 *p
++ = hexchars
[t
[i
] & 0xF];
791 if (t
< rdend
&& t
[0]) { *p
++ = '\\'; *p
++ = ' '; }
794 n
+= mprintf("%.*s", MaxWidth
- n
, buffer
);
796 case kDNSType_AAAA
: n
+= mprintf("%.16a", &rd
->ipv6
); break;
797 case kDNSType_SRV
: n
+= mprintf("%##s:%d", rd
->srv
.target
.c
, mDNSVal16(rd
->srv
.port
)); break;
799 mDNSu8
*s
= rd
->data
;
800 while (s
< rdend
&& p
< buffer
+MaxWidth
)
802 if (*s
== '\\') *p
++ = '\\';
803 if (*s
>= ' ') *p
++ = *s
;
809 *p
++ = hexchars
[*s
>> 4];
810 *p
++ = hexchars
[*s
& 0xF];
815 n
+= mprintf("%.*s", MaxWidth
- n
, buffer
);
822 mDNSlocal
void HexDump(const mDNSu8
*ptr
, const mDNSu8
*const end
)
828 if (&ptr
[i
] < end
) mprintf("%02X ", ptr
[i
]);
831 if (&ptr
[i
] < end
) mprintf("%c", ptr
[i
] <= ' ' || ptr
[i
] >= 126 ? '.' : ptr
[i
]);
837 mDNSlocal
void DisplayError(const mDNSAddr
*srcaddr
, const mDNSu8
*ptr
, const mDNSu8
*const end
, char *msg
)
839 mprintf("%#-16a **** ERROR: FAILED TO READ %s **** \n", srcaddr
, msg
);
843 mDNSlocal
void DisplayQuery(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
844 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSInterfaceID InterfaceID
)
847 const mDNSu8
*ptr
= msg
->data
;
848 const mDNSu8
*auth
= LocateAuthorities(msg
, end
);
849 mDNSBool MQ
= (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
850 HostEntry
*entry
= GotPacketFromHost(srcaddr
, MQ
? HostPkt_Q
: HostPkt_L
, msg
->h
.id
);
851 LargeCacheRecord pkt
;
853 DisplayPacketHeader(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
854 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF)
856 if (MQ
) NumPktQ
++; else NumPktL
++;
859 for (i
=0; i
<msg
->h
.numQuestions
; i
++)
862 mDNSu8
*p2
= (mDNSu8
*)getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
863 mDNSu16 ucbit
= q
.qclass
& kDNSQClass_UnicastResponse
;
864 q
.qclass
&= ~kDNSQClass_UnicastResponse
;
865 if (!p2
) { DisplayError(srcaddr
, ptr
, end
, "QUESTION"); return; }
867 p2
= (mDNSu8
*)FindUpdate(m
, msg
, auth
, end
, &q
, &pkt
);
871 DisplayResourceRecord(srcaddr
, ucbit
? "(PU)" : "(PM)", &pkt
.r
.resrec
);
872 recordstat(entry
, &q
.qname
, OP_probe
, q
.qtype
);
873 p2
= (mDNSu8
*)skipDomainName(msg
, p2
, end
);
874 // Having displayed this update record, clear type and class so we don't display the same one again.
875 p2
[0] = p2
[1] = p2
[2] = p2
[3] = 0;
879 const char *ptype
= ucbit
? "(QU)" : "(QM)";
880 if (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) NumQuestions
++;
881 else { NumLegacy
++; ptype
= "(LQ)"; }
882 mprintf("%#-16a %-5s %-5s %##s\n", srcaddr
, ptype
, DNSTypeName(q
.qtype
), q
.qname
.c
);
883 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) recordstat(entry
, &q
.qname
, OP_query
, q
.qtype
);
887 for (i
=0; i
<msg
->h
.numAnswers
; i
++)
889 const mDNSu8
*ep
= ptr
;
890 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
891 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "KNOWN ANSWER"); return; }
892 DisplayResourceRecord(srcaddr
, "(KA)", &pkt
.r
.resrec
);
894 // In the case of queries with long multi-packet KA lists, we count each subsequent KA packet
895 // the same as a single query, to more accurately reflect the burden on the network
896 // (A query with a six-packet KA list is *at least* six times the burden on the network as a single-packet query.)
897 if (msg
->h
.numQuestions
== 0 && i
== 0)
898 recordstat(entry
, pkt
.r
.resrec
.name
, OP_query
, pkt
.r
.resrec
.rrtype
);
901 for (i
=0; i
<msg
->h
.numAuthorities
; i
++)
903 const mDNSu8
*ep
= ptr
;
904 ptr
= skipResourceRecord(msg
, ptr
, end
);
905 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "AUTHORITY"); return; }
908 if (entry
) AnalyseHost(m
, entry
, InterfaceID
);
911 mDNSlocal
void DisplayResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
,
912 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSInterfaceID InterfaceID
)
915 const mDNSu8
*ptr
= msg
->data
;
916 HostEntry
*entry
= GotPacketFromHost(srcaddr
, HostPkt_R
, msg
->h
.id
);
917 LargeCacheRecord pkt
;
919 DisplayPacketHeader(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
920 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) NumPktR
++;
922 for (i
=0; i
<msg
->h
.numQuestions
; i
++)
925 const mDNSu8
*ep
= ptr
;
926 ptr
= getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
927 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "QUESTION"); return; }
928 if (mDNSAddrIsDNSMulticast(dstaddr
))
929 mprintf("%#-16a (?) **** ERROR: SHOULD NOT HAVE Q IN mDNS RESPONSE **** %-5s %##s\n", srcaddr
, DNSTypeName(q
.qtype
), q
.qname
.c
);
931 mprintf("%#-16a (Q) %-5s %##s\n", srcaddr
, DNSTypeName(q
.qtype
), q
.qname
.c
);
934 for (i
=0; i
<msg
->h
.numAnswers
; i
++)
936 const mDNSu8
*ep
= ptr
;
937 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
938 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "ANSWER"); return; }
939 if (pkt
.r
.resrec
.rroriginalttl
)
942 DisplayResourceRecord(srcaddr
, (pkt
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "(AN)" : "(AN+)", &pkt
.r
.resrec
);
943 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) recordstat(entry
, pkt
.r
.resrec
.name
, OP_answer
, pkt
.r
.resrec
.rrtype
);
944 if (entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
949 DisplayResourceRecord(srcaddr
, "(DE)", &pkt
.r
.resrec
);
950 recordstat(entry
, pkt
.r
.resrec
.name
, OP_goodbye
, pkt
.r
.resrec
.rrtype
);
954 for (i
=0; i
<msg
->h
.numAuthorities
; i
++)
956 const mDNSu8
*ep
= ptr
;
957 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &pkt
);
958 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "AUTHORITY"); return; }
959 mprintf("%#-16a (?) **** ERROR: SHOULD NOT HAVE AUTHORITY IN mDNS RESPONSE **** %-5s %##s\n",
960 srcaddr
, DNSTypeName(pkt
.r
.resrec
.rrtype
), pkt
.r
.resrec
.name
->c
);
963 for (i
=0; i
<msg
->h
.numAdditionals
; i
++)
965 const mDNSu8
*ep
= ptr
;
966 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAdd
, &pkt
);
967 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "ADDITIONAL"); return; }
969 DisplayResourceRecord(srcaddr
, (pkt
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "(AD)" : "(AD+)", &pkt
.r
.resrec
);
970 if (entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
973 if (entry
) AnalyseHost(m
, entry
, InterfaceID
);
976 mDNSlocal
void ProcessUnicastResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, const mDNSInterfaceID InterfaceID
)
979 const mDNSu8
*ptr
= LocateAnswers(msg
, end
);
980 HostEntry
*entry
= GotPacketFromHost(srcaddr
, HostPkt_R
, msg
->h
.id
);
981 //mprintf("%#a R\n", srcaddr);
983 for (i
=0; i
<msg
->h
.numAnswers
+ msg
->h
.numAuthorities
+ msg
->h
.numAdditionals
; i
++)
985 LargeCacheRecord pkt
;
986 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
987 if (pkt
.r
.resrec
.rroriginalttl
&& entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
991 mDNSlocal mDNSBool
AddressMatchesFilterList(const mDNSAddr
*srcaddr
)
994 if (!Filters
) return(srcaddr
->type
== mDNSAddrType_IPv4
);
995 for (f
=Filters
; f
; f
=f
->next
) if (mDNSSameAddress(srcaddr
, &f
->FilterAddr
)) return(mDNStrue
);
999 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
1000 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
)
1002 const mDNSu8 StdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
;
1003 const mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
1004 const mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
1005 mDNSu8
*ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
1006 int goodinterface
= (FilterInterface
== 0);
1008 (void)dstaddr
; // Unused
1009 (void)dstport
; // Unused
1011 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
1012 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
1013 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
1014 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
1015 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
1017 // For now we're only interested in monitoring IPv4 traffic.
1018 // All IPv6 packets should just be duplicates of the v4 packets.
1019 if (!goodinterface
) goodinterface
= (FilterInterface
== (int)mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
));
1020 if (goodinterface
&& AddressMatchesFilterList(srcaddr
))
1023 if (!mDNSAddrIsDNSMulticast(dstaddr
))
1025 if (QR_OP
== StdQ
) mprintf("Unicast query from %#a\n", srcaddr
);
1026 else if (QR_OP
== StdR
) ProcessUnicastResponse(m
, msg
, end
, srcaddr
, InterfaceID
);
1030 if (QR_OP
== StdQ
) DisplayQuery (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
1031 else if (QR_OP
== StdR
) DisplayResponse (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
1034 debugf("Unknown DNS packet type %02X%02X (ignored)", msg
->h
.flags
.b
[0], msg
->h
.flags
.b
[1]);
1035 GotPacketFromHost(srcaddr
, HostPkt_B
, msg
->h
.id
);
1043 mDNSlocal mStatus
mDNSNetMonitor(void)
1046 int h
, m
, s
, mul
, div
, TotPkt
;
1049 mStatus status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
1050 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
1051 mDNS_Init_DontAdvertiseLocalAddresses
,
1052 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
1053 if (status
) return(status
);
1055 gettimeofday(&tv_start
, NULL
);
1056 mDNSPosixListenForSignalInEventLoop(SIGINT
);
1057 mDNSPosixListenForSignalInEventLoop(SIGTERM
);
1061 struct timeval timeout
= { 0x3FFFFFFF, 0 }; // wait until SIGINT or SIGTERM
1062 mDNSBool gotSomething
;
1063 mDNSPosixRunEventLoopOnce(&mDNSStorage
, &timeout
, &signals
, &gotSomething
);
1065 while ( !( sigismember( &signals
, SIGINT
) || sigismember( &signals
, SIGTERM
)));
1067 // Now display final summary
1068 TotPkt
= NumPktQ
+ NumPktL
+ NumPktR
;
1069 gettimeofday(&tv_end
, NULL
);
1070 tv_interval
= tv_end
;
1071 if (tv_start
.tv_usec
> tv_interval
.tv_usec
)
1072 { tv_interval
.tv_usec
+= 1000000; tv_interval
.tv_sec
--; }
1073 tv_interval
.tv_sec
-= tv_start
.tv_sec
;
1074 tv_interval
.tv_usec
-= tv_start
.tv_usec
;
1075 h
= (tv_interval
.tv_sec
/ 3600);
1076 m
= (tv_interval
.tv_sec
% 3600) / 60;
1077 s
= (tv_interval
.tv_sec
% 60);
1078 if (tv_interval
.tv_sec
> 10)
1081 div
= tv_interval
.tv_sec
;
1086 div
= tv_interval
.tv_sec
* 1000 + tv_interval
.tv_usec
/ 1000;
1087 if (div
== 0) div
=1;
1091 localtime_r((time_t*)&tv_start
.tv_sec
, &tm
);
1092 mprintf("Started %3d:%02d:%02d.%06d\n", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, tv_start
.tv_usec
);
1093 localtime_r((time_t*)&tv_end
.tv_sec
, &tm
);
1094 mprintf("End %3d:%02d:%02d.%06d\n", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, tv_end
.tv_usec
);
1095 mprintf("Captured for %3d:%02d:%02d.%06d\n", h
, m
, s
, tv_interval
.tv_usec
);
1098 mprintf("Unique source addresses seen on network:");
1099 if (IPv4HostList
.num
) mprintf(" %ld (IPv4)", IPv4HostList
.num
);
1100 if (IPv6HostList
.num
) mprintf(" %ld (IPv6)", IPv6HostList
.num
);
1101 if (!IPv4HostList
.num
&& !IPv6HostList
.num
) mprintf(" None");
1105 mprintf("Modern Query Packets: %7d (avg%5d/min)\n", NumPktQ
, NumPktQ
* mul
/ div
);
1106 mprintf("Legacy Query Packets: %7d (avg%5d/min)\n", NumPktL
, NumPktL
* mul
/ div
);
1107 mprintf("Multicast Response Packets: %7d (avg%5d/min)\n", NumPktR
, NumPktR
* mul
/ div
);
1108 mprintf("Total Multicast Packets: %7d (avg%5d/min)\n", TotPkt
, TotPkt
* mul
/ div
);
1110 mprintf("Total New Service Probes: %7d (avg%5d/min)\n", NumProbes
, NumProbes
* mul
/ div
);
1111 mprintf("Total Goodbye Announcements: %7d (avg%5d/min)\n", NumGoodbyes
, NumGoodbyes
* mul
/ div
);
1112 mprintf("Total Query Questions: %7d (avg%5d/min)\n", NumQuestions
, NumQuestions
* mul
/ div
);
1113 mprintf("Total Queries from Legacy Clients:%7d (avg%5d/min)\n", NumLegacy
, NumLegacy
* mul
/ div
);
1114 mprintf("Total Answers/Announcements: %7d (avg%5d/min)\n", NumAnswers
, NumAnswers
* mul
/ div
);
1115 mprintf("Total Additional Records: %7d (avg%5d/min)\n", NumAdditionals
, NumAdditionals
* mul
/ div
);
1117 printstats(kReportTopServices
);
1119 if (!ExactlyOneFilter
)
1121 ShowSortedHostList(&IPv4HostList
, kReportTopHosts
);
1122 ShowSortedHostList(&IPv6HostList
, kReportTopHosts
);
1125 mDNS_Close(&mDNSStorage
);
1129 mDNSexport
int main(int argc
, char **argv
)
1131 const char *progname
= strrchr(argv
[0], '/') ? strrchr(argv
[0], '/') + 1 : argv
[0];
1135 setlinebuf(stdout
); // Want to see lines as they appear, not block buffered
1137 for (i
=1; i
<argc
; i
++)
1139 if (i
+1 < argc
&& !strcmp(argv
[i
], "-i") && atoi(argv
[i
+1]))
1141 FilterInterface
= atoi(argv
[i
+1]);
1143 printf("Monitoring interface %d\n", FilterInterface
);
1151 a
.type
= mDNSAddrType_IPv4
;
1153 if (inet_pton(AF_INET
, argv
[i
], &s4
) == 1)
1154 a
.ip
.v4
.NotAnInteger
= s4
.s_addr
;
1155 else if (inet_pton(AF_INET6
, argv
[i
], &s6
) == 1)
1157 a
.type
= mDNSAddrType_IPv6
;
1158 bcopy(&s6
, &a
.ip
.v6
, sizeof(a
.ip
.v6
));
1162 struct hostent
*h
= gethostbyname(argv
[i
]);
1163 if (h
) a
.ip
.v4
.NotAnInteger
= *(long*)h
->h_addr
;
1167 f
= malloc(sizeof(*f
));
1174 status
= mDNSNetMonitor();
1175 if (status
) { fprintf(stderr
, "%s: mDNSNetMonitor failed %d\n", progname
, (int)status
); return(status
); }
1179 fprintf(stderr
, "\nmDNS traffic monitor\n");
1180 fprintf(stderr
, "Usage: %s (<host>)\n", progname
);
1181 fprintf(stderr
, "Optional <host> parameter displays only packets from that host\n");
1183 fprintf(stderr
, "\nPer-packet header output:\n");
1184 fprintf(stderr
, "-Q- Multicast Query from mDNS client that accepts multicast responses\n");
1185 fprintf(stderr
, "-R- Multicast Response packet containing answers/announcements\n");
1186 fprintf(stderr
, "-LQ- Multicast Query from legacy client that does *not* listen for multicast responses\n");
1187 fprintf(stderr
, "Q/Ans/Auth/Add Number of questions, answers, authority records and additional records in packet\n");
1189 fprintf(stderr
, "\nPer-record display:\n");
1190 fprintf(stderr
, "(PM) Probe Question (new service starting), requesting multicast response\n");
1191 fprintf(stderr
, "(PU) Probe Question (new service starting), requesting unicast response\n");
1192 fprintf(stderr
, "(DE) Deletion/Goodbye (service going away)\n");
1193 fprintf(stderr
, "(LQ) Legacy Query Question\n");
1194 fprintf(stderr
, "(QM) Query Question, requesting multicast response\n");
1195 fprintf(stderr
, "(QU) Query Question, requesting unicast response\n");
1196 fprintf(stderr
, "(KA) Known Answer (information querier already knows)\n");
1197 fprintf(stderr
, "(AN) Unique Answer to question (or periodic announcment) (entire RR Set)\n");
1198 fprintf(stderr
, "(AN+) Answer to question (or periodic announcment) (add to existing RR Set members)\n");
1199 fprintf(stderr
, "(AD) Unique Additional Record Set (entire RR Set)\n");
1200 fprintf(stderr
, "(AD+) Additional records (add to existing RR Set members)\n");
1202 fprintf(stderr
, "\nFinal summary, sorted by service type:\n");
1203 fprintf(stderr
, "Probe Probes for this service type starting up\n");
1204 fprintf(stderr
, "Goodbye Goodbye (deletion) packets for this service type shutting down\n");
1205 fprintf(stderr
, "BrowseQ Browse questions from clients browsing to find a list of instances of this service\n");
1206 fprintf(stderr
, "BrowseA Browse answers/announcments advertising instances of this service\n");
1207 fprintf(stderr
, "ResolveQ Resolve questions from clients actively connecting to an instance of this service\n");
1208 fprintf(stderr
, "ResolveA Resolve answers/announcments giving connection information for an instance of this service\n");
1209 fprintf(stderr
, "\n");