Better output formating for MTA-STS

* failreason_mtasts_rec additions is now adding not to the first array index only
* arrays for formatting error has now separators (but also at the last index)
  hint from https://web.archive.org/web/20101114051536/http://codesnippets.joyent.com/posts/show/1826
* replaced a couple of quoted double quotes by single quotes
* replaced a couple of quoted single quotes by single quotes

Unrelated to mta-sts:
* HAS_DIG_NOIDNOUT was moved to places where we need dig
* echo "$mx" --> safe_echo "$mx"

The latter two should be backported to 3.0
This commit is contained in:
Dirk Wetter 2021-01-21 22:46:46 +01:00
parent 911ac8380f
commit d3e592579e

View File

@ -7423,21 +7423,21 @@ sub_mta_sts() {
failreason_mtasts_rec="no record" failreason_mtasts_rec="no record"
else else
if [[ $(count_char_occurence "$mta_sts_record" ';') -ne 2 ]]; then if [[ $(count_char_occurence "$mta_sts_record" ';') -ne 2 ]]; then
failreason_mtasts_rec+="number of ; should be 2" failreason_mtasts_rec+=("number of ; should be 2")
mta_sts_record_ok=false mta_sts_record_ok=false
fi fi
IFS=';' read v id <<< "${mta_sts_record}" IFS=';' read v id <<< "${mta_sts_record}"
if [[ ! "$v" == v=STSv1 ]] ; then if [[ ! "$v" == v=STSv1 ]] ; then
failreason_mtasts_rec+="v seems wrong" failreason_mtasts_rec+=("v seems wrong")
mta_sts_record_ok=false mta_sts_record_ok=false
fi fi
if [[ ! "$id" =~ ^[\ ]+id= ]]; then if [[ ! "$id" =~ ^[\ ]+id= ]]; then
failreason_mtasts_rec+="id seems wrong: $id" failreason_mtasts_rec+=("id seems wrong: $id")
mta_sts_record_ok=false mta_sts_record_ok=false
else else
id="${id#*=}" # strip key id="${id#*=}" # strip key
if [[ ! "$id" =~ ^[[:alnum:]]{1,32}$ ]]; then if [[ ! "$id" =~ ^[[:alnum:]]{1,32}$ ]]; then
failreason_mtasts_rec+="\'id\' should be up to 32 alnum chars " failreason_mtasts_rec+=("'id' should be up to 32 alnum chars ")
mta_sts_record_ok=false mta_sts_record_ok=false
fi fi
fi fi
@ -7504,7 +7504,7 @@ sub_mta_sts() {
# now the verdicts # now the verdicts
if "$mta_sts_record_ok"; then if "$mta_sts_record_ok"; then
pr_svrty_good "valid" pr_svrty_good "valid"
outln " _mta-sts TXT record $mta_sts_record" outln " _mta-sts TXT record \'$mta_sts_record\'"
# quotes! # quotes!
fileout "${jsonID}_txtrecord" "OK" "valid _mta-sts TXT record $mta_sts_record" fileout "${jsonID}_txtrecord" "OK" "valid _mta-sts TXT record $mta_sts_record"
elif [[ -z "$mta_sts_record" ]]; then elif [[ -z "$mta_sts_record" ]]; then
@ -7513,43 +7513,46 @@ sub_mta_sts() {
fileout "${jsonID}_txtrecord" "LOW" "no _mta-sts TXT record" fileout "${jsonID}_txtrecord" "LOW" "no _mta-sts TXT record"
else else
pr_svrty_low "invalid" pr_svrty_low "invalid"
# quotes! # Append to every element a string, here: '|'. n would work as well but we'd need $spaces.
fileout "${jsonID}_txtrecord" "LOW" "invalid _mta-sts TXT record $mta_sts_record ${failreason_mtasts_rec[@]}" # Catch is also for the last, so maybe we should avoid arrays
outln " _mta-sts TXT record ${mta_sts_record} | ${failreason_mtasts_rec[@]}" # Hint is from http://web.archive.org/web/20101114051536/http://codesnippets.joyent.com/posts/show/1826
failreason_mtasts_rec=( "${failreason_mtasts_rec[@]/%/ | }" )
fileout "${jsonID}_txtrecord" "LOW" "invalid _mta-sts TXT record $mta_sts_record $(printf '%s | ' "{failreason_mtasts_rec[@]}")"
outln " _mta-sts TXT record '${mta_sts_record}'\n${spaces} $(printf '%s' "${failreason_mtasts_rec[@]}")"
fi fi
out "$spaces" out "$spaces"
if "$policy_ok"; then if "$policy_ok"; then
if [[ $policy_mode == testing ]]; then if [[ $policy_mode == testing ]]; then
out "\"none\" is a valid policy but why are you using it?" out "\"none\" is a valid policy but why are you using it?"
fileout "${jsonID}_policy" "INFO" "none is valid but not a helpful policy \"https://mta-sts.$domain/.well-known/mta-sts.txt\"" fileout "${jsonID}_policy" "INFO" "none is valid but not a helpful policy at https://mta-sts.$domain/.well-known/mta-sts.txt"
elif [[ $policy_mode == testing ]]; then elif [[ $policy_mode == testing ]]; then
out "valid but not enforced" out "valid but not enforced"
fileout "${jsonID}_policy" "INFO" "valid but not enforced policy \"https://mta-sts.$domain/.well-known/mta-sts.txt\"" fileout "${jsonID}_policy" "INFO" "valid but not enforced policy at https://mta-sts.$domain/.well-known/mta-sts.txt"
else else
pr_svrty_good "valid and enforced" pr_svrty_good "valid and enforced"
fileout "${jsonID}_policy" "OK" "valid and enforced policy \"https://mta-sts.$domain/.well-known/mta-sts.txt\"" fileout "${jsonID}_policy" "OK" "valid and enforced policy at https://mta-sts.$domain/.well-known/mta-sts.txt"
fi fi
outln " policy https://mta-sts.$domain/.well-known/mta-sts.txt" outln " policy https://mta-sts.$domain/.well-known/mta-sts.txt"
elif [[ -z "$policy" ]]; then elif [[ -z "$policy" ]]; then
pr_svrty_low "no policy" pr_svrty_low "no policy"
outln " \"https://mta-sts.$domain/.well-known/mta-sts.txt\"" outln " at https://mta-sts.$domain/.well-known/mta-sts.txt"
fileout "${jsonID}_policy" "LOW" "no policy \"https://mta-sts.$domain/.well-known/mta-sts.txt\"" fileout "${jsonID}_policy" "LOW" "no policy at https://mta-sts.$domain/.well-known/mta-sts.txt"
else else
# missing: too short, not enforced, etc.. # missing: too short, not enforced, etc..
pr_svrty_low "invalid policy" pr_svrty_low "invalid policy"
#FIXME: for multiple failures we need to format ${failreason_policy[@]}, here? failreason_policy=( "${failreason_policy[@]/%/ | }" )
outln " \"https://mta-sts.$domain/.well-known/mta-sts.txt\": ${failreason_policy[@]}" fileout "${jsonID}_policy" "LOW" "invalid policy https://mta-sts.$domain/.well-known/mta-sts.txt: $(printf '%s' ${failreason_policy[@]})"
fileout "${jsonID}_policy" "LOW" "invalid policy \"https://mta-sts.$domain/.well-known/mta-sts.txt\"" outln " at https://mta-sts.$domain/.well-known/mta-sts.txt: $(printf '%s' ${failreason_policy[@]})"
fi fi
out "$spaces" out "$spaces"
if "$smtp_tls_record_ok"; then if "$smtp_tls_record_ok"; then
outln "found (optional) TLS RPT TXT record \"$smtp_tls_record\"" outln "found (optional) TLS RPT TXT record '$smtp_tls_record'"
fileout "${jsonID}_tlsrpt" "INFO" "optional TLS-RPT TXT record \"$smtp_tls_record\"" fileout "${jsonID}_tlsrpt" "INFO" "optional TLS-RPT TXT record '$smtp_tls_record'"
else else
outln "No TLS RPT record" outln "No TLS RPT record"
fileout "${jsonID}_tlsrpt" "INFO" "no or invalid (optional) TLS RPT record \"$smtp_tls_record\"" fileout "${jsonID}_tlsrpt" "INFO" "no or invalid (optional) TLS RPT record '$smtp_tls_record'"
fi fi
return 0 return 0
@ -20226,7 +20229,6 @@ get_a_record() {
local saved_openssl_conf="$OPENSSL_CONF" local saved_openssl_conf="$OPENSSL_CONF"
local noidnout="" local noidnout=""
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
[[ "$NODNS" == none ]] && return 0 # if no DNS lookup was instructed, leave here [[ "$NODNS" == none ]] && return 0 # if no DNS lookup was instructed, leave here
if [[ "$1" == localhost ]]; then if [[ "$1" == localhost ]]; then
# This is a bit ugly but prevents from doing DNS lookups which could fail # This is a bit ugly but prevents from doing DNS lookups which could fail
@ -20249,6 +20251,7 @@ get_a_record() {
fi fi
fi fi
if [[ -z "$ip4" ]] && "$HAS_DIG"; then if [[ -z "$ip4" ]] && "$HAS_DIG"; then
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
ip4=$(filter_ip4_address $(dig +short +timeout=2 +tries=2 $noidnout -t a "$1" 2>/dev/null | awk '/^[0-9]/ { print $1 }')) ip4=$(filter_ip4_address $(dig +short +timeout=2 +tries=2 $noidnout -t a "$1" 2>/dev/null | awk '/^[0-9]/ { print $1 }'))
fi fi
if [[ -z "$ip4" ]] && "$HAS_HOST"; then if [[ -z "$ip4" ]] && "$HAS_HOST"; then
@ -20271,7 +20274,6 @@ get_aaaa_record() {
local saved_openssl_conf="$OPENSSL_CONF" local saved_openssl_conf="$OPENSSL_CONF"
local noidnout="" local noidnout=""
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
[[ "$NODNS" == none ]] && return 0 # if no DNS lookup was instructed, leave here [[ "$NODNS" == none ]] && return 0 # if no DNS lookup was instructed, leave here
OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134
if is_ipv6addr "$1"; then if is_ipv6addr "$1"; then
@ -20292,6 +20294,7 @@ get_aaaa_record() {
fatal "Local hostname given but no 'avahi-resolve' or 'dig' available." $ERR_DNSBIN fatal "Local hostname given but no 'avahi-resolve' or 'dig' available." $ERR_DNSBIN
fi fi
elif "$HAS_DIG"; then elif "$HAS_DIG"; then
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
ip6=$(filter_ip6_address $(dig +short +timeout=2 +tries=2 $noidnout -t aaaa "$1" 2>/dev/null | awk '/^[0-9]/ { print $1 }')) ip6=$(filter_ip6_address $(dig +short +timeout=2 +tries=2 $noidnout -t aaaa "$1" 2>/dev/null | awk '/^[0-9]/ { print $1 }'))
elif "$HAS_HOST"; then elif "$HAS_HOST"; then
ip6=$(filter_ip6_address $(host -t aaaa "$1" | awk '/address/ { print $NF }')) ip6=$(filter_ip6_address $(host -t aaaa "$1" | awk '/address/ { print $NF }'))
@ -20317,7 +20320,6 @@ get_caa_rr_record() {
local all_caa="" local all_caa=""
local noidnout="" local noidnout=""
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
[[ -n "$NODNS" ]] && return 0 # if minimum DNS lookup was instructed, leave here [[ -n "$NODNS" ]] && return 0 # if minimum DNS lookup was instructed, leave here
# if there's a type257 record there are two output formats here, mostly depending on age of distribution # if there's a type257 record there are two output formats here, mostly depending on age of distribution
@ -20328,6 +20330,7 @@ get_caa_rr_record() {
# caa_property then has key/value pairs, see https://tools.ietf.org/html/rfc6844#section-3 # caa_property then has key/value pairs, see https://tools.ietf.org/html/rfc6844#section-3
OPENSSL_CONF="" OPENSSL_CONF=""
if "$HAS_DIG"; then if "$HAS_DIG"; then
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
raw_caa="$(dig +short +timeout=3 +tries=3 $noidnout type257 "$1" 2>/dev/null | awk '{ print $1" "$2" "$3 }')" raw_caa="$(dig +short +timeout=3 +tries=3 $noidnout type257 "$1" 2>/dev/null | awk '{ print $1" "$2" "$3 }')"
# empty if no CAA record # empty if no CAA record
elif "$HAS_DRILL"; then elif "$HAS_DRILL"; then
@ -20393,12 +20396,12 @@ get_mx_record() {
local saved_openssl_conf="$OPENSSL_CONF" local saved_openssl_conf="$OPENSSL_CONF"
local noidnout="" local noidnout=""
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134
# we need the last two columns here # we need the last two columns here
if "$HAS_HOST"; then if "$HAS_HOST"; then
mx="$(host -t MX "$1" 2>/dev/null | awk '/is handled by/ { print $(NF-1), $NF }')" mx="$(host -t MX "$1" 2>/dev/null | awk '/is handled by/ { print $(NF-1), $NF }')"
elif "$HAS_DIG"; then elif "$HAS_DIG"; then
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
mx="$(dig +short $noidnout -t MX "$1" 2>/dev/null | awk '/^[0-9]/ { print $1" "$2 }')" mx="$(dig +short $noidnout -t MX "$1" 2>/dev/null | awk '/^[0-9]/ { print $1" "$2 }')"
elif "$HAS_DRILL"; then elif "$HAS_DRILL"; then
mx="$(drill mx $1 | awk '/IN[ \t]MX[ \t]+/ { print $(NF-1), $NF }')" mx="$(drill mx $1 | awk '/IN[ \t]MX[ \t]+/ { print $(NF-1), $NF }')"
@ -20409,7 +20412,7 @@ get_mx_record() {
fatal "No dig, host, drill or nslookup" $ERR_DNSBIN fatal "No dig, host, drill or nslookup" $ERR_DNSBIN
fi fi
OPENSSL_CONF="$saved_openssl_conf" OPENSSL_CONF="$saved_openssl_conf"
echo "$mx" safe_echo "$mx"
} }
# arg1: domain / hostname. Returned will be the TXT record as a string which can be multilined # arg1: domain / hostname. Returned will be the TXT record as a string which can be multilined
@ -20420,12 +20423,12 @@ get_txt_record() {
local saved_openssl_conf="$OPENSSL_CONF" local saved_openssl_conf="$OPENSSL_CONF"
local noidnout="" local noidnout=""
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134 OPENSSL_CONF="" # see https://github.com/drwetter/testssl.sh/issues/134
# we need the last two columns here and strip any remaining double quotes later # we need the last two columns here and strip any remaining double quotes later
if "$HAS_HOST"; then if "$HAS_HOST"; then
record="$(host -t TXT "$1" 2>/dev/null | grep 'descriptive text')" record="$(host -t TXT "$1" 2>/dev/null | grep 'descriptive text')"
elif "$HAS_DIG"; then elif "$HAS_DIG"; then
"$HAS_DIG_NOIDNOUT" && noidnout="+noidnout"
record="$(dig +short $noidnout -t TXT "$1" 2>/dev/null)" record="$(dig +short $noidnout -t TXT "$1" 2>/dev/null)"
record="${record% from*}" record="${record% from*}"
elif "$HAS_DRILL"; then elif "$HAS_DRILL"; then