-
-
Save bmatthewshea/2f4301b769a46e7eb10d554a52a864b3 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| # By B Shea Dec2018 & Mar2020 | |
| # https://www.holylinux.net | |
| # Test for OpenSSL - if not installed stop here. | |
| if ! [[ -x $(which openssl) ]]; then | |
| printf "\nOpenSSL not found or not executable.\nPlease install OpenSSL before proceeding.\n\n" | |
| exit 1 | |
| fi | |
| ### user adjustable variables ### | |
| #openssl query timeout: | |
| openssl_timeout="timeout 10" | |
| # 30 days is default on warnings - overidden on command line with '-d': | |
| days_to_warn=30 | |
| # default name for file lists | |
| sitelist=./websites.txt | |
| ### Clear/list/set defaults for variables ### | |
| epoch_day=86400 | |
| epoch_warning=$((days_to_warn*epoch_day)) | |
| regex_numbers='^[0-9]+$' | |
| expire="0" | |
| website="" | |
| port="" | |
| tls="0" | |
| sTLS="" | |
| show_tls="" | |
| certfilename="" | |
| location="" | |
| filename="" | |
| displaysite="" | |
| #COLORS | |
| color="0" | |
| RED=$(tput setaf 1) #expired!! | |
| GREEN=$(tput setaf 2) #within bounds | |
| YELLOW=$(tput setaf 3) #warning/date close! | |
| NC=$(tput sgr0) #reset to normal | |
| # | |
| usage=" | |
| $(basename "$0") [-h] [-c] [-d DAYS] [-f FILENAME] | [-w WEBSITE] | [-s SITELIST] | |
| Retrieve the expiration date(s) on SSL certificate(s) using OpenSSL. | |
| Usage: | |
| -h Help | |
| -c Color output | |
| -d Amount of days to show warnings (default is 30 days) | |
| Example: -d 15 | |
| -f SSL date from FILENAME | |
| Example: -f /home/user/example.pem | |
| -w SSL date from SITE(:PORT) (Port defaults to 443) | |
| Example: -w www.example.com | |
| -s SSL date(s) from SITELIST | |
| Example: -s ./websites.txt | |
| List format: sub.domain.tld:993 (one per line - port optional) | |
| Example: | |
| $ $(basename "$0") -c -d 14 -s ./websites.txt | |
| WARNS (in color) if within 14 days of expiring on each entry in the file list. | |
| " | |
| #FUNCTIONS | |
| is_integer() { | |
| if ! [[ "$1" =~ $regex_numbers ]]; then | |
| printf "\nError.\nNot a number. You used a parameter that requires a whole number.\n$usage" | |
| exit 1 | |
| fi | |
| } | |
| menu_input() { | |
| echo | |
| echo "1: Enter file location of certificate" | |
| echo "2: Enter an Internet site in form of subdomain.domain.tld(:port)" | |
| echo | |
| read -p "Enter 1 or 2 (anything else quits): " -n 1 -r | |
| echo | |
| } | |
| get_lookup_input() { | |
| location="" | |
| echo | |
| read -p "Please enter the $lookuptype location: " location | |
| } | |
| set_format() { | |
| set_formatting="%-40s%-25s\n" | |
| set_formatting_green=$set_formatting | |
| set_formatting_yellow=$set_formatting | |
| set_formatting_red=$set_formatting | |
| printf "\nWarning is $days_to_warn days.\n" | |
| printf "Color is " | |
| if [[ $color == "1" ]]; then | |
| set_formatting_green="$GREEN%-40s$NC%-25s\n" | |
| set_formatting_yellow="$YELLOW%-40s$NC%-25s\n" | |
| set_formatting_red="$RED%-40s$NC%-25s\n" | |
| printf "enabled.\n\n" | |
| else | |
| printf "disabled.\n\n" | |
| fi | |
| printf "$set_formatting" "LOCATION" "EXPIRATION DATE" | |
| printf "$set_formatting" "--------" "---------------" | |
| } | |
| parse_port() { | |
| port=443 | |
| tls="0" | |
| show_tls="" | |
| parseurl=$(echo $website | awk '$1 ~ /^.*:/' | cut -d':' -f1) | |
| parseport=$(echo $website | awk '$1 ~ /^.*:/' | cut -d':' -f2) | |
| if [[ $parseport =~ $regex_numbers ]]; then # -> port was found | |
| website=$parseurl | |
| port=$parseport | |
| if [[ $port == "587" ]]; then # Use TLS lookup and notify | |
| show_tls=" (TLS)" | |
| tls="1" | |
| fi | |
| fi | |
| } | |
| check_expiry() { | |
| expire="0" | |
| # use epoch times for calcs/compares | |
| today_epoch="$(date +%s)" | |
| sTLS="" | |
| if [[ $tls == "1" ]]; then | |
| sTLS=" -starttls smtp" | |
| fi | |
| if [ "$lookuptype" == "FILENAME" ]; then | |
| expire_date=$(openssl x509 -in $certfilename$sTLS -noout -dates 2>/dev/null | \ | |
| awk -F= '/^notAfter/ { print $2; exit }') | |
| else | |
| expire_date=$($openssl_timeout openssl s_client -servername $website -connect $website:$port$sTLS </dev/null 2>/dev/null | \ | |
| openssl x509 -noout -dates 2>/dev/null | \ | |
| awk -F= '/^notAfter/ { print $2; exit }') | |
| fi | |
| if ! [[ -z $expire_date ]]; then # -> found date-process it: | |
| expire_epoch=$(date +%s -d "$expire_date") | |
| timeleft=`expr $expire_epoch - $today_epoch` | |
| if [[ $timeleft -le $epoch_warning ]]; then #WARN | |
| expire="1" | |
| fi | |
| if [[ $today_epoch -ge $expire_epoch ]]; then #EXPIRE | |
| expire="2" | |
| fi | |
| else | |
| expire="3" | |
| expire_date="N/A " | |
| fi | |
| } | |
| output_site() { | |
| parse_port | |
| check_expiry | |
| if [ "$lookuptype" != "FILENAME" ]; then | |
| display_site="$website:$port$show_tls" | |
| else | |
| display_site="$filename$show_tls" | |
| fi | |
| if [[ $expire == "1" ]]; then | |
| printf "$set_formatting_yellow" "$display_site" "$expire_date !" # YELLOW OUTPUT - warning | |
| elif [[ $expire == "2" ]]; then | |
| printf "$set_formatting_red" "$display_site" "$expire_date !!" # RED OUTPUT - expired | |
| elif [[ $expire == "3" ]]; then | |
| printf "$set_formatting" "$display_site" "$expire_date !!!" # NO COLOR - NOT FOUND | |
| else | |
| printf "$set_formatting_green" "$display_site" "$expire_date" # GREEN OUTPUT | |
| fi | |
| } | |
| # | |
| client_lookup() { | |
| lookuptype="WEBSITE" | |
| if [[ -z $website ]]; then #loop lookup - ask for input | |
| get_lookup_input | |
| website=$location | |
| fi | |
| set_format | |
| output_site | |
| lookuptype="" | |
| website="" | |
| echo | |
| } | |
| file_lookup() { | |
| lookuptype="FILENAME" | |
| if [[ -z $certfilename ]]; then #loop lookup - ask for input | |
| get_lookup_input | |
| certfilename=$location | |
| fi | |
| filename=$(basename -- "$certfilename") | |
| set_format | |
| output_site | |
| lookuptype="" | |
| filename="" | |
| echo | |
| } | |
| list_lookup() { | |
| lookuptype="FILELIST" | |
| file_contents=$(<$sitelist) | |
| set_format | |
| while IFS= read -r website; do | |
| if ! [[ -z $website ]]; then | |
| output_site | |
| fi | |
| done <<<"$file_contents" | |
| lookuptype="" | |
| echo | |
| } | |
| #HANDLE ARGUMENTS | |
| while getopts ':hcd:f:s:w:' option; do | |
| case "$option" in | |
| h) printf "$usage" | |
| exit 0 | |
| ;; | |
| c) color="1" | |
| ;; | |
| d) is_integer "$OPTARG" | |
| if [ "$OPTARG" -ge 1 -a "$OPTARG" -le 365 ]; then | |
| days_to_warn="$OPTARG" | |
| epoch_warning=$((days_to_warn*epoch_day)) | |
| else | |
| printf "\nDays must be between 1 and 365\n$usage" | |
| exit 1 | |
| fi | |
| ;; | |
| f) certfilename=$OPTARG | |
| [[ -r $certfilename ]] && file_lookup || printf "\nFile not found/not readable. Permissions?\n\n"; exit 1; | |
| exit 0 | |
| ;; | |
| s) sitelist=$OPTARG | |
| [[ -r $sitelist ]] && list_lookup || printf "\nFile not found/not readable. Permissions?\n\n"; exit 1; | |
| exit 0 | |
| ;; | |
| w) website=$OPTARG | |
| client_lookup | |
| exit 0 | |
| ;; | |
| :) printf "\nYou specified a flag that needs an argument.\n$usage" 1>&2 | |
| exit 1 | |
| ;; | |
| *) printf "\nI do not understand '"$1" "$2"'.\n$usage" 1>&2 | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| shift $((OPTIND - 1)) | |
| #LOOP RUN (default if no flags) | |
| if [ $# -eq 0 ]; then # no command line arguments/flags found | |
| printf "\nNo flags used or available. Interactive mode.\n" | |
| while : | |
| do | |
| menu_input | |
| if [[ $REPLY == "1" ]] | |
| then | |
| file_lookup | |
| elif [[ $REPLY == "2" ]] | |
| then | |
| client_lookup | |
| else # exit | |
| [[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 | |
| fi | |
| echo | |
| done | |
| fi |
Hi,
IP is most important. If hostname is problem - dont do it - it is not important.
IP is most important. If hostname is problem - dont do it - it is not important.
Gotcha/Understood. Will look into it asap.
Leaving this for anyone else who might run across this on MacOS (Catalina 10.15.6 as of writing). At first I was getting an error that said date: illegal time format. Found the issue was with the date command and how different versions of it work.
By default MacOS ships with a BSD date command while this script expects a GNU one. I wasn't smart enough to figure out how to get it working with the default date command so I installed coreutils through Homebrew.
Once that was done I changed the two usages of date in the check_expiry function to use gdate instead. That seemed to work for me! Hope this helps someone.
check_expiry() {
expire="0"
# use epoch times for calcs/compares
today_epoch="$(gdate +%s)"
sTLS=""
if [[ $tls == "1" ]]; then
sTLS=" -starttls smtp"
fi
if [ "$lookuptype" == "FILENAME" ]; then
expire_date=$(openssl x509 -in $certfilename$sTLS -noout -dates 2>/dev/null | \
awk -F= '/^notAfter/ { print $2; exit }')
else
expire_date=$($openssl_timeout openssl s_client -servername $website -connect $website:$port$sTLS </dev/null 2>/dev/null | \
openssl x509 -noout -dates 2>/dev/null | \
awk -F= '/^notAfter/ { print $2; exit }')
fi
if ! [[ -z $expire_date ]]; then # -> found date-process it:
expire_epoch=$(gdate +%s -d "$expire_date")
timeleft=`expr $expire_epoch - $today_epoch`
if [[ $timeleft -le $epoch_warning ]]; then #WARN
expire="1"
fi
if [[ $today_epoch -ge $expire_epoch ]]; then #EXPIRE
expire="2"
fi
else
expire="3"
expire_date="N/A "
fi
}Once that was done I changed the two usages of
datein thecheck_expiryfunction to usegdateinstead. That seemed to work for me! Hope this helps someone.today_epoch="$(gdate +%s)" ... expire_epoch=$(gdate +%s -d "$expire_date")
Awesome - glad you figured that out. And thanks for the input.
I will add a check to code. Something like this: https://stackoverflow.com/a/8748193/503621
& sorry been really busy with work and haven't had time for any side projects, lately.
This should work (replace line 143 w/ this):
expire_epoch=$(date -j -f "%b %d %T %Y %Z" "$expire_date" "+%s") # BSD VERSION of DATE
That should be the only incompatible statement.
The today_epoch="$(date +%s)" worked for me on a BSD bash shell.
Let me know if that fixes it (without using GNU/"gdate" version).
PS -
I have a new version of this script done - just need to test it some more :

@masterwebsk
So, if I understand, by 'real IP' you want the DNS lookup/IP & 'local' hostname in the script output?
Like:
Not quite sure what you mean by hostname? DNS / Hostname queries (by default/normally) are done by checking 'files' (
/etc/hosts) first, then the systems DNS service/resolver (be that public or private or both) - in that order. (from/etc/nsswitch.conf).So is that what you want? A local hostname (if found) under LOCATION? The public hostname (assuming this wasn't found in
/etc/hosts) is already shown ( = 'www.').