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.75 2006/01/05 22:33:58 cheshire
41 Use IFNAMSIZ (more portable) instead of IF_NAMESIZE
43 Revision 1.74 2005/12/02 20:08:39 cheshire
44 Update "No HINFO" message
46 Revision 1.73 2005/12/02 19:19:53 cheshire
47 <rdar://problem/4331590> Include interface index and name in mDNSNetMonitor output
49 Revision 1.72 2005/11/07 01:47:45 cheshire
50 <rdar://problem/4331590> Include interface index in mDNSNetMonitor output
52 Revision 1.71 2004/12/16 20:17:11 cheshire
53 <rdar://problem/3324626> Cache memory management improvements
55 Revision 1.70 2004/12/04 02:13:20 cheshire
56 Pass proper record type in GetLargeResourceRecord() calls
58 Revision 1.69 2004/11/30 22:37:01 cheshire
59 Update copyright dates and add "Mode: C; tab-width: 4" headers
61 Revision 1.68 2004/10/23 01:16:01 cheshire
62 <rdar://problem/3851677> uDNS operations not always reliable on multi-homed hosts
64 Revision 1.67 2004/10/16 00:17:00 cheshire
65 <rdar://problem/3770558> Replace IP TTL 255 check with local subnet source address check
67 Revision 1.66 2004/09/17 00:31:52 cheshire
68 For consistency with ipv6, renamed rdata field 'ip' to 'ipv4'
70 Revision 1.65 2004/09/16 01:58:22 cheshire
73 Revision 1.64 2004/06/15 02:39:47 cheshire
74 When displaying error message, only show command name, not entire path
76 Revision 1.63 2004/05/18 23:51:26 cheshire
77 Tidy up all checkin comments to use consistent "<rdar://problem/xxxxxxx>" format for bug numbers
79 Revision 1.62 2004/03/16 18:24:25 cheshire
80 If packet destination was not multicast, then display it
82 Revision 1.61 2004/02/20 09:36:46 cheshire
83 Also show TTL in packet header, if it's not 255
85 Revision 1.60 2004/02/07 02:11:35 cheshire
86 Make mDNSNetMonitor smarter about sending targeted unicast HINFO queries
88 Revision 1.59 2004/02/03 21:42:55 cheshire
89 Add constants kReportTopServices and kReportTopHosts
91 Revision 1.58 2004/01/27 20:15:23 cheshire
92 <rdar://problem/3541288>: Time to prune obsolete code for listening on port 53
94 Revision 1.57 2004/01/24 23:59:42 cheshire
95 Change to use mDNSVal16() instead of shifting and ORing
97 Revision 1.56 2004/01/24 05:25:34 cheshire
98 mDNSNetMonitor now uses the new ability to send unicast queries so that
99 it causes less perturbation of the network traffic it's monitoring.
101 Revision 1.55 2003/12/23 00:21:31 cheshire
102 Send HINFO queries to determine the mDNSResponder version of each host
104 Revision 1.54 2003/12/17 01:06:39 cheshire
105 Also show host name along with HINFO data
107 Revision 1.53 2003/12/17 00:51:22 cheshire
108 Changed mDNSNetMonitor and mDNSIdentify to link the object files
109 instead of #including the "DNSCommon.c" "uDNS.c" and source files
111 Revision 1.52 2003/12/17 00:21:51 cheshire
112 If we received one, display host's HINFO record in final summary
114 Revision 1.51 2003/12/13 03:05:28 ksekar
115 <rdar://problem/3192548>: DynDNS: Unicast query of service records
117 Revision 1.50 2003/12/08 20:47:02 rpantos
118 Add support for mDNSResponder on Linux.
120 Revision 1.49 2003/10/30 19:38:56 cheshire
121 Fix warning on certain compilers
123 Revision 1.48 2003/10/30 19:30:00 cheshire
124 Fix warnings on certain compilers
126 Revision 1.47 2003/09/05 18:49:57 cheshire
127 Add total packet size to display
129 Revision 1.46 2003/09/05 02:33:48 cheshire
130 Set output to be line buffered, so you can redirect to a file and "tail -f" the file in another window
132 Revision 1.45 2003/09/04 00:16:20 cheshire
133 Only show count of unique source addresses seen on network if we're not filtering
135 Revision 1.44 2003/09/02 22:13:28 cheshire
136 Show total host count in final summary table
138 Revision 1.43 2003/09/02 21:42:52 cheshire
139 Improved alignment of final summary table with v6 addresses
141 Revision 1.42 2003/09/02 20:59:24 cheshire
142 Use bcopy() instead of non-portable "__u6_addr.__u6_addr32" fields.
144 Revision 1.41 2003/08/29 22:05:44 cheshire
145 Also count subsequent KA packets for the purposes of statistics counting
147 Revision 1.40 2003/08/29 16:43:24 cheshire
148 Also display breakdown of Probe/Goodbye/BrowseQ etc. for each host
150 Revision 1.39 2003/08/28 02:07:48 vlubet
151 Added "per hosts" statistics
153 Revision 1.38 2003/08/20 22:41:42 cheshire
154 Also display total multicast packet count
156 Revision 1.37 2003/08/20 22:32:08 cheshire
157 Error in DisplayQuery: Authorities come *after* Answers, not before
159 Revision 1.36 2003/08/18 23:20:10 cheshire
160 RDLength moved from the RData to the ResourceRecord object.
162 Revision 1.35 2003/08/15 20:17:28 cheshire
163 "LargeResourceRecord" changed to "LargeCacheRecord"
165 Revision 1.34 2003/08/14 02:19:55 cheshire
166 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
168 Revision 1.33 2003/08/12 19:56:26 cheshire
171 Revision 1.32 2003/08/06 18:57:01 cheshire
174 Revision 1.31 2003/08/06 02:05:12 cheshire
175 Add ability to give a list of hosts to monitor
177 Revision 1.30 2003/08/05 23:56:26 cheshire
178 Update code to compile with the new mDNSCoreReceive() function that requires a TTL
179 (Right now mDNSPosix.c just reports 255 -- we should fix this)
181 Revision 1.29 2003/08/05 00:43:12 cheshire
182 Report errors encountered while processing authority section
184 Revision 1.28 2003/07/29 22:51:08 cheshire
185 Added hexdump for packets we can't decode, so we can find out *why* we couldn't decode them
187 Revision 1.27 2003/07/29 22:48:04 cheshire
188 Completed support for decoding packets containing oversized resource records
190 Revision 1.26 2003/07/19 03:25:23 cheshire
191 Change to make use of new GetLargeResourceRecord() call, for handling larger records
193 Revision 1.25 2003/07/18 00:13:23 cheshire
194 Remove erroneous trailing '\' from TXT record display
196 Revision 1.24 2003/07/17 17:10:51 cheshire
197 <rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
198 Further work: distinguish between PM and PU
200 Revision 1.23 2003/07/16 22:20:23 cheshire
201 <rdar://problem/3315761> Implement "unicast response" request, using top bit of qclass
202 Made mDNSNetMonitor distinguish between QM and QU in its logging output
204 Revision 1.22 2003/07/02 21:19:58 cheshire
205 <rdar://problem/3313413> Update copyright notices, etc., in source code comments
207 Revision 1.21 2003/06/18 05:48:41 cheshire
210 Revision 1.20 2003/06/06 22:18:22 cheshire
211 Add extra space in Q output to line it up with RR output
213 Revision 1.19 2003/06/06 21:05:04 cheshire
214 Display state of cache-flush bit on additional records
216 Revision 1.18 2003/06/06 20:01:30 cheshire
217 For clarity, rename question fields name/rrtype/rrclass as qname/qtype/qclass
218 (Global search-and-replace; no functional change to code execution.)
220 Revision 1.17 2003/06/06 14:26:50 cheshire
221 Explicitly #include <time.h> for the benefit of certain Linux distributions
223 Revision 1.16 2003/05/29 21:56:36 cheshire
225 Distinguish modern multicast queries from legacy multicast queries
226 In addition to record counts, display packet counts of queries, legacy queries, and responses
227 Include TTL in RR display
229 Revision 1.15 2003/05/29 20:03:57 cheshire
230 Various improvements:
231 Display start and end time, average rates in packets-per-minute,
232 show legacy queries as -LQ-, improve display of TXT and unknown records
234 Revision 1.14 2003/05/26 04:45:42 cheshire
235 Limit line length when printing super-long TXT records
237 Revision 1.13 2003/05/26 03:21:29 cheshire
238 Tidy up address structure naming:
239 mDNSIPAddr => mDNSv4Addr (for consistency with mDNSv6Addr)
240 mDNSAddr.addr.ipv4 => mDNSAddr.ip.v4
241 mDNSAddr.addr.ipv6 => mDNSAddr.ip.v6
243 Revision 1.12 2003/05/26 03:01:28 cheshire
244 <rdar://problem/3268904> sprintf/vsprintf-style functions are unsafe; use snprintf/vsnprintf instead
246 Revision 1.11 2003/05/26 00:48:13 cheshire
247 If mDNS packet contains a non-zero message ID, then display it.
249 Revision 1.10 2003/05/22 01:10:32 cheshire
250 Indicate when the TC bit is set on a query packet
252 Revision 1.9 2003/05/21 03:56:00 cheshire
253 Improve display of Probe queries
255 Revision 1.8 2003/05/09 21:41:56 cheshire
256 Track deletion/goodbye packets as separate category
258 Revision 1.7 2003/05/07 00:16:01 cheshire
259 More detailed decoding of Resource Records
261 Revision 1.6 2003/05/05 21:16:16 cheshire
262 <rdar://problem/3241281> Change timenow from a local variable to a structure member
264 Revision 1.5 2003/04/19 01:16:22 cheshire
265 Add filter option, to monitor only packets from a single specified source address
267 Revision 1.4 2003/04/18 00:45:21 cheshire
268 Distinguish announcements (AN) from deletions (DE)
270 Revision 1.3 2003/04/15 18:26:01 cheshire
271 Added timestamps and help information
273 Revision 1.2 2003/04/04 20:42:02 cheshire
274 Fix broken statistics counting
276 Revision 1.1 2003/04/04 01:37:14 cheshire
281 //*************************************************************************************************************
282 // Incorporate mDNS.c functionality
284 // We want to use much of the functionality provided by "mDNS.c",
285 // except we'll steal the packets that would be sent to normal mDNSCoreReceive() routine
286 #define mDNSCoreReceive __NOT__mDNSCoreReceive__NOT__
288 #undef mDNSCoreReceive
290 //*************************************************************************************************************
293 #include <stdio.h> // For printf()
294 #include <stdlib.h> // For malloc()
295 #include <string.h> // For bcopy()
296 #include <time.h> // For "struct tm" etc.
297 #include <signal.h> // For SIGINT, SIGTERM
298 #include <netdb.h> // For gethostbyname()
299 #include <sys/socket.h> // For AF_INET, AF_INET6, etc.
300 #include <arpa/inet.h> // For inet_addr()
301 #include <net/if.h> // For IF_NAMESIZE
302 #include <netinet/in.h> // For INADDR_NONE
304 #include "mDNSPosix.h" // Defines the specific types needed to run mDNS on this platform
305 #include "ExampleClientApp.h"
307 //*************************************************************************************************************
308 // Types and structures
312 // Primitive operations
316 // These are meta-categories;
317 // Query and Answer operations are actually subdivided into two classes:
318 // Browse query/answer and
319 // Resolve query/answer
323 // The "Browse" variants of query/answer
328 // The "Resolve" variants of query/answer
336 typedef struct ActivityStat_struct ActivityStat
;
337 struct ActivityStat_struct
343 int stat
[OP_NumTypes
];
346 typedef struct FilterList_struct FilterList
;
347 struct FilterList_struct
353 //*************************************************************************************************************
356 #define kReportTopServices 15
357 #define kReportTopHosts 15
359 //*************************************************************************************************************
362 static mDNS mDNSStorage
; // mDNS core uses this to store its globals
363 static mDNS_PlatformSupport PlatformStorage
; // Stores this platform's globals
365 struct timeval tv_start
, tv_end
, tv_interval
;
367 static FilterList
*Filters
;
368 #define ExactlyOneFilter (Filters && !Filters->next)
370 static int NumPktQ
, NumPktL
, NumPktR
, NumPktB
; // Query/Legacy/Response/Bad
371 static int NumProbes
, NumGoodbyes
, NumQuestions
, NumLegacy
, NumAnswers
, NumAdditionals
;
373 static ActivityStat
*stats
;
375 #define OPBanner "Total Ops Probe Goodbye BrowseQ BrowseA ResolveQ ResolveA"
377 //*************************************************************************************************************
380 // Special version of printf that knows how to print IP addresses, DNS-format name strings, etc.
381 mDNSlocal mDNSu32
mprintf(const char *format
, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
382 mDNSlocal mDNSu32
mprintf(const char *format
, ...)
385 unsigned char buffer
[512];
387 va_start(ptr
,format
);
388 length
= mDNS_vsnprintf((char *)buffer
, sizeof(buffer
), format
, ptr
);
390 printf("%s", buffer
);
394 //*************************************************************************************************************
397 // Would benefit from a hash
401 HostPkt_Q
= 0, // Query
402 HostPkt_L
= 1, // Legacy Query
403 HostPkt_R
= 2, // Response
404 HostPkt_B
= 3, // Bad
411 unsigned long pkts
[HostPkt_NumTypes
];
412 unsigned long totalops
;
413 unsigned long stat
[OP_NumTypes
];
416 UTF8str255 HIHardware
;
417 UTF8str255 HISoftware
;
422 #define HostEntryTotalPackets(H) ((H)->pkts[HostPkt_Q] + (H)->pkts[HostPkt_L] + (H)->pkts[HostPkt_R] + (H)->pkts[HostPkt_B])
431 static HostList IPv4HostList
= { 0, 0, 0 };
432 static HostList IPv6HostList
= { 0, 0, 0 };
434 mDNSlocal HostEntry
*FindHost(const mDNSAddr
*addr
, HostList
* list
)
438 for (i
= 0; i
< list
->num
; i
++)
440 HostEntry
*entry
= list
->hosts
+ i
;
441 if (mDNSSameAddress(addr
, &entry
->addr
))
448 mDNSlocal HostEntry
*AddHost(const mDNSAddr
*addr
, HostList
* list
)
452 if (list
->num
>= list
->max
)
454 long newMax
= list
->max
+ 64;
455 HostEntry
*newHosts
= realloc(list
->hosts
, newMax
* sizeof(HostEntry
));
456 if (newHosts
== NULL
)
459 list
->hosts
= newHosts
;
462 entry
= list
->hosts
+ list
->num
++;
465 for (i
=0; i
<HostPkt_NumTypes
; i
++) entry
->pkts
[i
] = 0;
467 for (i
=0; i
<OP_NumTypes
; i
++) entry
->stat
[i
] = 0;
468 entry
->hostname
.c
[0] = 0;
469 entry
->revname
.c
[0] = 0;
470 entry
->HIHardware
.c
[0] = 0;
471 entry
->HISoftware
.c
[0] = 0;
472 entry
->NumQueries
= 0;
474 if (entry
->addr
.type
== mDNSAddrType_IPv4
)
476 mDNSv4Addr ip
= entry
->addr
.ip
.v4
;
478 mDNS_snprintf(buffer
, sizeof(buffer
), "%d.%d.%d.%d.in-addr.arpa.", ip
.b
[3], ip
.b
[2], ip
.b
[1], ip
.b
[0]);
479 MakeDomainNameFromDNSNameString(&entry
->revname
, buffer
);
485 mDNSlocal HostEntry
*GotPacketFromHost(const mDNSAddr
*addr
, HostPkt_Type t
, mDNSOpaque16 id
)
487 if (ExactlyOneFilter
) return(NULL
);
490 HostList
*list
= (addr
->type
== mDNSAddrType_IPv4
) ? &IPv4HostList
: &IPv6HostList
;
491 HostEntry
*entry
= FindHost(addr
, list
);
492 if (!entry
) entry
= AddHost(addr
, list
);
493 if (!entry
) return(NULL
);
494 // Don't count our own interrogation packets
495 if (id
.NotAnInteger
!= 0xFFFF) entry
->pkts
[t
]++;
500 mDNSlocal
void RecordHostInfo(HostEntry
*entry
, const ResourceRecord
*const pktrr
)
502 if (!entry
->hostname
.c
[0])
504 if (pktrr
->rrtype
== kDNSType_A
|| pktrr
->rrtype
== kDNSType_AAAA
)
506 // Should really check that the rdata in the address record matches the source address of this packet
507 entry
->NumQueries
= 0;
508 AssignDomainName(&entry
->hostname
, pktrr
->name
);
511 if (pktrr
->rrtype
== kDNSType_PTR
)
512 if (SameDomainName(&entry
->revname
, pktrr
->name
))
514 entry
->NumQueries
= 0;
515 AssignDomainName(&entry
->hostname
, &pktrr
->rdata
->u
.name
);
518 else if (pktrr
->rrtype
== kDNSType_HINFO
)
520 RDataBody
*rd
= &pktrr
->rdata
->u
;
521 mDNSu8
*rdend
= (mDNSu8
*)rd
+ pktrr
->rdlength
;
522 mDNSu8
*hw
= rd
->txt
.c
;
523 mDNSu8
*sw
= hw
+ 1 + (mDNSu32
)hw
[0];
524 if (sw
+ 1 + sw
[0] <= rdend
)
526 AssignDomainName(&entry
->hostname
, pktrr
->name
);
527 mDNSPlatformMemCopy(hw
, entry
->HIHardware
.c
, 1 + (mDNSu32
)hw
[0]);
528 mDNSPlatformMemCopy(sw
, entry
->HISoftware
.c
, 1 + (mDNSu32
)sw
[0]);
533 mDNSlocal
void SendUnicastQuery(mDNS
*const m
, HostEntry
*entry
, domainname
*name
, mDNSu16 rrtype
, mDNSInterfaceID InterfaceID
)
535 const mDNSOpaque16 id
= { { 0xFF, 0xFF } };
537 mDNSu8
*qptr
= query
.data
;
538 const mDNSu8
*const limit
= query
.data
+ sizeof(query
.data
);
539 const mDNSAddr
*target
= &entry
->addr
;
540 InitializeDNSMessage(&query
.h
, id
, QueryFlags
);
541 qptr
= putQuestion(&query
, qptr
, limit
, name
, rrtype
, kDNSClass_IN
);
542 entry
->LastQuery
= m
->timenow
;
545 // Note: When there are multiple mDNSResponder agents running on a single machine
546 // (e.g. Apple mDNSResponder plus a SliMP3 server with embedded mDNSResponder)
547 // it is possible that unicast queries may not go to the primary system responder.
548 // We try the first query using unicast, but if that doesn't work we try again via multicast.
549 if (entry
->NumQueries
> 2)
551 target
= &AllDNSLinkGroup_v4
;
555 //mprintf("%#a Q\n", target);
556 InterfaceID
= mDNSInterface_Any
; // Send query from our unicast reply socket
557 m
->ExpectUnicastResponse
= m
->timenow
;
560 mDNSSendDNSMessage(&mDNSStorage
, &query
, qptr
, InterfaceID
, target
, MulticastDNSPort
, -1, mDNSNULL
);
563 mDNSlocal
void AnalyseHost(mDNS
*const m
, HostEntry
*entry
, const mDNSInterfaceID InterfaceID
)
565 // If we've done four queries without answer, give up
566 if (entry
->NumQueries
>= 4) return;
568 // If we've done a query in the last second, give the host a chance to reply before trying again
569 if (entry
->NumQueries
&& m
->timenow
- entry
->LastQuery
< mDNSPlatformOneSecond
) return;
571 // If we don't know the host name, try to find that first
572 if (!entry
->hostname
.c
[0])
574 if (entry
->revname
.c
[0])
576 SendUnicastQuery(m
, entry
, &entry
->revname
, kDNSType_PTR
, InterfaceID
);
577 //mprintf("%##s PTR %d\n", entry->revname.c, entry->NumQueries);
580 // If we have the host name but no HINFO, now ask for that
581 else if (!entry
->HIHardware
.c
[0])
583 SendUnicastQuery(m
, entry
, &entry
->hostname
, kDNSType_HINFO
, InterfaceID
);
584 //mprintf("%##s HINFO %d\n", entry->hostname.c, entry->NumQueries);
588 mDNSlocal
int CompareHosts(const void *p1
, const void *p2
)
590 return (int)(HostEntryTotalPackets((HostEntry
*)p2
) - HostEntryTotalPackets((HostEntry
*)p1
));
593 mDNSlocal
void ShowSortedHostList(HostList
*list
, int max
)
595 HostEntry
*e
, *end
= &list
->hosts
[(max
< list
->num
) ? max
: list
->num
];
596 qsort(list
->hosts
, list
->num
, sizeof(HostEntry
), CompareHosts
);
597 if (list
->num
) mprintf("\n%-25s%s%s\n", "Source Address", OPBanner
, " Pkts Query LegacyQ Response");
598 for (e
= &list
->hosts
[0]; e
< end
; e
++)
600 int len
= mprintf("%#-25a", &e
->addr
);
601 if (len
> 25) mprintf("\n%25s", "");
602 mprintf("%8lu %8lu %8lu %8lu %8lu %8lu %8lu", e
->totalops
,
603 e
->stat
[OP_probe
], e
->stat
[OP_goodbye
],
604 e
->stat
[OP_browseq
], e
->stat
[OP_browsea
],
605 e
->stat
[OP_resolveq
], e
->stat
[OP_resolvea
]);
606 mprintf(" %8lu %8lu %8lu %8lu",
607 HostEntryTotalPackets(e
), e
->pkts
[HostPkt_Q
], e
->pkts
[HostPkt_L
], e
->pkts
[HostPkt_R
]);
608 if (e
->pkts
[HostPkt_B
]) mprintf("Bad: %8lu", e
->pkts
[HostPkt_B
]);
610 if (!e
->HISoftware
.c
[0] && e
->NumQueries
> 2)
611 mDNSPlatformMemCopy("\x27*** Unknown (Jaguar, Windows, etc.) ***", &e
->HISoftware
, 0x28);
612 if (e
->hostname
.c
[0] || e
->HIHardware
.c
[0] || e
->HISoftware
.c
[0])
613 mprintf("%##-45s %#-14s %#s\n", e
->hostname
.c
, e
->HIHardware
.c
, e
->HISoftware
.c
);
617 //*************************************************************************************************************
618 // Receive and process packets
620 mDNSexport mDNSBool
ExtractServiceType(const domainname
*const fqdn
, domainname
*const srvtype
)
623 const mDNSu8
*src
= fqdn
->c
;
624 mDNSu8
*dst
= srvtype
->c
;
627 if (len
== 0 || len
>= 0x40) return(mDNSfalse
);
628 if (src
[1] != '_') src
+= 1 + len
;
631 if (len
== 0 || len
>= 0x40 || src
[1] != '_') return(mDNSfalse
);
632 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
635 if (len
== 0 || len
>= 0x40 || src
[1] != '_') return(mDNSfalse
);
636 for (i
=0; i
<=len
; i
++) *dst
++ = *src
++;
638 *dst
++ = 0; // Put the null root label on the end of the service type
643 mDNSlocal
void recordstat(HostEntry
*entry
, domainname
*fqdn
, int op
, mDNSu16 rrtype
)
645 ActivityStat
**s
= &stats
;
650 if (rrtype
== kDNSType_SRV
|| rrtype
== kDNSType_TXT
) op
= op
- OP_browsegroup
+ OP_resolvegroup
;
651 else if (rrtype
!= kDNSType_PTR
) return;
654 if (!ExtractServiceType(fqdn
, &srvtype
)) return;
656 while (*s
&& !SameDomainName(&(*s
)->srvtype
, &srvtype
)) s
= &(*s
)->next
;
660 *s
= malloc(sizeof(ActivityStat
));
663 (*s
)->srvtype
= srvtype
;
666 for (i
=0; i
<OP_NumTypes
; i
++) (*s
)->stat
[i
] = 0;
678 mDNSlocal
void printstats(int max
)
682 for (i
=0; i
<max
; i
++)
685 ActivityStat
*s
, *m
= NULL
;
686 for (s
= stats
; s
; s
=s
->next
)
687 if (!s
->printed
&& max
< s
->totalops
)
688 { m
= s
; max
= s
->totalops
; }
690 m
->printed
= mDNStrue
;
691 if (i
==0) mprintf("%-25s%s\n", "Service Type", OPBanner
);
692 mprintf("%##-25s%8d %8d %8d %8d %8d %8d %8d\n", m
->srvtype
.c
, m
->totalops
, m
->stat
[OP_probe
],
693 m
->stat
[OP_goodbye
], m
->stat
[OP_browseq
], m
->stat
[OP_browsea
], m
->stat
[OP_resolveq
], m
->stat
[OP_resolvea
]);
697 mDNSlocal
const mDNSu8
*FindUpdate(mDNS
*const m
, const DNSMessage
*const query
, const mDNSu8
*ptr
, const mDNSu8
*const end
,\
698 DNSQuestion
*q
, LargeCacheRecord
*pkt
)
701 for (i
= 0; i
< query
->h
.numAuthorities
; i
++)
703 const mDNSu8
*p2
= ptr
;
704 ptr
= GetLargeResourceRecord(m
, query
, ptr
, end
, q
->InterfaceID
, kDNSRecordTypePacketAuth
, pkt
);
706 if (ResourceRecordAnswersQuestion(&pkt
->r
.resrec
, q
)) return(p2
);
711 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
)
713 const char *const ptype
= (msg
->h
.flags
.b
[0] & kDNSFlag0_QR_Response
) ? "-R- " :
714 (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) ? "-Q- " : "-LQ-";
718 const mDNSu32 index
= mDNSPlatformInterfaceIndexfromInterfaceID(m
, InterfaceID
);
719 char if_name
[IFNAMSIZ
]; // Older Linux distributions don't define IF_NAMESIZE
720 if_indextoname(index
, if_name
);
721 gettimeofday(&tv
, NULL
);
722 localtime_r((time_t*)&tv
.tv_sec
, &tm
);
723 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
);
725 mprintf("%#-16a %s Q:%3d Ans:%3d Auth:%3d Add:%3d Size:%5d bytes",
726 srcaddr
, ptype
, msg
->h
.numQuestions
, msg
->h
.numAnswers
, msg
->h
.numAuthorities
, msg
->h
.numAdditionals
, end
- (mDNSu8
*)msg
);
728 if (msg
->h
.id
.NotAnInteger
) mprintf(" ID:%u", mDNSVal16(msg
->h
.id
));
730 if (!mDNSAddrIsDNSMulticast(dstaddr
)) mprintf(" To: %#a", dstaddr
);
732 if (msg
->h
.flags
.b
[0] & kDNSFlag0_TC
)
734 if (msg
->h
.flags
.b
[0] & kDNSFlag0_QR_Response
) mprintf(" Truncated");
735 else mprintf(" Truncated (KA list continues in next packet)");
740 mDNSlocal
void DisplayResourceRecord(const mDNSAddr
*const srcaddr
, const char *const op
, const ResourceRecord
*const pktrr
)
742 static const char hexchars
[16] = "0123456789ABCDEF";
744 char buffer
[MaxWidth
+8];
747 RDataBody
*rd
= &pktrr
->rdata
->u
;
748 mDNSu8
*rdend
= (mDNSu8
*)rd
+ pktrr
->rdlength
;
749 int n
= mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr
, op
, DNSTypeName(pktrr
->rrtype
), pktrr
->rroriginalttl
, pktrr
->name
->c
);
751 switch(pktrr
->rrtype
)
753 case kDNSType_A
: n
+= mprintf("%.4a", &rd
->ipv4
); break;
754 case kDNSType_PTR
: n
+= mprintf("%##.*s", MaxWidth
- n
, rd
->name
.c
); break;
755 case kDNSType_HINFO
:// same as kDNSType_TXT below
757 mDNSu8
*t
= rd
->txt
.c
;
758 while (t
< rdend
&& t
[0] && p
< buffer
+MaxWidth
)
761 for (i
=1; i
<=t
[0] && p
< buffer
+MaxWidth
; i
++)
763 if (t
[i
] == '\\') *p
++ = '\\';
764 if (t
[i
] >= ' ') *p
++ = t
[i
];
770 *p
++ = hexchars
[t
[i
] >> 4];
771 *p
++ = hexchars
[t
[i
] & 0xF];
775 if (t
< rdend
&& t
[0]) { *p
++ = '\\'; *p
++ = ' '; }
778 n
+= mprintf("%.*s", MaxWidth
- n
, buffer
);
780 case kDNSType_AAAA
: n
+= mprintf("%.16a", &rd
->ipv6
); break;
781 case kDNSType_SRV
: n
+= mprintf("%##s:%d", rd
->srv
.target
.c
, mDNSVal16(rd
->srv
.port
)); break;
783 mDNSu8
*s
= rd
->data
;
784 while (s
< rdend
&& p
< buffer
+MaxWidth
)
786 if (*s
== '\\') *p
++ = '\\';
787 if (*s
>= ' ') *p
++ = *s
;
793 *p
++ = hexchars
[*s
>> 4];
794 *p
++ = hexchars
[*s
& 0xF];
799 n
+= mprintf("%.*s", MaxWidth
- n
, buffer
);
806 mDNSlocal
void HexDump(const mDNSu8
*ptr
, const mDNSu8
*const end
)
812 if (&ptr
[i
] < end
) mprintf("%02X ", ptr
[i
]);
815 if (&ptr
[i
] < end
) mprintf("%c", ptr
[i
] <= ' ' || ptr
[i
] >= 126 ? '.' : ptr
[i
]);
821 mDNSlocal
void DisplayError(const mDNSAddr
*srcaddr
, const mDNSu8
*ptr
, const mDNSu8
*const end
, char *msg
)
823 mprintf("%#-16a **** ERROR: FAILED TO READ %s **** \n", srcaddr
, msg
);
827 mDNSlocal
void DisplayQuery(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*const end
,
828 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSInterfaceID InterfaceID
)
831 const mDNSu8
*ptr
= msg
->data
;
832 const mDNSu8
*auth
= LocateAuthorities(msg
, end
);
833 mDNSBool MQ
= (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
);
834 HostEntry
*entry
= GotPacketFromHost(srcaddr
, MQ
? HostPkt_Q
: HostPkt_L
, msg
->h
.id
);
835 LargeCacheRecord pkt
;
837 DisplayPacketHeader(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
838 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF)
840 if (MQ
) NumPktQ
++; else NumPktL
++;
843 for (i
=0; i
<msg
->h
.numQuestions
; i
++)
846 mDNSu8
*p2
= (mDNSu8
*)getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
847 mDNSu16 ucbit
= q
.qclass
& kDNSQClass_UnicastResponse
;
848 q
.qclass
&= ~kDNSQClass_UnicastResponse
;
849 if (!p2
) { DisplayError(srcaddr
, ptr
, end
, "QUESTION"); return; }
851 p2
= (mDNSu8
*)FindUpdate(m
, msg
, auth
, end
, &q
, &pkt
);
855 DisplayResourceRecord(srcaddr
, ucbit
? "(PU)" : "(PM)", &pkt
.r
.resrec
);
856 recordstat(entry
, &q
.qname
, OP_probe
, q
.qtype
);
857 p2
= (mDNSu8
*)skipDomainName(msg
, p2
, end
);
858 // Having displayed this update record, clear type and class so we don't display the same one again.
859 p2
[0] = p2
[1] = p2
[2] = p2
[3] = 0;
863 const char *ptype
= ucbit
? "(QU)" : "(QM)";
864 if (srcport
.NotAnInteger
== MulticastDNSPort
.NotAnInteger
) NumQuestions
++;
865 else { NumLegacy
++; ptype
= "(LQ)"; }
866 mprintf("%#-16a %-5s %-5s %##s\n", srcaddr
, ptype
, DNSTypeName(q
.qtype
), q
.qname
.c
);
867 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) recordstat(entry
, &q
.qname
, OP_query
, q
.qtype
);
871 for (i
=0; i
<msg
->h
.numAnswers
; i
++)
873 const mDNSu8
*ep
= ptr
;
874 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
875 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "KNOWN ANSWER"); return; }
876 DisplayResourceRecord(srcaddr
, "(KA)", &pkt
.r
.resrec
);
878 // In the case of queries with long multi-packet KA lists, we count each subsequent KA packet
879 // the same as a single query, to more accurately reflect the burden on the network
880 // (A query with a six-packet KA list is *at least* six times the burden on the network as a single-packet query.)
881 if (msg
->h
.numQuestions
== 0 && i
== 0)
882 recordstat(entry
, pkt
.r
.resrec
.name
, OP_query
, pkt
.r
.resrec
.rrtype
);
885 for (i
=0; i
<msg
->h
.numAuthorities
; i
++)
887 const mDNSu8
*ep
= ptr
;
888 ptr
= skipResourceRecord(msg
, ptr
, end
);
889 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "AUTHORITY"); return; }
892 if (entry
) AnalyseHost(m
, entry
, InterfaceID
);
895 mDNSlocal
void DisplayResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
,
896 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, const mDNSInterfaceID InterfaceID
)
899 const mDNSu8
*ptr
= msg
->data
;
900 HostEntry
*entry
= GotPacketFromHost(srcaddr
, HostPkt_R
, msg
->h
.id
);
901 LargeCacheRecord pkt
;
903 DisplayPacketHeader(m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
904 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) NumPktR
++;
906 for (i
=0; i
<msg
->h
.numQuestions
; i
++)
909 const mDNSu8
*ep
= ptr
;
910 ptr
= getQuestion(msg
, ptr
, end
, InterfaceID
, &q
);
911 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "QUESTION"); return; }
912 if (mDNSAddrIsDNSMulticast(dstaddr
))
913 mprintf("%#-16a (?) **** ERROR: SHOULD NOT HAVE Q IN mDNS RESPONSE **** %-5s %##s\n", srcaddr
, DNSTypeName(q
.qtype
), q
.qname
.c
);
915 mprintf("%#-16a (Q) %-5s %##s\n", srcaddr
, DNSTypeName(q
.qtype
), q
.qname
.c
);
918 for (i
=0; i
<msg
->h
.numAnswers
; i
++)
920 const mDNSu8
*ep
= ptr
;
921 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
922 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "ANSWER"); return; }
923 if (pkt
.r
.resrec
.rroriginalttl
)
926 DisplayResourceRecord(srcaddr
, (pkt
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "(AN)" : "(AN+)", &pkt
.r
.resrec
);
927 if (msg
->h
.id
.NotAnInteger
!= 0xFFFF) recordstat(entry
, pkt
.r
.resrec
.name
, OP_answer
, pkt
.r
.resrec
.rrtype
);
928 if (entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
933 DisplayResourceRecord(srcaddr
, "(DE)", &pkt
.r
.resrec
);
934 recordstat(entry
, pkt
.r
.resrec
.name
, OP_goodbye
, pkt
.r
.resrec
.rrtype
);
938 for (i
=0; i
<msg
->h
.numAuthorities
; i
++)
940 const mDNSu8
*ep
= ptr
;
941 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAuth
, &pkt
);
942 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "AUTHORITY"); return; }
943 mprintf("%#-16a (?) **** ERROR: SHOULD NOT HAVE AUTHORITY IN mDNS RESPONSE **** %-5s %##s\n",
944 srcaddr
, DNSTypeName(pkt
.r
.resrec
.rrtype
), pkt
.r
.resrec
.name
->c
);
947 for (i
=0; i
<msg
->h
.numAdditionals
; i
++)
949 const mDNSu8
*ep
= ptr
;
950 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAdd
, &pkt
);
951 if (!ptr
) { DisplayError(srcaddr
, ep
, end
, "ADDITIONAL"); return; }
953 DisplayResourceRecord(srcaddr
, (pkt
.r
.resrec
.RecordType
& kDNSRecordTypePacketUniqueMask
) ? "(AD)" : "(AD+)", &pkt
.r
.resrec
);
954 if (entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
957 if (entry
) AnalyseHost(m
, entry
, InterfaceID
);
960 mDNSlocal
void ProcessUnicastResponse(mDNS
*const m
, const DNSMessage
*const msg
, const mDNSu8
*end
, const mDNSAddr
*srcaddr
, const mDNSInterfaceID InterfaceID
)
963 const mDNSu8
*ptr
= LocateAnswers(msg
, end
);
964 HostEntry
*entry
= GotPacketFromHost(srcaddr
, HostPkt_R
, msg
->h
.id
);
965 //mprintf("%#a R\n", srcaddr);
967 for (i
=0; i
<msg
->h
.numAnswers
+ msg
->h
.numAuthorities
+ msg
->h
.numAdditionals
; i
++)
969 LargeCacheRecord pkt
;
970 ptr
= GetLargeResourceRecord(m
, msg
, ptr
, end
, InterfaceID
, kDNSRecordTypePacketAns
, &pkt
);
971 if (pkt
.r
.resrec
.rroriginalttl
&& entry
) RecordHostInfo(entry
, &pkt
.r
.resrec
);
975 mDNSlocal mDNSBool
AddressMatchesFilterList(const mDNSAddr
*srcaddr
)
978 if (!Filters
) return(srcaddr
->type
== mDNSAddrType_IPv4
);
979 for (f
=Filters
; f
; f
=f
->next
) if (mDNSSameAddress(srcaddr
, &f
->FilterAddr
)) return(mDNStrue
);
983 mDNSexport
void mDNSCoreReceive(mDNS
*const m
, DNSMessage
*const msg
, const mDNSu8
*const end
,
984 const mDNSAddr
*srcaddr
, mDNSIPPort srcport
, const mDNSAddr
*dstaddr
, mDNSIPPort dstport
, const mDNSInterfaceID InterfaceID
)
986 const mDNSu8 StdQ
= kDNSFlag0_QR_Query
| kDNSFlag0_OP_StdQuery
;
987 const mDNSu8 StdR
= kDNSFlag0_QR_Response
| kDNSFlag0_OP_StdQuery
;
988 const mDNSu8 QR_OP
= (mDNSu8
)(msg
->h
.flags
.b
[0] & kDNSFlag0_QROP_Mask
);
989 mDNSu8
*ptr
= (mDNSu8
*)&msg
->h
.numQuestions
;
991 (void)dstaddr
; // Unused
992 (void)dstport
; // Unused
994 // Read the integer parts which are in IETF byte-order (MSB first, LSB second)
995 msg
->h
.numQuestions
= (mDNSu16
)((mDNSu16
)ptr
[0] << 8 | ptr
[1]);
996 msg
->h
.numAnswers
= (mDNSu16
)((mDNSu16
)ptr
[2] << 8 | ptr
[3]);
997 msg
->h
.numAuthorities
= (mDNSu16
)((mDNSu16
)ptr
[4] << 8 | ptr
[5]);
998 msg
->h
.numAdditionals
= (mDNSu16
)((mDNSu16
)ptr
[6] << 8 | ptr
[7]);
1000 // For now we're only interested in monitoring IPv4 traffic.
1001 // All IPv6 packets should just be duplicates of the v4 packets.
1002 if (AddressMatchesFilterList(srcaddr
))
1005 if (!mDNSAddrIsDNSMulticast(dstaddr
))
1007 if (QR_OP
== StdQ
) mprintf("Unicast query from %#a\n", srcaddr
);
1008 else if (QR_OP
== StdR
) ProcessUnicastResponse(m
, msg
, end
, srcaddr
, InterfaceID
);
1012 if (QR_OP
== StdQ
) DisplayQuery (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
1013 else if (QR_OP
== StdR
) DisplayResponse (m
, msg
, end
, srcaddr
, srcport
, dstaddr
, InterfaceID
);
1016 debugf("Unknown DNS packet type %02X%02X (ignored)", msg
->h
.flags
.b
[0], msg
->h
.flags
.b
[1]);
1017 GotPacketFromHost(srcaddr
, HostPkt_B
, msg
->h
.id
);
1025 mDNSlocal mStatus
mDNSNetMonitor(void)
1028 int h
, m
, s
, mul
, div
, TotPkt
;
1031 mStatus status
= mDNS_Init(&mDNSStorage
, &PlatformStorage
,
1032 mDNS_Init_NoCache
, mDNS_Init_ZeroCacheSize
,
1033 mDNS_Init_DontAdvertiseLocalAddresses
,
1034 mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
1035 if (status
) return(status
);
1037 gettimeofday(&tv_start
, NULL
);
1038 mDNSPosixListenForSignalInEventLoop(SIGINT
);
1039 mDNSPosixListenForSignalInEventLoop(SIGTERM
);
1043 struct timeval timeout
= { 0x3FFFFFFF, 0 }; // wait until SIGINT or SIGTERM
1044 mDNSBool gotSomething
;
1045 mDNSPosixRunEventLoopOnce(&mDNSStorage
, &timeout
, &signals
, &gotSomething
);
1047 while ( !( sigismember( &signals
, SIGINT
) || sigismember( &signals
, SIGTERM
)));
1049 // Now display final summary
1050 TotPkt
= NumPktQ
+ NumPktL
+ NumPktR
;
1051 gettimeofday(&tv_end
, NULL
);
1052 tv_interval
= tv_end
;
1053 if (tv_start
.tv_usec
> tv_interval
.tv_usec
)
1054 { tv_interval
.tv_usec
+= 1000000; tv_interval
.tv_sec
--; }
1055 tv_interval
.tv_sec
-= tv_start
.tv_sec
;
1056 tv_interval
.tv_usec
-= tv_start
.tv_usec
;
1057 h
= (tv_interval
.tv_sec
/ 3600);
1058 m
= (tv_interval
.tv_sec
% 3600) / 60;
1059 s
= (tv_interval
.tv_sec
% 60);
1060 if (tv_interval
.tv_sec
> 10)
1063 div
= tv_interval
.tv_sec
;
1068 div
= tv_interval
.tv_sec
* 1000 + tv_interval
.tv_usec
/ 1000;
1069 if (div
== 0) div
=1;
1073 localtime_r((time_t*)&tv_start
.tv_sec
, &tm
);
1074 mprintf("Started %3d:%02d:%02d.%06d\n", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, tv_start
.tv_usec
);
1075 localtime_r((time_t*)&tv_end
.tv_sec
, &tm
);
1076 mprintf("End %3d:%02d:%02d.%06d\n", tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, tv_end
.tv_usec
);
1077 mprintf("Captured for %3d:%02d:%02d.%06d\n", h
, m
, s
, tv_interval
.tv_usec
);
1078 if (!Filters
) mprintf("Unique source addresses seen on network: %ld\n", IPv4HostList
.num
+ IPv6HostList
.num
);
1080 mprintf("Modern Query Packets: %7d (avg%5d/min)\n", NumPktQ
, NumPktQ
* mul
/ div
);
1081 mprintf("Legacy Query Packets: %7d (avg%5d/min)\n", NumPktL
, NumPktL
* mul
/ div
);
1082 mprintf("Multicast Response Packets: %7d (avg%5d/min)\n", NumPktR
, NumPktR
* mul
/ div
);
1083 mprintf("Total Multicast Packets: %7d (avg%5d/min)\n", TotPkt
, TotPkt
* mul
/ div
);
1085 mprintf("Total New Service Probes: %7d (avg%5d/min)\n", NumProbes
, NumProbes
* mul
/ div
);
1086 mprintf("Total Goodbye Announcements: %7d (avg%5d/min)\n", NumGoodbyes
, NumGoodbyes
* mul
/ div
);
1087 mprintf("Total Query Questions: %7d (avg%5d/min)\n", NumQuestions
, NumQuestions
* mul
/ div
);
1088 mprintf("Total Queries from Legacy Clients:%7d (avg%5d/min)\n", NumLegacy
, NumLegacy
* mul
/ div
);
1089 mprintf("Total Answers/Announcements: %7d (avg%5d/min)\n", NumAnswers
, NumAnswers
* mul
/ div
);
1090 mprintf("Total Additional Records: %7d (avg%5d/min)\n", NumAdditionals
, NumAdditionals
* mul
/ div
);
1092 printstats(kReportTopServices
);
1094 if (!ExactlyOneFilter
)
1096 ShowSortedHostList(&IPv4HostList
, kReportTopHosts
);
1097 ShowSortedHostList(&IPv6HostList
, kReportTopHosts
);
1100 mDNS_Close(&mDNSStorage
);
1104 mDNSexport
int main(int argc
, char **argv
)
1106 const char *progname
= strrchr(argv
[0], '/') ? strrchr(argv
[0], '/') + 1 : argv
[0];
1110 setlinebuf(stdout
); // Want to see lines as they appear, not block buffered
1112 for (i
=1; i
<argc
; i
++)
1118 a
.type
= mDNSAddrType_IPv4
;
1120 if (inet_pton(AF_INET
, argv
[i
], &s4
) == 1)
1121 a
.ip
.v4
.NotAnInteger
= s4
.s_addr
;
1122 else if (inet_pton(AF_INET6
, argv
[i
], &s6
) == 1)
1124 a
.type
= mDNSAddrType_IPv6
;
1125 bcopy(&s6
, &a
.ip
.v6
, sizeof(a
.ip
.v6
));
1129 struct hostent
*h
= gethostbyname(argv
[i
]);
1130 if (h
) a
.ip
.v4
.NotAnInteger
= *(long*)h
->h_addr
;
1134 f
= malloc(sizeof(*f
));
1140 status
= mDNSNetMonitor();
1141 if (status
) { fprintf(stderr
, "%s: mDNSNetMonitor failed %ld\n", progname
, status
); return(status
); }
1145 fprintf(stderr
, "\nmDNS traffic monitor\n");
1146 fprintf(stderr
, "Usage: %s (<host>)\n", progname
);
1147 fprintf(stderr
, "Optional <host> parameter displays only packets from that host\n");
1149 fprintf(stderr
, "\nPer-packet header output:\n");
1150 fprintf(stderr
, "-Q- Multicast Query from mDNS client that accepts multicast responses\n");
1151 fprintf(stderr
, "-R- Multicast Response packet containing answers/announcements\n");
1152 fprintf(stderr
, "-LQ- Multicast Query from legacy client that does *not* listen for multicast responses\n");
1153 fprintf(stderr
, "Q/Ans/Auth/Add Number of questions, answers, authority records and additional records in packet\n");
1155 fprintf(stderr
, "\nPer-record display:\n");
1156 fprintf(stderr
, "(PM) Probe Question (new service starting), requesting multicast response\n");
1157 fprintf(stderr
, "(PU) Probe Question (new service starting), requesting unicast response\n");
1158 fprintf(stderr
, "(DE) Deletion/Goodbye (service going away)\n");
1159 fprintf(stderr
, "(LQ) Legacy Query Question\n");
1160 fprintf(stderr
, "(QM) Query Question, requesting multicast response\n");
1161 fprintf(stderr
, "(QU) Query Question, requesting unicast response\n");
1162 fprintf(stderr
, "(KA) Known Answer (information querier already knows)\n");
1163 fprintf(stderr
, "(AN) Unique Answer to question (or periodic announcment) (entire RR Set)\n");
1164 fprintf(stderr
, "(AN+) Answer to question (or periodic announcment) (add to existing RR Set members)\n");
1165 fprintf(stderr
, "(AD) Unique Additional Record Set (entire RR Set)\n");
1166 fprintf(stderr
, "(AD+) Additional records (add to existing RR Set members)\n");
1168 fprintf(stderr
, "\nFinal summary, sorted by service type:\n");
1169 fprintf(stderr
, "Probe Probes for this service type starting up\n");
1170 fprintf(stderr
, "Goodbye Goodbye (deletion) packets for this service type shutting down\n");
1171 fprintf(stderr
, "BrowseQ Browse questions from clients browsing to find a list of instances of this service\n");
1172 fprintf(stderr
, "BrowseA Browse answers/announcments advertising instances of this service\n");
1173 fprintf(stderr
, "ResolveQ Resolve questions from clients actively connecting to an instance of this service\n");
1174 fprintf(stderr
, "ResolveA Resolve answers/announcments giving connection information for an instance of this service\n");
1175 fprintf(stderr
, "\n");