147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt/* -*- Mode: C; tab-width: 4 -*-
247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Licensed under the Apache License, Version 2.0 (the "License");
647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * you may not use this file except in compliance with the License.
747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * You may obtain a copy of the License at
847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *     http://www.apache.org/licenses/LICENSE-2.0
1047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
1147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Unless required by applicable law or agreed to in writing, software
1247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * distributed under the License is distributed on an "AS IS" BASIS,
1347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * See the License for the specific language governing permissions and
1547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * limitations under the License.
1647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt *
1747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Formatting notes:
1847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * This code follows the "Whitesmiths style" C indentation rules. Plenty of discussion
1947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * on C indentation can be found on the web, such as <http://www.kafejo.com/komp/1tbs.htm>,
2047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * but for the sake of brevity here I will say just this: Curly braces are not syntactially
2147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * part of an "if" statement; they are the beginning and ending markers of a compound statement;
2247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * therefore common sense dictates that if they are part of a compound statement then they
2347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * should be indented to the same level as everything else in that compound statement.
2447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * Indenting curly braces at the same level as the "if" implies that curly braces are
2547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * part of the "if", which is false. (This is as misleading as people who write "char* x,y;"
2647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * thinking that variables x and y are both of type "char*" -- and anyone who doesn't
2747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * understand why variable y is not of type "char*" just proves the point that poor code
2847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt * layout leads people to unfortunate misunderstandings about how the C language really works.)
2947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt */
3047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
3147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
3247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Incorporate mDNS.c functionality
3347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
3447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// We want to use much of the functionality provided by "mDNS.c",
3547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// except we'll steal the packets that would be sent to normal mDNSCoreReceive() routine
3647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define mDNSCoreReceive __NOT__mDNSCoreReceive__NOT__
3747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "mDNS.c"
3847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#undef mDNSCoreReceive
3947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
4147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Headers
4247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
4347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdio.h>			// For printf()
4447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <stdlib.h>			// For malloc()
4547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <string.h>			// For strrchr(), strcmp()
4647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <time.h>			// For "struct tm" etc.
4747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include <signal.h>			// For SIGINT, SIGTERM
4847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(WIN32)
4947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Both mDNS.c and mDNSWin32.h declare UDPSocket_struct type resulting in a compile-time error, so
5047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// trick the compiler when including mDNSWin32.h
5147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	define UDPSocket_struct _UDPSocket_struct
5247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <mDNSEmbeddedAPI.h>
5347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <mDNSWin32.h>
5447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <PosixCompat.h>
5547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	define IFNAMSIZ 256
5647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic HANDLE gStopEvent = INVALID_HANDLE_VALUE;
5747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic BOOL WINAPI ConsoleControlHandler( DWORD inControlEvent ) { SetEvent( gStopEvent ); return TRUE; }
5847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltvoid setlinebuf( FILE * fp ) {}
5947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#else
6047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <netdb.h>			// For gethostbyname()
6147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <sys/socket.h>		// For AF_INET, AF_INET6, etc.
6247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <net/if.h>			// For IF_NAMESIZE
6347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <netinet/in.h>		// For INADDR_NONE
6447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include <arpa/inet.h>		// For inet_addr()
6547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#	include "mDNSPosix.h"      // Defines the specific types needed to run mDNS on this platform
6647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
6747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#include "ExampleClientApp.h"
6847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
6947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
7047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Types and structures
7147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltenum
7347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
7447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Primitive operations
7547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_probe        = 0,
7647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_goodbye      = 1,
7747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
7847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// These are meta-categories;
7947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Query and Answer operations are actually subdivided into two classes:
8047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Browse  query/answer and
8147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Resolve query/answer
8247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_query        = 2,
8347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_answer       = 3,
8447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
8547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// The "Browse" variants of query/answer
8647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_browsegroup  = 2,
8747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_browseq      = 2,
8847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_browsea      = 3,
8947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// The "Resolve" variants of query/answer
9147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_resolvegroup = 4,
9247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_resolveq     = 4,
9347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_resolvea     = 5,
9447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	OP_NumTypes = 6
9647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	};
9747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
9847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct ActivityStat_struct ActivityStat;
9947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct ActivityStat_struct
10047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
10147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ActivityStat *next;
10247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname srvtype;
10347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int printed;
10447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int totalops;
10547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int stat[OP_NumTypes];
10647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	};
10747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
10847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct FilterList_struct FilterList;
10947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct FilterList_struct
11047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
11147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FilterList *next;
11247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSAddr FilterAddr;
11347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	};
11447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
11647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Constants
11747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
11847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kReportTopServices 15
11947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define kReportTopHosts    15
12047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
12247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Globals
12347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNS mDNSStorage;						// mDNS core uses this to store its globals
12547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic mDNS_PlatformSupport PlatformStorage;	// Stores this platform's globals
12647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport const char ProgramName[] = "mDNSNetMonitor";
12747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
12847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstruct timeval tv_start, tv_end, tv_interval;
12947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic int FilterInterface = 0;
13047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic FilterList *Filters;
13147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define ExactlyOneFilter (Filters && !Filters->next)
13247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
13347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic int NumPktQ, NumPktL, NumPktR, NumPktB;	// Query/Legacy/Response/Bad
13447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic int NumProbes, NumGoodbyes, NumQuestions, NumLegacy, NumAnswers, NumAdditionals;
13547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
13647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic ActivityStat *stats;
13747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
13847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define OPBanner "Total Ops   Probe   Goodbye  BrowseQ  BrowseA ResolveQ ResolveA"
13947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
14047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
14147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Utilities
14247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
14347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Special version of printf that knows how to print IP addresses, DNS-format name strings, etc.
14447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 mprintf(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
14547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSu32 mprintf(const char *format, ...)
14647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
14747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32 length;
14847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned char buffer[512];
14947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_list ptr;
15047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_start(ptr,format);
15147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	length = mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr);
15247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	va_end(ptr);
15347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	printf("%s", buffer);
15447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(length);
15547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
15647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
15747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
15847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Host Address List
15947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//
16047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Would benefit from a hash
16147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
16247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef enum
16347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
16447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostPkt_Q        = 0,		// Query
16547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostPkt_L        = 1,		// Legacy Query
16647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostPkt_R        = 2,		// Response
16747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostPkt_B        = 3,		// Bad
16847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostPkt_NumTypes = 4
16947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} HostPkt_Type;
17047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
17147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct
17247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
17347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSAddr addr;
17447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned long pkts[HostPkt_NumTypes];
17547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned long totalops;
17647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	unsigned long stat[OP_NumTypes];
17747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname hostname;
17847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname revname;
17947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	UTF8str255 HIHardware;
18047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	UTF8str255 HISoftware;
18147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu32    NumQueries;
18247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSs32    LastQuery;
18347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} HostEntry;
18447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#define HostEntryTotalPackets(H) ((H)->pkts[HostPkt_Q] + (H)->pkts[HostPkt_L] + (H)->pkts[HostPkt_R] + (H)->pkts[HostPkt_B])
18647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
18747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalttypedef struct
18847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
18947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	long		num;
19047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	long		max;
19147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostEntry	*hosts;
19247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	} HostList;
19347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
19447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic HostList IPv4HostList = { 0, 0, 0 };
19547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltstatic HostList IPv6HostList = { 0, 0, 0 };
19647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
19747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal HostEntry *FindHost(const mDNSAddr *addr, HostList *list)
19847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
19947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	long	i;
20047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < list->num; i++)
20247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
20347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		HostEntry *entry = list->hosts + i;
20447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (mDNSSameAddress(addr, &entry->addr))
20547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return entry;
20647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
20747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
20847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return NULL;
20947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
21047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
21147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal HostEntry *AddHost(const mDNSAddr *addr, HostList *list)
21247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
21347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
21447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostEntry *entry;
21547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (list->num >= list->max)
21647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
21747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		long newMax = list->max + 64;
21847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		HostEntry *newHosts = realloc(list->hosts, newMax * sizeof(HostEntry));
21947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (newHosts == NULL)
22047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			return NULL;
22147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		list->max = newMax;
22247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		list->hosts = newHosts;
22347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
22447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
22547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry = list->hosts + list->num++;
22647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
22747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->addr = *addr;
22847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<HostPkt_NumTypes; i++) entry->pkts[i] = 0;
22947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->totalops = 0;
23047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<OP_NumTypes;      i++) entry->stat[i] = 0;
23147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->hostname.c[0] = 0;
23247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->revname.c[0] = 0;
23347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->HIHardware.c[0] = 0;
23447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->HISoftware.c[0] = 0;
23547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->NumQueries = 0;
23647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
23747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (entry->addr.type == mDNSAddrType_IPv4)
23847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
23947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSv4Addr ip = entry->addr.ip.v4;
24047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		char buffer[32];
24147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Note: This is reverse order compared to a normal dotted-decimal IP address, so we can't use our customary "%.4a" format code
24247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d.in-addr.arpa.", ip.b[3], ip.b[2], ip.b[1], ip.b[0]);
24347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		MakeDomainNameFromDNSNameString(&entry->revname, buffer);
24447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
24547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
24647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(entry);
24747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
24847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
24947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal HostEntry *GotPacketFromHost(const mDNSAddr *addr, HostPkt_Type t, mDNSOpaque16 id)
25047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
25147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (ExactlyOneFilter) return(NULL);
25247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
25347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
25447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		HostList *list = (addr->type == mDNSAddrType_IPv4) ? &IPv4HostList : &IPv6HostList;
25547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		HostEntry *entry = FindHost(addr, list);
25647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!entry) entry = AddHost(addr, list);
25747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!entry) return(NULL);
25847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// Don't count our own interrogation packets
25947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (id.NotAnInteger != 0xFFFF) entry->pkts[t]++;
26047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		return(entry);
26147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
26247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
26347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
26447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void RecordHostInfo(HostEntry *entry, const ResourceRecord *const pktrr)
26547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
26647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!entry->hostname.c[0])
26747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
26847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (pktrr->rrtype == kDNSType_A || pktrr->rrtype == kDNSType_AAAA)
26947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
27047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// Should really check that the rdata in the address record matches the source address of this packet
27147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			entry->NumQueries = 0;
27247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			AssignDomainName(&entry->hostname, pktrr->name);
27347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
27447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
27547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (pktrr->rrtype == kDNSType_PTR)
27647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (SameDomainName(&entry->revname, pktrr->name))
27747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
27847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				entry->NumQueries = 0;
27947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				AssignDomainName(&entry->hostname, &pktrr->rdata->u.name);
28047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
28147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
28247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (pktrr->rrtype == kDNSType_HINFO)
28347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
28447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		RDataBody *rd = &pktrr->rdata->u;
28547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *rdend = (mDNSu8 *)rd + pktrr->rdlength;
28647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *hw = rd->txt.c;
28747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *sw = hw + 1 + (mDNSu32)hw[0];
28847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (sw + 1 + sw[0] <= rdend)
28947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
29047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			AssignDomainName(&entry->hostname, pktrr->name);
29147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSPlatformMemCopy(entry->HIHardware.c, hw, 1 + (mDNSu32)hw[0]);
29247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSPlatformMemCopy(entry->HISoftware.c, sw, 1 + (mDNSu32)sw[0]);
29347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
29447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
29547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
29647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
29747e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *name, mDNSu16 rrtype, mDNSInterfaceID InterfaceID)
29847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
29947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSOpaque16 id = { { 0xFF, 0xFF } };
30047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSMessage query;
30147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8       *qptr        = query.data;
30247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *const limit = query.data + sizeof(query.data);
30347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSAddr *target    = &entry->addr;
30447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	InitializeDNSMessage(&query.h, id, QueryFlags);
30547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	qptr = putQuestion(&query, qptr, limit, name, rrtype, kDNSClass_IN);
30647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->LastQuery = m->timenow;
30747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	entry->NumQueries++;
30847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
30947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Note: When there are multiple mDNSResponder agents running on a single machine
31047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// (e.g. Apple mDNSResponder plus a SliMP3 server with embedded mDNSResponder)
31147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// it is possible that unicast queries may not go to the primary system responder.
31247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// We try the first query using unicast, but if that doesn't work we try again via multicast.
31347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (entry->NumQueries > 2)
31447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
31547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		target = &AllDNSLinkGroup_v4;
31647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
31747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
31847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
31947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		//mprintf("%#a Q\n", target);
32047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		InterfaceID = mDNSInterface_Any;	// Send query from our unicast reply socket
32147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
32247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
32347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSSendDNSMessage(&mDNSStorage, &query, qptr, InterfaceID, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSNULL);
32447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
32547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
32647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
32747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
32847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If we've done four queries without answer, give up
32947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (entry->NumQueries >= 4) return;
33047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If we've done a query in the last second, give the host a chance to reply before trying again
33247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (entry->NumQueries && m->timenow - entry->LastQuery < mDNSPlatformOneSecond) return;
33347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
33447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If we don't know the host name, try to find that first
33547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!entry->hostname.c[0])
33647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
33747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (entry->revname.c[0])
33847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
33947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			SendUnicastQuery(m, entry, &entry->revname, kDNSType_PTR, InterfaceID);
34047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			//mprintf("%##s PTR %d\n", entry->revname.c, entry->NumQueries);
34147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
34247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
34347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// If we have the host name but no HINFO, now ask for that
34447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else if (!entry->HIHardware.c[0])
34547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
34647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		SendUnicastQuery(m, entry, &entry->hostname, kDNSType_HINFO, InterfaceID);
34747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		//mprintf("%##s HINFO %d\n", entry->hostname.c, entry->NumQueries);
34847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
34947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
35047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal int CompareHosts(const void *p1, const void *p2)
35247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
35347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return (int)(HostEntryTotalPackets((HostEntry *)p2) - HostEntryTotalPackets((HostEntry *)p1));
35447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
35547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
35647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ShowSortedHostList(HostList *list, int max)
35747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
35847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostEntry *e, *end = &list->hosts[(max < list->num) ? max : list->num];
35947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	qsort(list->hosts, list->num, sizeof(HostEntry), CompareHosts);
36047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (list->num) mprintf("\n%-25s%s%s\n", "Source Address", OPBanner, "    Pkts    Query   LegacyQ Response");
36147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (e = &list->hosts[0]; e < end; e++)
36247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
36347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int len = mprintf("%#-25a", &e->addr);
36447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (len > 25) mprintf("\n%25s", "");
36547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf("%8lu %8lu %8lu %8lu %8lu %8lu %8lu", e->totalops,
36647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			e->stat[OP_probe], e->stat[OP_goodbye],
36747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			e->stat[OP_browseq], e->stat[OP_browsea],
36847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			e->stat[OP_resolveq], e->stat[OP_resolvea]);
36947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf(" %8lu %8lu %8lu %8lu",
37047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			HostEntryTotalPackets(e), e->pkts[HostPkt_Q], e->pkts[HostPkt_L], e->pkts[HostPkt_R]);
37147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (e->pkts[HostPkt_B]) mprintf("Bad: %8lu", e->pkts[HostPkt_B]);
37247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf("\n");
37347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!e->HISoftware.c[0] && e->NumQueries > 2)
37447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSPlatformMemCopy(&e->HISoftware, "\x27*** Unknown (Jaguar, Windows, etc.) ***", 0x28);
37547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (e->hostname.c[0] || e->HIHardware.c[0] || e->HISoftware.c[0])
37647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mprintf("%##-45s %#-14s %#s\n", e->hostname.c, e->HIHardware.c, e->HISoftware.c);
37747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
37847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
37947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt//*************************************************************************************************************
38147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt// Receive and process packets
38247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport mDNSBool ExtractServiceType(const domainname *const fqdn, domainname *const srvtype)
38447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
38547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i, len;
38647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *src = fqdn->c;
38747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *dst = srvtype->c;
38847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
38947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
39047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len == 0 || len >= 0x40) return(mDNSfalse);
39147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (src[1] != '_') src += 1 + len;
39247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
39447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len == 0 || len >= 0x40 || src[1] != '_') return(mDNSfalse);
39547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=len; i++) *dst++ = *src++;
39647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
39747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	len = *src;
39847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (len == 0 || len >= 0x40 || src[1] != '_') return(mDNSfalse);
39947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<=len; i++) *dst++ = *src++;
40047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
40147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	*dst++ = 0;		// Put the null root label on the end of the service type
40247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
40347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNStrue);
40447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
40547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
40647e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void recordstat(HostEntry *entry, const domainname *fqdn, int op, mDNSu16 rrtype)
40747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
40847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	ActivityStat **s = &stats;
40947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	domainname srvtype;
41047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
41147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (op != OP_probe)
41247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
41347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (rrtype == kDNSType_SRV || rrtype == kDNSType_TXT) op = op - OP_browsegroup + OP_resolvegroup;
41447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else if (rrtype != kDNSType_PTR) return;
41547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
41647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
41747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ExtractServiceType(fqdn, &srvtype)) return;
41847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
41947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (*s && !SameDomainName(&(*s)->srvtype, &srvtype)) s = &(*s)->next;
42047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!*s)
42147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
42247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int i;
42347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		*s = malloc(sizeof(ActivityStat));
42447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!*s) exit(-1);
42547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		(*s)->next     = NULL;
42647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		(*s)->srvtype  = srvtype;
42747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		(*s)->printed  = 0;
42847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		(*s)->totalops = 0;
42947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (i=0; i<OP_NumTypes; i++) (*s)->stat[i] = 0;
43047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
43147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
43247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(*s)->totalops++;
43347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(*s)->stat[op]++;
43447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (entry)
43547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
43647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		entry->totalops++;
43747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		entry->stat[op]++;
43847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
43947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
44047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
44147e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void printstats(int max)
44247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
44347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
44447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!stats) return;
44547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<max; i++)
44647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
44747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int max = 0;
44847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ActivityStat *s, *m = NULL;
44947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (s = stats; s; s=s->next)
45047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (!s->printed && max < s->totalops)
45147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{ m = s; max = s->totalops; }
45247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!m) return;
45347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		m->printed = mDNStrue;
45447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (i==0) mprintf("%-25s%s\n", "Service Type", OPBanner);
45547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf("%##-25s%8d %8d %8d %8d %8d %8d %8d\n", m->srvtype.c, m->totalops, m->stat[OP_probe],
45647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			m->stat[OP_goodbye], m->stat[OP_browseq], m->stat[OP_browsea], m->stat[OP_resolveq], m->stat[OP_resolvea]);
45747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
45847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
45947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
46047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal const mDNSu8 *FindUpdate(mDNS *const m, const DNSMessage *const query, const mDNSu8 *ptr, const mDNSu8 *const end,
46147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DNSQuestion *q, LargeCacheRecord *pkt)
46247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
46347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
46447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i = 0; i < query->h.numAuthorities; i++)
46547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
46647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *p2 = ptr;
46747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, pkt);
46847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) break;
46947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&pkt->r.resrec, q)) return(p2);
47047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
47147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSNULL);
47247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
47347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47447e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DisplayPacketHeader(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSInterfaceID InterfaceID)
47547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
47647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const char *const ptype =   (msg->h.flags.b[0] & kDNSFlag0_QR_Response)             ? "-R- " :
47747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								(srcport.NotAnInteger == MulticastDNSPort.NotAnInteger) ? "-Q- " : "-LQ-";
47847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
47947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct timeval tv;
48047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct tm tm;
48147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu32 index = mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNSfalse);
48247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char if_name[IFNAMSIZ];		// Older Linux distributions don't define IF_NAMESIZE
48347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if_indextoname(index, if_name);
48447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gettimeofday(&tv, NULL);
48547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	localtime_r((time_t*)&tv.tv_sec, &tm);
48647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	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);
48747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
48847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("%#-16a %s             Q:%3d  Ans:%3d  Auth:%3d  Add:%3d  Size:%5d bytes",
48947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		srcaddr, ptype, msg->h.numQuestions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, end - (mDNSu8 *)msg);
49047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (msg->h.id.NotAnInteger) mprintf("  ID:%u", mDNSVal16(msg->h.id));
49247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!mDNSAddrIsDNSMulticast(dstaddr)) mprintf("   To: %#a", dstaddr);
49447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
49547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (msg->h.flags.b[0] & kDNSFlag0_TC)
49647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
49747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (msg->h.flags.b[0] & kDNSFlag0_QR_Response) mprintf("   Truncated");
49847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else                                           mprintf("   Truncated (KA list continues in next packet)");
49947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
50047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("\n");
50147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
50247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
50347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *const op, const ResourceRecord *const pktrr)
50447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
50547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	static const char hexchars[16] = "0123456789ABCDEF";
50647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	#define MaxWidth 132
50747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char buffer[MaxWidth+8];
50847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	char *p = buffer;
50947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
51047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	RDataBody *rd = &pktrr->rdata->u;
51147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *rdend = (mDNSu8 *)rd + pktrr->rdlength;
51247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int n = mprintf("%#-16a %-5s %-5s%5lu %##s -> ", srcaddr, op, DNSTypeName(pktrr->rrtype), pktrr->rroriginalttl, pktrr->name->c);
51347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
51447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (pktrr->RecordType == kDNSRecordTypePacketNegative) { mprintf("**** ERROR: FAILED TO READ RDATA ****\n"); return; }
51547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
51647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// The kDNSType_OPT case below just calls GetRRDisplayString_rdb
51747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Perhaps more (or all?) of the cases should do that?
51847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	switch(pktrr->rrtype)
51947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
52047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_A:	n += mprintf("%.4a", &rd->ipv4); break;
52147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_PTR:	n += mprintf("%##.*s", MaxWidth - n, rd->name.c); break;
52247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_HINFO:// same as kDNSType_TXT below
52347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_TXT:	{
52447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSu8 *t = rd->txt.c;
52547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							while (t < rdend && t[0] && p < buffer+MaxWidth)
52647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
52747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								int i;
52847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								for (i=1; i<=t[0] && p < buffer+MaxWidth; i++)
52947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
53047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									if (t[i] == '\\') *p++ = '\\';
53147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									if (t[i] >= ' ') *p++ = t[i];
53247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									else
53347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										{
53447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										*p++ = '\\';
53547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										*p++ = '0';
53647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										*p++ = 'x';
53747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										*p++ = hexchars[t[i] >> 4];
53847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										*p++ = hexchars[t[i] & 0xF];
53947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt										}
54047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
54147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								t += 1+t[0];
54247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (t < rdend && t[0]) { *p++ = '\\'; *p++ = ' '; }
54347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
54447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*p++ = 0;
54547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							n += mprintf("%.*s", MaxWidth - n, buffer);
54647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							} break;
54747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_AAAA:	n += mprintf("%.16a", &rd->ipv6); break;
54847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_SRV:	n += mprintf("%##s:%d", rd->srv.target.c, mDNSVal16(rd->srv.port)); break;
54947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_OPT:	{
55047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							char b[MaxMsg];
55147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// Quick hack: we don't want the prefix that GetRRDisplayString_rdb puts at the start of its
55247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// string, because it duplicates the name and rrtype we already display, so we compute the
55347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							// length of that prefix and strip that many bytes off the beginning of the string we display.
55447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSu32 striplen = mDNS_snprintf(b, MaxMsg-1, "%4d %##s %s ", pktrr->rdlength, pktrr->name->c, DNSTypeName(pktrr->rrtype));
55547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							GetRRDisplayString_rdb(pktrr, &pktrr->rdata->u, b);
55647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							n += mprintf("%.*s", MaxWidth - n, b + striplen);
55747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							} break;
55847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		case kDNSType_NSEC:	{
55947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							int i;
56047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							for (i=0; i<255; i++)
56147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (rd->nsec.bitmap[i>>3] & (128 >> (i&7)))
56247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									n += mprintf("%s ", DNSTypeName(i));
56347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							} break;
56447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		default:			{
56547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							mDNSu8 *s = rd->data;
56647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							while (s < rdend && p < buffer+MaxWidth)
56747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								{
56847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (*s == '\\') *p++ = '\\';
56947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								if (*s >= ' ') *p++ = *s;
57047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								else
57147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									{
57247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									*p++ = '\\';
57347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									*p++ = '0';
57447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									*p++ = 'x';
57547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									*p++ = hexchars[*s >> 4];
57647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									*p++ = hexchars[*s & 0xF];
57747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt									}
57847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								s++;
57947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt								}
58047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							*p++ = 0;
58147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							n += mprintf("%.*s", MaxWidth - n, buffer);
58247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt							} break;
58347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
58447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
58547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("\n");
58647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
58747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
58847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void HexDump(const mDNSu8 *ptr, const mDNSu8 *const end)
58947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
59047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (ptr < end)
59147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
59247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		int i;
59347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (i=0; i<16; i++)
59447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (&ptr[i] < end) mprintf("%02X ", ptr[i]);
59547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else mprintf("   ");
59647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		for (i=0; i<16; i++)
59747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (&ptr[i] < end) mprintf("%c", ptr[i] <= ' ' || ptr[i] >= 126 ? '.' : ptr[i]);
59847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr += 16;
59947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf("\n");
60047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
60147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
60247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
60347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DisplayError(const mDNSAddr *srcaddr, const mDNSu8 *ptr, const mDNSu8 *const end, char *msg)
60447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
60547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("%#-16a **** ERROR: FAILED TO READ %s **** \n", srcaddr, msg);
60647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HexDump(ptr, end);
60747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
60847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
60947e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DisplayQuery(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end,
61047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSInterfaceID InterfaceID)
61147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
61247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
61347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = msg->data;
61447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *auth = LocateAuthorities(msg, end);
61547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSBool MQ = (srcport.NotAnInteger == MulticastDNSPort.NotAnInteger);
61647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostEntry *entry = GotPacketFromHost(srcaddr, MQ ? HostPkt_Q : HostPkt_L, msg->h.id);
61747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LargeCacheRecord pkt;
61847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
61947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DisplayPacketHeader(m, msg, end, srcaddr, srcport, dstaddr, InterfaceID);
62047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (msg->h.id.NotAnInteger != 0xFFFF)
62147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
62247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (MQ) NumPktQ++; else NumPktL++;
62347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
62447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
62547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numQuestions; i++)
62647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
62747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DNSQuestion q;
62847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu8 *p2 = (mDNSu8 *)getQuestion(msg, ptr, end, InterfaceID, &q);
62947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSu16 ucbit = q.qclass & kDNSQClass_UnicastResponse;
63047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		q.qclass &= ~kDNSQClass_UnicastResponse;
63147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!p2) { DisplayError(srcaddr, ptr, end, "QUESTION"); return; }
63247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = p2;
63347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		p2 = (mDNSu8 *)FindUpdate(m, msg, auth, end, &q, &pkt);
63447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (p2)
63547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
63647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			NumProbes++;
63747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			DisplayResourceRecord(srcaddr, ucbit ? "(PU)" : "(PM)", &pkt.r.resrec);
63847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			recordstat(entry, &q.qname, OP_probe, q.qtype);
63947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			p2 = (mDNSu8 *)skipDomainName(msg, p2, end);
64047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			// Having displayed this update record, clear type and class so we don't display the same one again.
64147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			p2[0] = p2[1] = p2[2] = p2[3] = 0;
64247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
64347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
64447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
64547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			const char *ptype = ucbit ? "(QU)" : "(QM)";
64647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (srcport.NotAnInteger == MulticastDNSPort.NotAnInteger) NumQuestions++;
64747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else { NumLegacy++; ptype = "(LQ)"; }
64847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mprintf("%#-16a %-5s %-5s      %##s\n", srcaddr, ptype, DNSTypeName(q.qtype), q.qname.c);
64947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (msg->h.id.NotAnInteger != 0xFFFF) recordstat(entry, &q.qname, OP_query, q.qtype);
65047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
65147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
65247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
65347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numAnswers; i++)
65447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
65547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ep = ptr;
65647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
65747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { DisplayError(srcaddr, ep, end, "KNOWN ANSWER"); return; }
65847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DisplayResourceRecord(srcaddr, "(KA)", &pkt.r.resrec);
65947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// In the case of queries with long multi-packet KA lists, we count each subsequent KA packet
66147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// the same as a single query, to more accurately reflect the burden on the network
66247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// (A query with a six-packet KA list is *at least* six times the burden on the network as a single-packet query.)
66347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (msg->h.numQuestions == 0 && i == 0)
66447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			recordstat(entry, pkt.r.resrec.name, OP_query, pkt.r.resrec.rrtype);
66547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
66647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
66747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numAuthorities; i++)
66847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
66947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ep = ptr;
67047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &pkt);
67147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { DisplayError(srcaddr, ep, end, "AUTHORITY"); return; }
67247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// After we display an Update record with its matching question (above) we zero out its type and class
67347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		// If any remain that haven't been zero'd out, display them here
67447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (pkt.r.resrec.rrtype || pkt.r.resrec.rrclass) DisplayResourceRecord(srcaddr, "(AU)", &pkt.r.resrec);
67547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
67647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
67747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numAdditionals; i++)
67847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
67947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ep = ptr;
68047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &pkt);
68147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { DisplayError(srcaddr, ep, end, "ADDITIONAL"); return; }
68247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DisplayResourceRecord(srcaddr, pkt.r.resrec.rrtype == kDNSType_OPT ? "(OP)" : "(AD)", &pkt.r.resrec);
68347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
68447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (entry) AnalyseHost(m, entry, InterfaceID);
68647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
68747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
68847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void DisplayResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end,
68947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, const mDNSInterfaceID InterfaceID)
69047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
69147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
69247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = msg->data;
69347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostEntry *entry = GotPacketFromHost(srcaddr, HostPkt_R, msg->h.id);
69447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	LargeCacheRecord pkt;
69547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
69647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	DisplayPacketHeader(m, msg, end, srcaddr, srcport, dstaddr, InterfaceID);
69747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (msg->h.id.NotAnInteger != 0xFFFF) NumPktR++;
69847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
69947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numQuestions; i++)
70047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
70147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DNSQuestion q;
70247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ep = ptr;
70347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = getQuestion(msg, ptr, end, InterfaceID, &q);
70447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { DisplayError(srcaddr, ep, end, "QUESTION"); return; }
70547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (mDNSAddrIsDNSMulticast(dstaddr))
70647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mprintf("%#-16a (?)   **** ERROR: SHOULD NOT HAVE Q IN mDNS RESPONSE **** %-5s %##s\n", srcaddr, DNSTypeName(q.qtype), q.qname.c);
70747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
70847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mprintf("%#-16a (Q)   %-5s      %##s\n", srcaddr, DNSTypeName(q.qtype), q.qname.c);
70947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
71047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
71147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numAnswers; i++)
71247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
71347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ep = ptr;
71447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
71547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { DisplayError(srcaddr, ep, end, "ANSWER"); return; }
71647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (pkt.r.resrec.rroriginalttl)
71747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
71847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			NumAnswers++;
71947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			DisplayResourceRecord(srcaddr, (pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "(AN)" : "(AN+)", &pkt.r.resrec);
72047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (msg->h.id.NotAnInteger != 0xFFFF) recordstat(entry, pkt.r.resrec.name, OP_answer, pkt.r.resrec.rrtype);
72147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (entry) RecordHostInfo(entry, &pkt.r.resrec);
72247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
72347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
72447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
72547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			NumGoodbyes++;
72647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			DisplayResourceRecord(srcaddr, "(DE)", &pkt.r.resrec);
72747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			recordstat(entry, pkt.r.resrec.name, OP_goodbye, pkt.r.resrec.rrtype);
72847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
72947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
73047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
73147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numAuthorities; i++)
73247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
73347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ep = ptr;
73447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAuth, &pkt);
73547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { DisplayError(srcaddr, ep, end, "AUTHORITY"); return; }
73647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf("%#-16a (?)  **** ERROR: SHOULD NOT HAVE AUTHORITY IN mDNS RESPONSE **** %-5s %##s\n",
73747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			srcaddr, DNSTypeName(pkt.r.resrec.rrtype), pkt.r.resrec.name->c);
73847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
73947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
74047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numAdditionals; i++)
74147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
74247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		const mDNSu8 *ep = ptr;
74347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAdd, &pkt);
74447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!ptr) { DisplayError(srcaddr, ep, end, "ADDITIONAL"); return; }
74547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		NumAdditionals++;
74647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DisplayResourceRecord(srcaddr,
74747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			pkt.r.resrec.rrtype == kDNSType_OPT ? "(OP)" : (pkt.r.resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? "(AD)" : "(AD+)",
74847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			&pkt.r.resrec);
74947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (entry) RecordHostInfo(entry, &pkt.r.resrec);
75047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
75147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
75247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (entry) AnalyseHost(m, entry, InterfaceID);
75347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
75447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
75547e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal void ProcessUnicastResponse(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *end, const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID)
75647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
75747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
75847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 *ptr = LocateAnswers(msg, end);
75947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HostEntry *entry = GotPacketFromHost(srcaddr, HostPkt_R, msg->h.id);
76047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	//mprintf("%#a R\n", srcaddr);
76147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
76247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=0; i<msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals; i++)
76347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
76447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		LargeCacheRecord pkt;
76547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ptr = GetLargeResourceRecord(m, msg, ptr, end, InterfaceID, kDNSRecordTypePacketAns, &pkt);
76647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (ptr && pkt.r.resrec.rroriginalttl && entry) RecordHostInfo(entry, &pkt.r.resrec);
76747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
76847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
76947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
77047e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mDNSBool AddressMatchesFilterList(const mDNSAddr *srcaddr)
77147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
77247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	FilterList *f;
77347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!Filters) return(srcaddr->type == mDNSAddrType_IPv4);
77447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (f=Filters; f; f=f->next) if (mDNSSameAddress(srcaddr, &f->FilterAddr)) return(mDNStrue);
77547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(mDNSfalse);
77647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
77747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
77847e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
77947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSAddr *srcaddr, mDNSIPPort srcport, const mDNSAddr *dstaddr, mDNSIPPort dstport, const mDNSInterfaceID InterfaceID)
78047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
78147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 StdQ = kDNSFlag0_QR_Query    | kDNSFlag0_OP_StdQuery;
78247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 StdR = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery;
78347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const mDNSu8 QR_OP = (mDNSu8)(msg->h.flags.b[0] & kDNSFlag0_QROP_Mask);
78447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSu8 *ptr = (mDNSu8 *)&msg->h.numQuestions;
78547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int goodinterface = (FilterInterface == 0);
78647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
78747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(void)dstaddr;	// Unused
78847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	(void)dstport;	// Unused
78947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
79047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Read the integer parts which are in IETF byte-order (MSB first, LSB second)
79147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.numQuestions   = (mDNSu16)((mDNSu16)ptr[0] <<  8 | ptr[1]);
79247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.numAnswers     = (mDNSu16)((mDNSu16)ptr[2] <<  8 | ptr[3]);
79347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.numAuthorities = (mDNSu16)((mDNSu16)ptr[4] <<  8 | ptr[5]);
79447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	msg->h.numAdditionals = (mDNSu16)((mDNSu16)ptr[6] <<  8 | ptr[7]);
79547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
79647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// For now we're only interested in monitoring IPv4 traffic.
79747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// All IPv6 packets should just be duplicates of the v4 packets.
79847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!goodinterface) goodinterface = (FilterInterface == (int)mDNSPlatformInterfaceIndexfromInterfaceID(m, InterfaceID, mDNSfalse));
79947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (goodinterface && AddressMatchesFilterList(srcaddr))
80047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
80147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Lock(m);
80247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!mDNSAddrIsDNSMulticast(dstaddr))
80347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
80447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if      (QR_OP == StdQ) mprintf("Unicast query from %#a\n", srcaddr);
80547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else if (QR_OP == StdR) ProcessUnicastResponse(m, msg, end, srcaddr,                   InterfaceID);
80647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
80747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
80847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
80947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if      (QR_OP == StdQ) DisplayQuery          (m, msg, end, srcaddr, srcport, dstaddr, InterfaceID);
81047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else if (QR_OP == StdR) DisplayResponse       (m, msg, end, srcaddr, srcport, dstaddr, InterfaceID);
81147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
81247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
81347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				debugf("Unknown DNS packet type %02X%02X (ignored)", msg->h.flags.b[0], msg->h.flags.b[1]);
81447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				GotPacketFromHost(srcaddr, HostPkt_B, msg->h.id);
81547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				NumPktB++;
81647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
81747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
81847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Unlock(m);
81947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
82047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
82147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
82247e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSlocal mStatus mDNSNetMonitor(void)
82347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
82447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	struct tm tm;
82547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int h, m, s, mul, div, TotPkt;
82647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if !defined(WIN32)
82747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	sigset_t signals;
82847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
82947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
83047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus status = mDNS_Init(&mDNSStorage, &PlatformStorage,
83147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Init_NoCache, mDNS_Init_ZeroCacheSize,
83247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Init_DontAdvertiseLocalAddresses,
83347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext);
83447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (status) return(status);
83547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
83647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gettimeofday(&tv_start, NULL);
83747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
83847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined( WIN32 )
83947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	status = SetupInterfaceList(&mDNSStorage);
84047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (status) return(status);
84147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
84247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (gStopEvent == INVALID_HANDLE_VALUE) return mStatus_UnknownErr;
84347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!SetConsoleCtrlHandler(ConsoleControlHandler, TRUE)) return mStatus_UnknownErr;
84447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while (WaitForSingleObjectEx(gStopEvent, INFINITE, TRUE) == WAIT_IO_COMPLETION)
84547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		DispatchSocketEvents(&mDNSStorage);
84647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!SetConsoleCtrlHandler(ConsoleControlHandler, FALSE)) return mStatus_UnknownErr;
84747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	CloseHandle(gStopEvent);
84847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#else
84947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPosixListenForSignalInEventLoop(SIGINT);
85047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNSPosixListenForSignalInEventLoop(SIGTERM);
85147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
85247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	do
85347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
85447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		struct timeval	timeout = { 0x3FFFFFFF, 0 };	// wait until SIGINT or SIGTERM
85547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSBool		gotSomething;
85647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mDNSPosixRunEventLoopOnce(&mDNSStorage, &timeout, &signals, &gotSomething);
85747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
85847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	while ( !( sigismember( &signals, SIGINT) || sigismember( &signals, SIGTERM)));
85947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
86047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
86147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	// Now display final summary
86247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	TotPkt = NumPktQ + NumPktL + NumPktR;
86347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	gettimeofday(&tv_end, NULL);
86447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	tv_interval = tv_end;
86547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (tv_start.tv_usec > tv_interval.tv_usec)
86647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{ tv_interval.tv_usec += 1000000; tv_interval.tv_sec--; }
86747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	tv_interval.tv_sec  -= tv_start.tv_sec;
86847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	tv_interval.tv_usec -= tv_start.tv_usec;
86947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	h = (tv_interval.tv_sec / 3600);
87047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	m = (tv_interval.tv_sec % 3600) / 60;
87147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	s = (tv_interval.tv_sec % 60);
87247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (tv_interval.tv_sec > 10)
87347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
87447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mul = 60;
87547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		div = tv_interval.tv_sec;
87647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
87747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	else
87847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
87947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mul = 60000;
88047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		div = tv_interval.tv_sec * 1000 + tv_interval.tv_usec / 1000;
88147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (div == 0) div=1;
88247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
88347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
88447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("\n\n");
88547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	localtime_r((time_t*)&tv_start.tv_sec, &tm);
88647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Started      %3d:%02d:%02d.%06d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tv_start.tv_usec);
88747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	localtime_r((time_t*)&tv_end.tv_sec, &tm);
88847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("End          %3d:%02d:%02d.%06d\n", tm.tm_hour, tm.tm_min, tm.tm_sec, tv_end.tv_usec);
88947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Captured for %3d:%02d:%02d.%06d\n", h, m, s, tv_interval.tv_usec);
89047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!Filters)
89147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
89247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf("Unique source addresses seen on network:");
89347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (IPv4HostList.num) mprintf(" %ld (IPv4)", IPv4HostList.num);
89447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (IPv6HostList.num) mprintf(" %ld (IPv6)", IPv6HostList.num);
89547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (!IPv4HostList.num && !IPv6HostList.num) mprintf(" None");
89647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		mprintf("\n");
89747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
89847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("\n");
89947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Modern Query        Packets:      %7d   (avg%5d/min)\n", NumPktQ,        NumPktQ        * mul / div);
90047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Legacy Query        Packets:      %7d   (avg%5d/min)\n", NumPktL,        NumPktL        * mul / div);
90147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Multicast Response  Packets:      %7d   (avg%5d/min)\n", NumPktR,        NumPktR        * mul / div);
90247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Total     Multicast Packets:      %7d   (avg%5d/min)\n", TotPkt,         TotPkt         * mul / div);
90347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("\n");
90447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Total New Service Probes:         %7d   (avg%5d/min)\n", NumProbes,      NumProbes      * mul / div);
90547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Total Goodbye Announcements:      %7d   (avg%5d/min)\n", NumGoodbyes,    NumGoodbyes    * mul / div);
90647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Total Query Questions:            %7d   (avg%5d/min)\n", NumQuestions,   NumQuestions   * mul / div);
90747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Total Queries from Legacy Clients:%7d   (avg%5d/min)\n", NumLegacy,      NumLegacy      * mul / div);
90847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Total Answers/Announcements:      %7d   (avg%5d/min)\n", NumAnswers,     NumAnswers     * mul / div);
90947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("Total Additional Records:         %7d   (avg%5d/min)\n", NumAdditionals, NumAdditionals * mul / div);
91047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mprintf("\n");
91147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	printstats(kReportTopServices);
91247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
91347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (!ExactlyOneFilter)
91447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
91547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ShowSortedHostList(&IPv4HostList, kReportTopHosts);
91647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		ShowSortedHostList(&IPv6HostList, kReportTopHosts);
91747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
91847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
91947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mDNS_Close(&mDNSStorage);
92047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(0);
92147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
92247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
92347e4cebad7397422144bb03a21f3f7682c062c4aRobert GreenwaltmDNSexport int main(int argc, char **argv)
92447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	{
92547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	const char *progname = strrchr(argv[0], '/') ? strrchr(argv[0], '/') + 1 : argv[0];
92647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	int i;
92747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	mStatus status;
92847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
92947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#if defined(WIN32)
93047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
93147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt#endif
93247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
93347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	setlinebuf(stdout);				// Want to see lines as they appear, not block buffered
93447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
93547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	for (i=1; i<argc; i++)
93647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		{
93747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		if (i+1 < argc && !strcmp(argv[i], "-i") && atoi(argv[i+1]))
93847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
93947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			FilterInterface = atoi(argv[i+1]);
94047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			i += 2;
94147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			printf("Monitoring interface %d\n", FilterInterface);
94247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
94347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		else
94447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			{
94547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			struct in_addr s4;
94647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			struct in6_addr s6;
94747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			FilterList *f;
94847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			mDNSAddr a;
94947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			a.type = mDNSAddrType_IPv4;
95047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
95147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			if (inet_pton(AF_INET, argv[i], &s4) == 1)
95247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				a.ip.v4.NotAnInteger = s4.s_addr;
95347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else if (inet_pton(AF_INET6, argv[i], &s6) == 1)
95447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
95547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				a.type = mDNSAddrType_IPv6;
95647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				mDNSPlatformMemCopy(&a.ip.v6, &s6, sizeof(a.ip.v6));
95747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
95847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			else
95947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				{
96047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				struct hostent *h = gethostbyname(argv[i]);
96147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				if (h) a.ip.v4.NotAnInteger = *(long*)h->h_addr;
96247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				else goto usage;
96347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt				}
96447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
96547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			f = malloc(sizeof(*f));
96647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			f->FilterAddr = a;
96747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			f->next = Filters;
96847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			Filters = f;
96947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt			}
97047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt		}
97147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
97247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	status = mDNSNetMonitor();
97347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	if (status) { fprintf(stderr, "%s: mDNSNetMonitor failed %d\n", progname, (int)status); return(status); }
97447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(0);
97547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
97647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwaltusage:
97747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "\nmDNS traffic monitor\n");
97847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "Usage: %s [-i index] [host]\n", progname);
97947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "Optional [-i index] parameter displays only packets from that interface index\n");
98047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "Optional [host] parameter displays only packets from that host\n");
98147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "\nPer-packet header output:\n");
98347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "-Q-            Multicast Query from mDNS client that accepts multicast responses\n");
98447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "-R-            Multicast Response packet containing answers/announcements\n");
98547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "-LQ-           Multicast Query from legacy client that does *not* listen for multicast responses\n");
98647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "Q/Ans/Auth/Add Number of questions, answers, authority records and additional records in packet\n");
98747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
98847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "\nPer-record display:\n");
98947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(PM)           Probe Question (new service starting), requesting multicast response\n");
99047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(PU)           Probe Question (new service starting), requesting unicast response\n");
99147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(DE)           Deletion/Goodbye (service going away)\n");
99247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(LQ)           Legacy Query Question\n");
99347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(QM)           Query Question, requesting multicast response\n");
99447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(QU)           Query Question, requesting unicast response\n");
99547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(KA)           Known Answer (information querier already knows)\n");
99647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(AN)           Unique Answer to question (or periodic announcment) (entire RR Set)\n");
99747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(AN+)          Answer to question (or periodic announcment) (add to existing RR Set members)\n");
99847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(AD)           Unique Additional Record Set (entire RR Set)\n");
99947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "(AD+)          Additional records (add to existing RR Set members)\n");
100047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt
100147e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "\nFinal summary, sorted by service type:\n");
100247e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "Probe          Probes for this service type starting up\n");
100347e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "Goodbye        Goodbye (deletion) packets for this service type shutting down\n");
100447e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "BrowseQ        Browse questions from clients browsing to find a list of instances of this service\n");
100547e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "BrowseA        Browse answers/announcments advertising instances of this service\n");
100647e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "ResolveQ       Resolve questions from clients actively connecting to an instance of this service\n");
100747e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "ResolveA       Resolve answers/announcments giving connection information for an instance of this service\n");
100847e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	fprintf(stderr, "\n");
100947e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	return(-1);
101047e4cebad7397422144bb03a21f3f7682c062c4aRobert Greenwalt	}
1011