Skip to content

Instantly share code, notes, and snippets.

@acidprime
Created January 9, 2012 01:00
Show Gist options
  • Save acidprime/1580354 to your computer and use it in GitHub Desktop.
Save acidprime/1580354 to your computer and use it in GitHub Desktop.
Validate Port , Scan a port with stroke from CSV list of servers
#!/bin/bash
# set -xv
# Required commands
declare -x awk="/usr/bin/awk"
declare -x dscl="/usr/bin/dscl"
declare -x defaults="/usr/bin/defaults"
declare -x cat="/bin/cat"
declare -x du="/usr/bin/du"
declare -x id="/usr/bin/id"
declare -x ntpdate="ntpdate"
declare -x scutil="/usr/sbin/scutil"
declare -x perl="/usr/bin/perl"
declare -x ping="/sbin/ping"
declare -x basename="/usr/bin/basename"
declare -x date="/bin/date"
declare -x defaults="/usr/bin/defaults"
declare -x dscl="/usr/bin/dscl"
declare -x find="/usr/bin/find"
declare -x groups="/usr/bin/groups"
declare -x ls="/bin/ls"
declare -x mv="/bin/mv"
declare -x rm="/bin/rm "
declare -x rmdir="/bin/rmdir"
declare -x sudo="/usr/bin/sudo"
declare -x stroke="/Applications/Utilities/Network Utility.app/Contents/Resources/stroke"
# -- Runtime varibles
declare -x REQCMDS="$awk $dscl $deaults $ntpdate $perl $scutil"
declare -x SCRIPT="${0##*/}" ; SCRIPTNAME="${SCRIPT%%\.*}"
declare -x SCRIPTPATH="$0" RUNDIRECTORY="${0%/*}"
declare -x SYSTEMVERSION="/System/Library/CoreServices/SystemVersion.plist"
declare -x OSVER="$("$defaults" read "${SYSTEMVERSION%.plist}" ProductVersion )"
#declare -x CONFIGFILE="${RUNDIRECTORY:?}/${SCRIPTNAME}.conf"
declare -x BUILDVERSION="2009051"
#[ "$EUID" != 0 ] && printf "%s\n" "This script requires root access ($EUID)!" && exit 1
# -- Start the script log
# Set to "VERBOSE" for more logging prior to using -v
declare -x LOGLEVEL="NORMAL" SCRIPTLOG="/Library/Logs/${SCRIPT%%\.*}.log"
declare -i CURRENT_LOG_SIZE="$("$du" -hm "${SCRIPTLOG:?}" |
"$awk" '/^[0-9]/{print $1;exit}')"
if [ ${CURRENT_LOG_SIZE:=0} -gt 50 ] ; then
"$rm" "$SCRIPTLOG"
printf "%s\n" "LOGSIZE:$CURRENT_LOG_SIZE, too large removing"
fi
exec 2>>"${SCRIPTLOG:?}" # Redirect standard error to log file
# Strip any extention from scriptname and log stderr to script log
if [ -n ${SCRIPTLOG:?"The script log has not been specified"} ] ; then
printf "%s\n" \
"STARTED:$SCRIPTNAME:EUID:$EUID:$("$date" +%H:%M:%S): Mac OS X $OSVER:BUILD:$BUILDVERSION" >>"${SCRIPTLOG:?}"
printf "%s\n" "Log file is: ${SCRIPTLOG:?}"
fi
statusMessage() { # Status message function with type and now color!
# Requires SCRIPTLOG STATUS_TYPE=1 STATUS_MESSAGE=2
declare date="${date:="/bin/date"}"
declare DATE="$("$date" -u "+%Y-%m-%d")"
declare STATUS_TYPE="$1" STATUS_MESSAGE="$2"
if [ "$ENABLECOLOR" = "YES" ] ; then
# Background Color
declare REDBG="41" WHITEBG="47" BLACKBG="40"
declare YELLOWBG="43" BLUEBG="44" GREENBG="42"
# Foreground Color
declare BLACKFG="30" WHITEFG="37" YELLOWFG="33"
declare BLUEFG="36" REDFG="31"
declare BOLD="1" NOTBOLD="0"
declare format='\033[%s;%s;%sm%s\033[0m\n'
# "Bold" "Background" "Forground" "Status message"
printf '\033[0m' # Clean up any previous color in the prompt
else
declare format='%s\n'
fi
# Function only seems to work on intel and higher.
showUIDialog(){
statusMessage header "FUNCTION: # $FUNCNAME" ; unset EXITVALUE TRY
"$killall" -HUP "System Events" 2>/dev/null
declare -x UIMESSAGE="$1"
"$osascript" <<EOF
try
with timeout of 0.1 seconds
tell application "System Events"
set UIMESSAGE to (system attribute "UIMESSAGE") as string
activate
display dialog UIMESSAGE with icon 2 giving up after "3600" buttons "Dismiss" default button "Dismiss"
end tell
end timeout
end try
EOF
return 0
} # END showUIDialog()
case "${STATUS_TYPE:?"Error status message with null type"}" in
progress) \
[ -n "$LOGLEVEL" ] &&
printf $format $NOTBOLD $WHITEBG $BLACKFG "PROGRESS:$STATUS_MESSAGE" ;
printf "%s\n" "$DATE:PROGRESS: $STATUS_MESSAGE" >> "${SCRIPTLOG:?}" ;;
# Used for general progress messages, always viewable
notice) \
printf "%s\n" "$DATE:NOTICE:$STATUS_MESSAGE" >> "${SCRIPTLOG:?}" ;
[ -n "$LOGLEVEL" ] &&
printf $format $NOTBOLD $YELLOWBG $BLACKFG "NOTICE :$STATUS_MESSAGE" ;;
# Notifications of non-fatal errors , always viewable
error) \
printf "%s\n\a" "$DATE:ERROR:$STATUS_MESSAGE" >> "${SCRIPTLOG:?}" ;
[ -n "$LOGLEVEL" ] &&
printf $format $NOTBOLD $REDBG $YELLOWFG "ERROR :$STATUS_MESSAGE" ;;
# Errors , always viewable
verbose) \
printf "%s\n" "$DATE:VERBOSE: $STATUS_MESSAGE" >> "${SCRIPTLOG:?}" ;
[ "$LOGLEVEL" = "VERBOSE" ] &&
printf $format $NOTBOLD $WHITEBG $BLACKFG "VERBOSE :$STATUS_MESSAGE" ;;
# All verbose output
header) \
[ "$LOGLEVEL" = "BEBUG" ] &&
printf $format $NOTBOLD $BLUEBG $BLUEFG "VERBOSE :$STATUS_MESSAGE" ;
printf "%s\n" "$DATE:PROGRESS: $STATUS_MESSAGE" >> "${SCRIPTLOG:?}" ;;
# Function and section headers for the script
passed) \
[ -n "$LOGLEVEL" ] &&
printf $format $NOTBOLD $GREENBG $BLACKFG "SANITY :$STATUS_MESSAGE" ;
printf "%s\n" "$DATE:SANITY: $STATUS_MESSAGE" >> "${SCRIPTLOG:?}" ;;
# Sanity checks and "good" information
graphical) \
[ "$GUI" = "ENABLED" ] &&
showUIDialog "$STATUS_MESSAGE" ;;
esac
return 0
} # END statusMessage()
die() { # die Function
statusMessage header "FUNCTION: # $FUNCNAME" ; unset EXITVALUE
declare LASTDIETYPE="$1" LAST_MESSAGE="$2" LASTEXIT="$3"
declare LASTDIETYPE="${LASTDIETYPE:="UNTYPED"}"
if [ ${LASTEXIT:="192"} -gt 0 ] ; then
statusMessage error "$LASTDIETYPE :$LAST_MESSAGE:EXIT:$LASTEXIT"
# Print specific error message in red
else
statusMessage verbose "$LASTDIETYPE :$LAST_MESSAGE:EXIT:$LASTEXIT"
# Print specific error message in white
fi
statusMessage verbose "COMPLETED:$SCRIPT IN $SECONDS SECONDS"
"$killall" "System Events"
exit "${LASTEXIT}" # Exit with last status or 192 if none.
return 1 # Should never get here
} # END die()
cleanUp() { # -- Clean up of our inportant sessions variables and functions.
statusMessage header "FUNCTION: # $FUNCNAME" ; unset EXITVALUE
statusMessage verbose "TIME: $SCRIPT ran in $SECONDS seconds"
unset -f ${!check*}
[ "${ENABLECOLOR:-"ENABLECOLOR"}" = "YES" ] && printf '\033[0m' # Clear Color
if [ "$PPID" == 1 ] ; then # LaunchD is always PID 1 in 10.4+
: # Future LaunchD code
fi
exec 2>&- # Reset the error redirects
return 0
} # END cleanUp()
# Check script options
statusMessage header "GETOPTS: Processing script $# options:$@"
# ABOVE: Check to see if we are running as a postflight script,the installer creates $SCRIPT_NAME
[ $# = 0 ] && statusMessage verbose "No options given"
# If we are not running postflight and no parameters given, print usage to stderr and exit status 1
while getopts vDCup:f: SWITCH ; do
case $SWITCH in
v ) export LOGLEVEL="VERBOSE" ;;
C ) export ENABLECOLOR="YES" ;;
D ) export LOGLEVEL="DEBUG" ;;
u ) export GUI="ENABLED" ;;
p ) export PORT="$OPTARG" ;;
f ) export CSV_FILE="$OPTARG" ;;
esac
done # END getopts
checkCommands() { # CHECK_CMDS Required Commands installed check using the REQCMDS varible.
declare -i FUNCSECONDS="$SECONDS" # Capture start time
statusMessage header "FUNCTION: # ${FUNCNAME}" ; unset EXITVALUE
declare REQCMDS="$1"
for RQCMD in ${REQCMDS:?} ; do
if [ -x "$RQCMD" ] ; then
statusMessage passed "PASSED: $RQCMD is executable"
else
# Export the command Name to the die status message can refernce it"
export RQCMD ; return 1
fi
done
return 0
declare -i FUNCTIME=$(( ${SECONDS:?} - ${FUNCSECONDS:?} ))
[ "${FUNCTIME:?}" != 0 ] &&
statusMessage verbose "TIME:$FUNCNAME:Took $FUNCTIME seconds to EXIT:$EXITVALUE"
} # END checkCommands()
checkSystemVersion() {
# CHECK_OS Read the /Sys*/Lib*/CoreSer*/S*Version.plist value for OS version
statusMessage header "FUNCTION: # ${FUNCNAME}" ; unset EXITVALUE
declare OSVER="$1"
case "${OSVER:?}" in
10.0* | 10.1* | 10.2* | 10.3* | 10.4*) \
die ERROR "$FUNCNAME: Unsupported OS version: $OSVER." 192 ;;
10.5*) \
statusMessage passed "CHECK_OS: OS check: $OSVER successful!";
return 0;;
10.6*) \
die ERROR "$FUNCNAME:$LINENO Unsupported OS:$OSVER is too new." 192 ;;
*) \
die ERROR "CHECK_OS:$LINENO Unsupported OS:$OSVER unknown error" 192 ;;
esac
return 1
} # END checkSystemVersion()
checkHostReachable(){
statusMessage header "FUNCTION: # $FUNCNAME" ; unset EXITVALUE TRY
declare HOSTTOCHECK="$1"
declare -i FTIMEOUT="$2"
declare -i FUNCSECONDS="$SECONDS" # Capture start time
declare scutil="${scutil:="/usr/sbin/scutil"}" awk="${awk:="/usr/bin/awk"}"
# Begin specfic host check
until "$scutil" -r "${HOSTTOCHECK:?}" |
"$awk" 'BEGIN { FS=","}
$1~/^Reachable/{
if ( $3 == "Connection Required")
{ exit 1 }
# scutil can test if a conneciton is required i.e VPN or PPP
else if ( $2 == "Connection Required" )
{ exit 1 }
# scutil can test if a conneciton is required i.e VPN or PPP
else if ( $1 == "Reachable" )
{ exit 0 }
}
$1~/^Not Reachable/{
if ( $1 == "Not Reachable" )
{ exit 1 }}'
do # Parse the scutil output for checking if the host is reachable
# I wish apple would check their exit statuses so this could be used outside
declare CURRENT_RETRY=$((${FTIMEOUT} - ${TRY:-0}))
statusMessage notice "Waiting for $HOSTTOCHECK to become Reachable RETRY:$CURRENT_RETRY"
let "TRY++" # Add one to the TRY, status message acutally set it 0 for us above.
"$sleep" 1
if [ "${TRY:?}" == "${FTIMEOUT:?}" ] ; then
statusMessage error "Timed out waiting for $HOSTTOCHECK"
return 1
fi
done
statusMessage passed "CHECK: $HOSTTOCHECK is Reachable using DNS or IP"
return 0
} # END checkHostReachable()
checkLineEndings(){
declare -i FUNCSECONDS="$SECONDS" # Capture start time
declare FILE_TO_CHECK="$1"
statusMessage header "FUNCTION: # ${FUNCNAME}" ; unset EXITVALUE
if [ -f "$FILE_TO_CHECK" ] ; then
if ! $perl -ne "exit 1 if m/\r\n/;" "$FILE_TO_CHECK" ; then
statusMessage notice \
"Incorrect line endings detected (probobly due to Mircosoft edit)"
statusMessage notice \
"Backup: $CSV_FILE.bak"
$cp -f "$FILE_TO_CHECK" "$FILE_TO_CHECK".bak
statusMessage verbose 'Resetting line endings \r/\n/ to \n'
$perl -i -pe 's/\r/\n/g' "$FILE_TO_CHECK"
elif ! $perl -ne "exit 1 if m/\r/;" "$FILE_TO_CHECK" ; then
statusMessage notice \
"Incorrect line endings detected (DOS?) fixing backup: $FILE_TO_CHECK.bak"
$cp -f "$FILE_TO_CHECK" "$FILE_TO_CHECK".bak
statusMessage verbose 'Resetting line endings \r/\n/'
$perl -i -pe 's/\r/\n/g' "$FILE_TO_CHECK"
fi
else
statusMessage error "File: $FILE_TO_CHECK does not exist"
die ERROR "Invalid file specified: $FILE_TO_CHECK"
fi
statusMessage verbose "TIME:$FUNCNAME:Took $FUNCTIME seconds to EXIT:$EXITVALUE"
}
checkSystemVersion "${OSVER}"
statusMessage verbose "Using file: $CSV_FILE"
checkLineEndings "$CSV_FILE"
OLDIFS="$IFS"
IFS=$'\n'
for LINE in `$cat "$CSV_FILE"` ; do
let LINE_NUM++
if [ $LINE_NUM -eq 1 ] ; then
statusMessage progress "Skipping first line:$(echo "$LINE" | $awk '{print substr($0)}')"
continue
fi
SERVER_HOSTNAME="$(printf "%s" "$LINE" | $awk -F',' '{print $4}')"
SERVER_IP="$(printf "%s" "$LINE" | $awk -F',' '{print $5}')"
statusMessage notice "Scanning port range ${PORT:?} ${PORT:?} on $SERVER_HOSTNAME($SERVER_IP)"
if checkHostReachable "${SERVER_HOSTNAME:-null}" 10 ; then
if $ping -c 1 "$SERVER_HOSTNAME" &>/dev/null ; then
declare -ix PORT_CHECK="$($stroke "${SERVER_HOSTNAME:?}" $PORT $PORT |
$awk '/Open/{seen++}END{print seen}')"
if [ $PORT_CHECK -ge 1 ] ; then
statusMessage passed "OPEN: $SERVER_HOSTNAME:$PORT"
else
statusMessage error "CLOSED: $SERVER_HOSTNAME:$PORT"
fi
else
statusMessage error "$SERVER_HOSTNAME does not respond to pings"
fi
elif checkHostReachable "${SERVER_IP:-null}" 10 ; then
if $ping -c 1 "$SERVER_IP" &>/dev/null ; then
declare -ix PORT_CHECK="$($stroke "${SERVER_IP:?}" $PORT $PORT |
$awk '/Open/{seen++}END{print seen}')"
if [ $PORT_CHECK -ge 1 ] ; then
statusMessage passed "OPEN: $SERVER_IP:$PORT"
else
statusMessage error "CLOSED: $SERVER_IP:$PORT"
fi
else
statusMessage error "$SERVER_HOSTNAME does not respond to pings"
fi
fi
done
OLDIFS="$IFS"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment