check_bro.sh 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. #!/usr/bin/env bash
  2. # Author: Jon Schipp
  3. # Date: 11-08-2013
  4. ########
  5. # Examples:
  6. # 1.) Check status of all Bro workers
  7. # $ ./check_bro.sh -f /usr/local/bro-2.2/bin/broctl -T status
  8. # 2.) Return average packet loss for the 3 named bro workers
  9. # $ ./check_bro.sh -T loss -i "nids0,nids1,nids2"
  10. # 3.) Check average packet loss of all bro workers against warning and critical thresholds i.e > 10% or 20% packet loss.
  11. # $ ./check_bro.sh -T loss -i all -w 10 -c 20
  12. # 4.) Check packet loss percentage for the last most recent interval from Bro's capture_loss.log above 10% loss.
  13. # $ ./check_bro.sh -f /usr/local/bro-2.2/logs/current/capture_loss.log -T capture_loss -c 10
  14. # 5.) Check average packet loss reported by Myricom's SnifferG driver for each Bro node.
  15. # $ ./check_bro.sh -T myricom -i "192.168.1.254,192.168.1.253" -u bro
  16. # Nagios Exit Codes
  17. OK=0
  18. WARNING=1
  19. CRITICAL=2
  20. UNKNOWN=3
  21. # Default location of broctl
  22. # Set this to the proper location if your installation differs or use ``-f''
  23. BROCTL=/usr/local/bro/bin/broctl
  24. # Default location of myri_counters
  25. # Set this to the proper location if your installation differs
  26. MYRI_COUNTERS=/opt/snf/bin/myri_counters
  27. # Default location of capture_loss.log
  28. # Set this to the proper location if your installation differs
  29. CAPTURE_LOG=/usr/local/bro/logs/current/capture_loss.log
  30. usage()
  31. {
  32. cat <<EOF
  33. Check status of Bro and Bro workers.
  34. This script should be run on the Bro manager.
  35. Options:
  36. -c <int> Critical threshold as percent of packet loss
  37. -f <path> Set optional absolute path for broctl, myri_counters, or capture_loss.log (Use as first option)
  38. (def: $BROCTL,
  39. $MYRI_COUNTERS,
  40. $CAPTURE_LOG)
  41. -i <node/worker> Identifier for Bro instance(s). IP, FQDN, or name depending on the check. (sep:, )
  42. -p <name> Print the value of data from Bro e.g. Notice::suppressing or capture_filter
  43. -T <type> Check type, "status/loss/capture_loss/myricom/print"
  44. status - Check status of all Bro workers
  45. loss - Average packet loss by name for a single-
  46. (\`\`-i nids01''), set (\`\`-i "nids01,nids02"), or all workers (\`\`-i all'').
  47. capture_loss - Checks for packet loss in capture_loss.log
  48. myricom - Average Myricom Sniffer driver packet loss by IP or FQDN for a single-
  49. (\`\`-i 192.168.1.1'') or set (\`\`-i "192.168.1.1,192.168.1.2") of Bro nodes
  50. Connects to nodes via SSH (pub-key auth). If username is not root use ``-u''.
  51. print - Print Bro values
  52. -u <user> Username for the myricom check (def: root)
  53. -w <int> Warning threshold as percent of packet loss
  54. Usage: $0 -f /usr/local/bro-dev/bin/brotcl -T status
  55. $0 -f /usr/local/bro-2.2/logs/current/capture_loss.log -T capture_loss -c 20
  56. EOF
  57. }
  58. argcheck() {
  59. # if less than n argument
  60. if [ $ARGC -lt $1 ]; then
  61. echo "Missing arguments! Use \`\`-h'' for help."
  62. exit 1
  63. fi
  64. }
  65. # Initialize variables
  66. CRIT=0
  67. WARN=0
  68. LIST_NODES=0
  69. LOSS_CHECK=0
  70. CAPTURE_LOSS_CHECK=0
  71. STATUS_CHECK=0
  72. PRINT_CHECK=0
  73. MYRI_CHECK=0
  74. MYRI_STATS=0
  75. USER=root
  76. LOSS=0
  77. RECV=0
  78. RUNNING=0
  79. STOPPED=0
  80. CRASHED=0
  81. UNKNOWN_WORKER=0
  82. WORKERS=all
  83. EXCLUDE=none
  84. ARGC=$#
  85. argcheck 1
  86. while getopts "hfc:i:lm:p:T:u:w:" OPTION
  87. do
  88. case $OPTION in
  89. h)
  90. usage
  91. ;;
  92. f)
  93. shift
  94. if [[ $1 == *broctl ]]; then
  95. BROCTL="$1"
  96. elif [[ $1 == *myri_counters ]]; then
  97. MYRI_COUNTERS=$1
  98. elif [[ $1 == *capture_loss.log ]]; then
  99. CAPTURE_LOG=$1
  100. else
  101. echo "File name appears to be incorrect, maybe try setting the approprate variable in $0."
  102. fi
  103. ;;
  104. c)
  105. CHECK_THRESHOLD=1
  106. CRIT="$OPTARG"
  107. ;;
  108. l)
  109. LIST_NODES=1
  110. ;;
  111. i)
  112. if [ $LOSS_CHECK -eq 1 ] && [[ "$OPTARG" == all ]]; then
  113. WORKERS=".*"
  114. elif [ $LOSS_CHECK -eq 1 ]; then
  115. WORKERS=$(echo "$OPTARG" | sed 's/,/:\\|/g')
  116. elif [ $MYRI_CHECK -eq 1 ]; then
  117. NODE=$(echo "$OPTARG" | sed 's/,/ /g')
  118. else
  119. echo "ERROR: Argument is in incorrect format or \`\`-T <type>'' was not specified first"
  120. exit $UNKOWN
  121. fi
  122. ;;
  123. p)
  124. PRINT="$OPTARG"
  125. ;;
  126. T)
  127. if [[ "$OPTARG" == status ]]; then
  128. STATUS_CHECK=1
  129. elif [[ "$OPTARG" == myricom ]]; then
  130. MYRI_CHECK=1
  131. elif [[ "$OPTARG" == loss ]]; then
  132. LOSS_CHECK=1
  133. elif [[ "$OPTARG" == capture_loss ]]; then
  134. CAPTURE_LOSS_CHECK=1
  135. elif [[ "$OPTARG" == print ]]; then
  136. PRINT_CHECK=1
  137. else
  138. echo "Unknown argument type"
  139. exit $UNKNOWN
  140. fi
  141. ;;
  142. u)
  143. USER="$OPTARG"
  144. ;;
  145. w)
  146. WARN="$OPTARG"
  147. ;;
  148. \?)
  149. exit 1
  150. ;;
  151. esac
  152. done
  153. if [ $LOSS_CHECK -eq 1 ] || [ $STATUS_CHECK -eq 1 ] || [ $LIST_NODES -eq 1 ] || [ $PRINT_CHECK -eq 1 ] ; then
  154. if [ ! -f $BROCTL ];
  155. then
  156. echo "ERROR: Broctl has not been found. Update the BROCTL variable in $0 or specify the path with \`\`-f''"
  157. exit 1
  158. fi
  159. fi
  160. if [ $LIST_NODES -eq 1 ]; then
  161. $BROCTL nodes
  162. exit $OK
  163. fi
  164. if [ $LOSS_CHECK -eq 1 ]; then
  165. # Total average packet loss as a percent for specified workers
  166. FLOAT_LOSS=$($BROCTL netstats | grep "$WORKERS" | sed 's/[a-z]*=//g' | awk '{ drop += $4 ; link += $5 } END { printf("%f\n", ((drop/NR) / (link/NR))* 100) }')
  167. LOSS=$(/usr/bin/printf "%d\n" $FLOAT_LOSS 2>/dev/null)
  168. if [ $LOSS -gt $CRIT ] ;then
  169. echo "Average packet loss is: $FLOAT_LOSS"
  170. exit $CRITICAL
  171. elif [ $LOSS -gt $WARN ]; then
  172. echo "Average packet loss is: $FLOAT_LOSS"
  173. exit $WARNING
  174. else
  175. echo "Average packet loss is: $FLOAT_LOSS"
  176. exit $OK
  177. fi
  178. fi
  179. # Check status of Bro workers
  180. if [ $STATUS_CHECK -eq 1 ]; then
  181. # Broctl stderr is whitespace separated and we need to match on entire line
  182. IFS=$'\n'
  183. for line in $($BROCTL status 2>&1 | grep -v 'Name\|waiting\|Getting')
  184. do
  185. NAME=$(echo "$line" | awk '{ print $1 }')
  186. case "$line" in
  187. *stop*)
  188. echo "$NAME has stopped"
  189. STOPPED=$((STOPPED+1))
  190. ;;
  191. *fail*)
  192. echo "$NAME has crashed"
  193. CRASHED=$((CRASHED+1))
  194. ;;
  195. *run*)
  196. echo "$NAME is running"
  197. RUNNING=$((RUNNING+1))
  198. ;;
  199. *)
  200. echo "Unknown status of worker: $NAME"
  201. UNKNOWN_WORKER=$((UNKNOWN_WORKER+1))
  202. ;;
  203. esac
  204. done
  205. if [ $STOPPED -gt 0 ] || [ $CRASHED -gt 0 ] || [ $UNKNOWN_WORKER -gt 0 ]; then
  206. echo "-> $STOPPED stopped workers, $CRASHED crashed workers, $RUNNING running workers, and $UNKNOWN_WORKER workers with an unknown status"
  207. exit $CRITICAL
  208. else
  209. echo "All $RUNNING instances are running!"
  210. exit $OK
  211. fi
  212. fi
  213. if [ $CAPTURE_LOSS_CHECK -eq 1 ]; then
  214. if [ ! -f $CAPTURE_LOG ]; then
  215. echo "capture_loss.log cannot be found, modify CAPTURE_LOG in $0 or use \`\`-f''"
  216. exit $UNKNOWN
  217. fi
  218. INTERVAL=$(awk 'NR == 9 { printf("%d\n", $2) }' $CAPTURE_LOG)
  219. TIME=$(date +"%s")
  220. RECENT=$(echo $((TIME-INTERVAL)))
  221. awk -v recent=$RECENT -v crit=$CRIT -v loss=0 -v threshold=0 '! /^#/ && $1 > recent && $4 > 0 \
  222. {
  223. loss++; decimal=sprintf("%d", $6);
  224. if ( strtonum(decimal) > crit ) {
  225. threshold++
  226. print "Peer: "$3,"\t","Loss:", $6;
  227. }
  228. }
  229. END {
  230. if ( loss >= 1 ) {
  231. print "\n--------------------\n"loss,"instances of loss with",threshold,"exceeding the threshold ("crit"%).";
  232. if ( threshold > 0 ) {
  233. exit 2
  234. }
  235. exit 0
  236. }
  237. else
  238. print "\nNo loss detected"; }' $CAPTURE_LOG
  239. if [ $? -eq 2 ]; then
  240. exit $CRITICAL
  241. else
  242. exit $OK
  243. fi
  244. fi
  245. if [ $PRINT_CHECK -eq 1 ]; then
  246. $BROCTL print $PRINT
  247. exit $OK
  248. fi
  249. if [ $MYRI_CHECK -eq 1 ]; then
  250. LOSS=0
  251. RECV=0
  252. COUNT=0
  253. LOSS_TOT=0
  254. RECV_TOT=0
  255. AVERAGE=0
  256. if [ ! -f $MYRI_COUNTERS ]; then
  257. echo "ERROR: myri_counters has not been found. Update the MYRI_COUNTERS variable in $0 or specify the path with \`\`-f''"
  258. exit $UNKOWN
  259. fi
  260. for node in $NODE
  261. do
  262. MYRI_STATS=$(ssh -l $USER $node $MYRI_COUNTERS | awk -F : '/SNF drop ring full|SNF recv pkts/ { print $2 }' | sed 's/[ \t]*//')
  263. RECV=$(echo $MYRI_STATS | awk '{ print $1 }')
  264. LOSS=$(echo $MYRI_STATS | awk '{ print $2 }')
  265. LOSS_TOT=$((LOSS+LOSS_TOT))
  266. RECV_TOT=$((RECV+RECV_TOT))
  267. COUNT=$((COUNT+1))
  268. echo "$node: Lost $LOSS of $RECV"
  269. done
  270. echo "--------------------"
  271. # Average
  272. FLOAT_LOSS=$(echo "(($LOSS_TOT / $COUNT) / ($RECV_TOT / $COUNT)) * 100" | bc -l)
  273. LOSS=$(/usr/bin/printf "%d\n" $FLOAT_LOSS 2>/dev/null)
  274. if [ $LOSS -gt $CRIT ]; then
  275. echo "Average packet loss is: $FLOAT_LOSS"
  276. exit $CRITICAL
  277. elif [ $LOSS -gt $WARN ]; then
  278. echo "Average packet loss is: $FLOAT_LOSS"
  279. exit $WARNING
  280. else
  281. echo "Average packet loss is: $FLOAT_LOSS"
  282. exit $OK
  283. fi
  284. fi