blob: bda53ba8e8a1bb99eac9e0ca53f2bbf00ec45d22 (
plain) (
tree)
|
|
#! /bin/bash
#
# Copyright (c) 2017-2018 Apple Inc. All rights reserved.
#
# This script is currently for Apple Internal use only.
#
version=1.4
script=${BASH_SOURCE[0]}
dnssdutil=${dnssdutil:-dnssdutil}
#============================================================================================================================
# PrintUsage
#============================================================================================================================
PrintUsage()
{
echo ""
echo "Usage: $( basename "${script}" ) [options]"
echo ""
echo "Options:"
echo " -V Display version of this script and exit."
echo ""
}
#============================================================================================================================
# LogOut
#============================================================================================================================
LogOut()
{
echo "$( date '+%Y-%m-%d %H:%M:%S%z' ): $*"
}
#============================================================================================================================
# LogMsg
#============================================================================================================================
LogMsg()
{
echo "$*"
if [ -d "${workPath}" ]; then
LogOut "$*" >> "${workPath}/log.txt"
fi
}
#============================================================================================================================
# ErrQuit
#============================================================================================================================
ErrQuit()
{
echo "error: $*"
exit 1
}
#============================================================================================================================
# SignalHandler
#============================================================================================================================
SignalHandler()
{
LogMsg "Exiting due to signal."
trap '' SIGINT SIGTERM
pkill -TERM -P $$
wait
exit 2
}
#============================================================================================================================
# ExitHandler
#============================================================================================================================
ExitHandler()
{
if [ -d "${tempPath}" ]; then
rm -fr "${tempPath}"
fi
}
#============================================================================================================================
# RunNetStat
#============================================================================================================================
RunNetStat()
{
LogMsg "Running netstat -g -n -s"
netstat -g -n -s &> "${workPath}/netstat-g-n-s.txt"
}
#============================================================================================================================
# StartPacketCapture
#============================================================================================================================
StartPacketCapture()
{
LogMsg "Starting tcpdump."
tcpdump -n -w "${workPath}/tcpdump.pcapng" &> "${workPath}/tcpdump.txt" &
tcpdumpPID=$!
}
#============================================================================================================================
# SaveExistingPacketCaptures
#============================================================================================================================
SaveExistingPacketCaptures()
{
LogMsg "Saving existing mDNS packet captures."
mkdir "${workPath}/pcaps"
for file in /tmp/mdns-tcpdump.pcapng*; do
[ -e "${file}" ] || continue
baseName=$( sed -E 's/^mdns-tcpdump.pcapng([0-9]+)$/mdns-tcpdump-\1.pcapng/' <<< "$( basename ${file} )" )
gzip < ${file} > "${workPath}/pcaps/${baseName}.gz"
done
}
#============================================================================================================================
# StopPacketCapture
#============================================================================================================================
StopPacketCapture()
{
LogMsg "Stopping tcpdump."
kill -TERM ${tcpdumpPID}
}
#============================================================================================================================
# RunInterfaceMulticastTests
#============================================================================================================================
RunInterfaceMulticastTests()
{
local ifname="$1"
local allHostsV4=224.0.0.1
local allHostsV6=ff02::1
local mDNSV4=224.0.0.251
local mDNSV6=ff02::fb
local serviceList=( $( "${dnssdutil}" queryrecord -i "${ifname}" -A -t ptr -n _services._dns-sd._udp.local -l 6 | sed -E -n 's/.*(_.*_(tcp|udp)\.local\.)$/\1/p' | sort -u ) )
local log="${workPath}/mcast-test-log-${ifname}.txt"
LogOut "List of services: ${serviceList[*]}" >> "${log}"
# Ping All Hosts IPv4 multicast address.
local routeOutput=$( route -n get -ifscope ${ifname} "${allHostsV4}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
LogOut "Pinging "${allHostsV4}" on interface ${ifname}." >> "${log}"
ping -t 5 -b ${ifname} "${allHostsV4}" &> "${workPath}/ping-all-hosts-${ifname}.txt"
else
LogOut "No route to "${allHostsV4}" on interface ${ifname}." >> "${log}"
fi
# Ping mDNS IPv4 multicast address.
routeOutput=$( route -n get -ifscope ${ifname} "${mDNSV4}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
LogOut "Pinging "${mDNSV4}" on interface ${ifname}." >> "${log}"
ping -t 5 -b ${ifname} "${mDNSV4}" &> "${workPath}/ping-mDNS-${ifname}.txt"
else
LogOut "No route to "${mDNSV4}" on interface ${ifname}." >> "${log}"
fi
# Ping All Hosts IPv6 multicast address.
routeOutput=$( route -n get -ifscope ${ifname} -inet6 "${allHostsV6}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
LogOut "Pinging "${allHostsV6}" on interface ${ifname}." >> "${log}"
ping6 -c 6 -I ${ifname} "${allHostsV6}" &> "${workPath}/ping6-all-hosts-${ifname}.txt"
else
LogOut "No route to "${allHostsV6}" on interface ${ifname}." >> "${log}"
fi
# Ping mDNS IPv6 multicast address.
routeOutput=$( route -n get -ifscope ${ifname} -inet6 "${mDNSV6}" 2> /dev/null )
if [ -n "${routeOutput}" ]; then
LogOut "Pinging "${mDNSV6}" on interface ${ifname}." >> "${log}"
ping6 -c 6 -I ${ifname} "${mDNSV6}" &> "${workPath}/ping6-mDNS-${ifname}.txt"
else
LogOut "No route to "${mDNSV6}" on interface ${ifname}." >> "${log}"
fi
# Send mDNS queries for services.
for service in "${serviceList[@]}"; do
LogOut "Sending mDNS queries for "${service}" on interface ${ifname}." >> "${log}"
for(( i = 1; i <= 3; ++i )); do
printf "\n"
"${dnssdutil}" mdnsquery -i "${ifname}" -n "${service}" -t ptr -r 2
printf "\n"
"${dnssdutil}" mdnsquery -i "${ifname}" -n "${service}" -t ptr -r 1 --QU -p 5353
printf "\n"
done >> "${workPath}/mdnsquery-${ifname}.txt" 2>&1
done
}
#============================================================================================================================
# RunMulticastTests
#============================================================================================================================
RunMulticastTests()
{
local interfaces=( $( ifconfig -l -u ) )
local skipPrefixes=( ap awdl bridge ipsec lo p2p pdp_ip pktap UDC utun )
local ifname=""
local pid=""
local pids=()
LogMsg "List of interfaces: ${interfaces[*]}"
for ifname in "${interfaces[@]}"; do
local skip=false
for prefix in ${skipPrefixes[@]}; do
if [[ ${ifname} =~ ^${prefix}[0-9]*$ ]]; then
skip=true
break
fi
done
if [ "${skip}" != "true" ]; then
ifconfig ${ifname} | grep -q inet
if [ $? -ne 0 ]; then
skip=true
fi
fi
if [ "${skip}" == "true" ]; then
continue
fi
LogMsg "Starting interface multicast tests for ${ifname}."
RunInterfaceMulticastTests "${ifname}" & pids+=($!)
done
LogMsg "Waiting for interface multicast tests to complete..."
for pid in "${pids[@]}"; do
wait "${pid}"
done
LogMsg "All interface multicast tests completed."
}
#============================================================================================================================
# RunBrowseTest
#============================================================================================================================
RunBrowseTest()
{
LogMsg "Running dnssdutil browseAll command."
"${dnssdutil}" browseAll -A -d local -b 10 -c 10 &> "${workPath}/browseAll.txt"
}
#============================================================================================================================
# IsMacOS
#============================================================================================================================
IsMacOS()
{
[[ $( sw_vers -productName ) =~ ^Mac\ OS ]]
}
#============================================================================================================================
# ArchiveLogs
#============================================================================================================================
ArchiveLogs()
{
local workdir=$( basename "${workPath}" )
local archivePath="${dstPath}/${workdir}.tar.gz"
LogMsg "Archiving logs."
echo "---"
tar -C "${tempPath}" -czf "${archivePath}" "${workdir}"
if [ -e "${archivePath}" ]; then
echo "Created log archive at ${archivePath}"
echo "*** Please run sysdiagnose NOW. ***"
echo "Attach both the log archive and the sysdiagnose archive to the radar."
if IsMacOS; then
open "${dstPath}"
fi
else
echo "Failed to create archive at ${archivePath}."
fi
echo "---"
}
#============================================================================================================================
# CreateWorkDirName
#============================================================================================================================
CreateWorkDirName()
{
local suffix=""
local productName=$( sw_vers -productName )
if [ -n "${productName}" ]; then
suffix+="_${productName}"
fi
local model=""
if IsMacOS; then
model=$( sysctl -n hw.model )
model=${model//,/-}
else
model=$( gestalt_query -undecorated DeviceName )
fi
if [ -n "${model}" ]; then
suffix+="_${model}"
fi
local buildVersion=$( sw_vers -buildVersion )
if [ -n "${buildVersion}" ]; then
suffix+="_${buildVersion}"
fi
suffix=${suffix//[^A-Za-z0-9._-]/_}
printf "bonjour-mcast-diags_$( date '+%Y.%m.%d_%H-%M-%S%z' )${suffix}"
}
#============================================================================================================================
# main
#============================================================================================================================
main()
{
while getopts ":hV" option; do
case "${option}" in
h)
PrintUsage
exit 0
;;
V)
echo "$( basename "${script}" ) version ${version}"
exit 0
;;
:)
ErrQuit "option '${OPTARG}' requires an argument."
;;
*)
ErrQuit "unknown option '${OPTARG}'."
;;
esac
done
[ "${OPTIND}" -gt "$#" ] || ErrQuit "unexpected argument \""${!OPTIND}"\"."
if IsMacOS; then
if [ "${EUID}" -ne 0 ]; then
echo "Re-launching with sudo"
exec sudo ${script}
fi
dstPath=/var/tmp
else
[ "${EUID}" -eq 0 ] || ErrQuit "$( basename "${script}" ) needs to be run as root."
dstPath=/var/mobile/Library/Logs/CrashReporter
fi
tempPath=$( mktemp -d -q ) || ErrQuit "Failed to make temp directory."
workPath="${tempPath}/$( CreateWorkDirName )"
mkdir "${workPath}" || ErrQuit "Failed to make work directory."
trap SignalHandler SIGINT SIGTERM
trap ExitHandler EXIT
LogMsg "About: $( basename "${script}" ) version ${version} ($( md5 -q ${script} ))."
if [ "${dnssdutil}" != "dnssdutil" ]; then
if [ -x "$( which "${dnssdutil}" )" ]; then
LogMsg "Using $( "${dnssdutil}" -V ) at $( which "${dnssdutil}" )."
else
LogMsg "WARNING: dnssdutil (${dnssdutil}) isn't an executable."
fi
fi
RunNetStat
StartPacketCapture
SaveExistingPacketCaptures
RunBrowseTest
RunMulticastTests
StopPacketCapture
ArchiveLogs
}
main "$@"
|