#!/bin/bash # Copyright (c) 2013 Peter Palfrader # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. set -e set -u usage() { echo "Usage: $0 [] [ ...]" echo "Options:" echo " -a use this authority [$AUTH]" echo " -l log dir [$LOGDIR]" echo " -m send mail when a certificate mismatch is found" echo " -v be a bit verbose" echo " -h print this help" } TORPID="" CHECKDIR="" cleanup() { [ -z "$TORPID" ] || kill "$TORPID" || true [ -z "$CHECKDIR" ] || rm -rf "$CHECKDIR" || true } AUTH=tor.noreply.org PER_RUN=60 DEFAULT_CHECKHOSTS="www.torproject.org" LOGDIR="tor-exit-ssl-check-many.log" CACHEDIR="tor-exit-ssl-check-many.cache" MAIL=0 CHECKDIR=$(mktemp -d "/tmp/cert-check-many-XXXXXX") DUMPFILE="$CHECKDIR/dump" trap 'cleanup' EXIT mkdir -vp "$LOGDIR" mkdir -vp "$CACHEDIR" LOG="$LOGDIR/log" CTR=0 HOSTNAME=$(hostname) VERBOSE=0 while getopts "vha:l:m" OPTION do case "$OPTION" in v) VERBOSE=$((VERBOSE + 1)) ;; h) usage exit 0 ;; a) AUTH="$OPTARG" ;; l) LOGDIR="$OPTARG" ;; m) MAIL=1 ;; *) usage >&2 exit 1 esac done shift $(($OPTIND - 1)) if [ "${1:-}" = "--help" ]; then usage exit 0 fi declare -a CHECKHOSTS=("$@") if [ "${#CHECKHOSTS[@]}" = 0 ]; then for i in $DEFAULT_CHECKHOSTS; do CHECKHOSTS[${#CHECKHOSTS[@]}]="$i" done fi run_some_checks() { local idx=$(( RANDOM % ${#CHECKHOSTS[@]} )) local host="${CHECKHOSTS[$idx]}" wget -q -O - "http://$AUTH"/tor/status-vote/current/consensus | \ grep -v BadExit | grep '^s .*Exit' -B1 |\ awk '$1 == "r" {print $3}' |\ sort -R | \ head -n "$PER_RUN" | \ while read fpr; do [ "$VERBOSE" = 0 ] || echo -n "[$(TZ=UTC date +%Y-%m-%dT%H:%M:%SZ)] Checking $host at $fpr..." if timeout 600 tor-exit-ssl-check -c "$CACHEDIR" -C "$CONTROLSOCKET" "$fpr" $host > "$DUMPFILE" 2>&1; then ecode=0 else ecode="$?" fi [ "$VERBOSE" = 0 ] || echo "$ecode" prefix="[$(TZ=UTC date +%Y-%m-%dT%H:%M:%SZ)][$fpr][EC=$ecode]" case "$ecode" in 0) echo "$prefix OK" >> "$LOG";; 2) echo "$prefix connect failed" >> "$LOG";; 4) echo "$prefix handshake failed" >> "$LOG";; 8) lf="$LOGDIR/$(date +%s).$HOSTNAME.$$.$CTR" echo "$prefix differences - logged as $lf" >> "$LOG" CTR=$((CTR + 1)) echo "$fpr" > "$lf" echo >> "$lf" cat "$DUMPFILE" >> "$lf" echo >> "$lf" wget -q -O - http://"$AUTH"/tor/server/fp/$(echo "$fpr" | perl -MMIME::Base64 -e "print unpack(\"H*\", decode_base64(<>)),\"\n\"") >> "$lf" if [ "$MAIL" -gt 0 ]; then (echo "Log file at $lf:"; echo; cat "$lf") | mail -s "certificate mismatch found for relay $fpr" "$USER" fi ;; 124) echo "$prefix timeout!" >> "$LOG";; *) echo "$prefix unknown exit code" >> "$LOG" echo "$prefix unknown exit code" >&2 cp $DUMPFILE "$LOGDIR/failed-output" exit 1 esac done } start_tor() { local pidfile="$CHECKDIR/pid" if command -v tor > /dev/null; then tor="tor" elif [ -x /usr/sbin/tor ]; then tor="/usr/sbin/tor" else echo >&2 "Cannot find tor executable" exit 1 fi local datadir="$CHECKDIR/tor" CONTROLSOCKET="$CHECKDIR/sock" cat > "$CHECKDIR/torrc" << EOF DataDirectory $datadir RunAsDaemon 1 SocksPort auto PidFile $pidfile SafeLogging 0 ControlSocket $CONTROLSOCKET StrictNodes 1 EOF mkdir -p -m 0700 "$datadir" "$tor" --hush -f "$CHECKDIR/torrc" TORPID="$(cat $pidfile)" } start_tor while : ; do run_some_checks sleep 60 done