From 36c92d150e954390fd4f8603cce1997a98bcbdf8 Mon Sep 17 00:00:00 2001 From: Tim Kimber Date: Wed, 23 Sep 2020 22:34:40 +0100 Subject: [PATCH] Fixes and changes to test get_auth_dns --- getssl | 98 +++++++++++------ test/19-test-get_auth_dns-dig.bats | 166 +++++++++++++++++++++++++++++ 2 files changed, 231 insertions(+), 33 deletions(-) create mode 100644 test/19-test-get_auth_dns-dig.bats diff --git a/getssl b/getssl index c92733f..05b2f2f 100755 --- a/getssl +++ b/getssl @@ -292,6 +292,9 @@ _NOTIFY_VALID=0 _QUIET=0 _RECREATE_CSR=0 _REVOKE=0 +_RUNNING_TEST=0 +_TEST_SKIP_CNAME_CALL=0 +_TEST_SKIP_SOA_CALL=0 _UPGRADE=0 _UPGRADE_CHECK=1 _USE_DEBUG=0 @@ -942,8 +945,19 @@ date_renew() { # calculates the renewal time in epoch debug() { # write out debug info if the debug flag has been set if [[ ${_USE_DEBUG} -eq 1 ]]; then - echo " " - echo "$@" + # If running tests then output in TAP format (for debugging tests) + if [[ -n "$_RUNNING_TEST" ]]; then + echo "#" "$@" >&3 + else + echo " " + echo "$@" + fi + fi +} + +test_output() { # write out debug output for testing + if [[ ${_RUNNING_TEST} -eq 1 ]]; then + echo "#" "$@" fi } @@ -1251,6 +1265,9 @@ fi get_auth_dns() { # get the authoritative dns server for a domain (sets primary_ns ) orig_gad_d="$1" # domain name gad_s="$PUBLIC_DNS_SERVER" # start with PUBLIC_DNS_SERVER + if [[ -n "$gad_s" ]]; then + gad_s="@$gad_s" + fi if [[ "$os" == "cygwin" ]]; then gad_d="$orig_gad_d" @@ -1268,49 +1285,62 @@ get_auth_dns() { # get the authoritative dns server for a domain (sets primary_n if [[ -n "$HAS_DIG_OR_DRILL" ]]; then gad_d="$orig_gad_d" # Use SOA +trace to find the name server - if [[ -z "$gad_s" ]]; then - debug Using "$HAS_DIG_OR_DRILL SOA +trace +nocomments $gad_d" to find primary nameserver - res=$($HAS_DIG_OR_DRILL SOA +trace +nocomments "$gad_d" 2>/dev/null | grep "IN\WNS\W") - else - debug Using "$HAS_DIG_OR_DRILL SOA +trace +nocomments $gad_d @$gad_s" to find primary nameserver - res=$($HAS_DIG_OR_DRILL SOA +trace +nocomments "$gad_d" "@$gad_s" 2>/dev/null | grep "IN\WNS\W") + if [[ $_TEST_SKIP_SOA_CALL == 0 ]]; then + debug Using "$HAS_DIG_OR_DRILL SOA +trace +nocomments $gad_d $gad_s" to find primary nameserver + test_output "Using $HAS_DIG_OR_DRILL SOA" + res=$($HAS_DIG_OR_DRILL SOA +trace +nocomments "$gad_d" "$gad_s" 2>/dev/null | grep "IN\WNS\W") fi - # fallback to existing code + # Check if domain is a CNAME if [[ -z "$res" ]]; then - if [[ -z "$gad_s" ]]; then #checking for CNAMEs (need grep as dig 9.11 sometimes returns everything not just CNAME entries) - debug Checking for CNAME using "$HAS_DIG_OR_DRILL CNAME $gad_d" - res=$($HAS_DIG_OR_DRILL CNAME "$gad_d"| grep "^$gad_d" | grep CNAME) + test_output "Using $HAS_DIG_OR_DRILL CNAME" + + # Two options here; either dig CNAME will return the CNAME and the NS or just the CNAME + debug Checking for CNAME using "$HAS_DIG_OR_DRILL CNAME $gad_d $gad_s" + res=$($HAS_DIG_OR_DRILL CNAME "$gad_d" "$gad_s"| grep "^$gad_d") + cname=$(echo "$res"| awk '$4 ~ "CNAME" {print $5}' |sed 's/\.$//g') + + if [[ $_TEST_SKIP_CNAME_CALL == 0 ]]; then + debug Checking if CNAME result contains NS records + res=$($HAS_DIG_OR_DRILL CNAME "$gad_d" "$gad_s"| grep -E "IN\W(NS|SOA)\W") else - debug Checking for CNAME using "$HAS_DIG_OR_DRILL CNAME $gad_d @$gad_s" - res=$($HAS_DIG_OR_DRILL CNAME "$gad_d" "@$gad_s"| grep "^$gad_d" | grep CNAME) - fi - if [[ -n "$res" ]]; then # domain is a CNAME so get main domain - gad_d=$(echo "$res"| awk '{print $5}' |sed 's/\.$//g') - debug Domain is a CNAME, actual domain is "$gad_d" + res="" fi - # If gad_d is an A record then this returns the SOA for the root domain, e.g. without the www - # dig NS ubuntu.getssl.text - # > getssl.test. IN SOA ns1.duckdns.org - # If gad_d is a CNAME record then this returns the NS for the domain pointed to by $gad_d - # dig NS www.getssl.text - # > www.getssl.test. IN CNAME getssl.test - # > getssl.test. IN NS ns1.duckdns.org - if [[ -z "$gad_s" ]]; then - debug Using "$HAS_DIG_OR_DRILL NS $gad_d" to find primary nameserver - res=$($HAS_DIG_OR_DRILL NS "$gad_d"| grep -E "IN\W(NS|SOA)\W") - else - debug Using "$HAS_DIG_OR_DRILL NS $gad_d @$gad_s" to find primary nameserver - res=$($HAS_DIG_OR_DRILL NS "$gad_d" "@$gad_s"| grep -E "IN\W(NS|SOA)\W") + + if [[ -n "$cname" ]]; then # domain is a CNAME so get main domain + debug Domain is a CNAME, actual domain is "$cname" fi fi + + # Query for NS records + if [[ -z "$res" ]]; then + test_output "Using $HAS_DIG_OR_DRILL NS" + debug Using "$HAS_DIG_OR_DRILL NS $gad_d $gad_s" to find primary nameserver + res=$($HAS_DIG_OR_DRILL NS "$gad_d" $gad_s | grep -E "IN\W(NS|SOA)\W") + fi + if [[ -n "$res" ]]; then - all_auth_dns_servers=$(echo "$res" | awk '$4 ~ "NS" {print $5}' | sed 's/\.$//g'|tr '\n' ' ') + # Convert dig output into an array of nameservers + IFS=$'\n' read -r -d '' -a ns_servers < <(echo "$res" | awk '$4 ~ "(NS|SOA)" {print $5}' | sed 's/\.$//g') + + # Nameservers from SOA +trace includes root and all intermediate servers, so just use all the ones with the same domain as the last name server + # i.e. if we have root, google, duckdns1, duckdns2 then return all the duckdns servers + ns_domain=${ns_servers[${#ns_servers[@]} -1 ]#*.} + all_auth_dns_servers="" + for i in "${ns_servers[@]}"; do + if [[ $i =~ $ns_domain ]]; then + all_auth_dns_servers="$all_auth_dns_servers $i" + fi + done + if [[ $CHECK_ALL_AUTH_DNS == "true" ]]; then primary_ns="$all_auth_dns_servers" else - primary_ns=$(echo "$all_auth_dns_servers" | awk '{print $1}') + primary_ns=$(echo "$all_auth_dns_servers" | awk '{print " " $1}') fi + + debug set primary_ns = "$primary_ns" + test_output set primary_ns ="$primary_ns" return fi fi @@ -2343,6 +2373,8 @@ while [[ -n ${1+defined} ]]; do _ONLY_CHECK_CONFIG=1 ;; -w) shift; WORKING_DIR="$1" ;; + --source) + return ;; -*) usage error_exit "Unknown option $1" ;; diff --git a/test/19-test-get_auth_dns-dig.bats b/test/19-test-get_auth_dns-dig.bats new file mode 100644 index 0000000..a726442 --- /dev/null +++ b/test/19-test-get_auth_dns-dig.bats @@ -0,0 +1,166 @@ +#! /usr/bin/env bats + +load '/bats-support/load.bash' +load '/bats-assert/load.bash' +load '/getssl/test/test_helper.bash' + + +# This is run for every test +setup() { + . /getssl/getssl --source + find_dns_utils + _RUNNING_TEST=1 + _USE_DEBUG=0 + echo " " >&3 + echo " " >&3 + + if [ -f /usr/bin/host ]; then + mv /usr/bin/host /usr/bin/host.getssl.bak + fi + if [ -f /usr/bin/nslookup ]; then + mv /usr/bin/nslookup /usr/bin/nslookup.getssl.bak + fi +} + + +teardown() { + if [ -f /usr/bin/host.getssl.bak ]; then + mv /usr/bin/host.getssl.bak /usr/bin/host + fi + if [ -f /usr/bin/nslookup.getssl.bak ]; then + mv /usr/bin/nslookup.getssl.bak /usr/bin/nslookup + fi +} + + + @test "Check get_auth_dns using dig NS" { + # Test that get_auth_dns() handles scenario where NS query returns Authority section + # + # ************** EXAMPLE DIG OUTPUT ************** + # + # ;; ANSWER SECTION: + # ubuntu-getssl.duckdns.org. 60 IN A 54.89.252.137 + # + # ;; AUTHORITY SECTION: + # duckdns.org. 600 IN NS ns2.duckdns.org. + # duckdns.org. 600 IN NS ns3.duckdns.org. + # duckdns.org. 600 IN NS ns1.duckdns.org. + # + # ;; ADDITIONAL SECTION: + # ns2.duckdns.org. 600 IN A 54.191.117.119 + # ns3.duckdns.org. 600 IN A 52.26.169.94 + # ns1.duckdns.org. 600 IN A 54.187.92.222 + + # Disable CNAME check + _TEST_SKIP_CNAME_CALL=1 + + PUBLIC_DNS_SERVER=ns1.duckdns.org + CHECK_ALL_AUTH_DNS=false + + run get_auth_dns ubuntu-getssl.duckdns.org + + # Assert that we've found the primary_ns server + assert_output --regexp 'set primary_ns = ns[1-3]+\.duckdns\.org' + # Assert that we had to use dig NS + assert_line --partial 'Using dig NS' + + # Check all Authoritive DNS servers are returned if requested + CHECK_ALL_AUTH_DNS=true + run get_auth_dns ubuntu-getssl.duckdns.org + assert_output --regexp 'set primary_ns = ns[1-3]+\.duckdns\.org ns[1-3]+\.duckdns\.org ns[1-3]+\.duckdns\.org' +} + + +@test "Check get_auth_dns using dig SOA" { + # Test that get_auth_dns() handles scenario where SOA query returns Authority section + # + # ************** EXAMPLE DIG OUTPUT ************** + # + # ;; AUTHORITY SECTION: + # duckdns.org. 600 IN SOA ns3.duckdns.org. hostmaster.duckdns.org. 2019170803 6000 120 2419200 600 + + # DuckDNS server returns nothing for SOA, so use public dns instead + PUBLIC_DNS_SERVER=1.0.0.1 + CHECK_ALL_AUTH_DNS=false + + run get_auth_dns ubuntu-getssl.duckdns.org + + # Assert that we've found the primary_ns server + assert_output --regexp 'set primary_ns = ns[1-3]+\.duckdns\.org' + + # Assert that we had to use dig NS + assert_line --partial 'Using dig SOA' + refute_line --partial 'Using dig NS' + + # Check all Authoritive DNS servers are returned if requested + CHECK_ALL_AUTH_DNS=true + run get_auth_dns ubuntu-getssl.duckdns.org + assert_output --regexp 'set primary_ns = ns[1-3]+\.duckdns\.org ns[1-3]+\.duckdns\.org ns[1-3]+\.duckdns\.org' +} + + +@test "Check get_auth_dns using dig CNAME (public dns)" { + # Test that get_auth_dns() handles scenario where CNAME query returns just a CNAME record + # + # ************** EXAMPLE DIG OUTPUT ************** + # + # ;; ANSWER SECTION: + # www.duckdns.org. 600 IN CNAME DuckDNSAppELB-570522007.us-west-2.elb.amazonaws.com. + + # Disable SOA check + _TEST_SKIP_SOA_CALL=1 + + PUBLIC_DNS_SERVER=1.0.0.1 + CHECK_ALL_AUTH_DNS=false + + run get_auth_dns www.duckdns.org + + # Assert that we've found the primary_ns server + assert_output --regexp 'set primary_ns = ns.*\.awsdns.*\.com' + + # Assert that we found a CNAME and use dig NS + assert_line --partial 'Using dig CNAME' + assert_line --partial 'Using dig NS' + + # Check all Authoritive DNS servers are returned if requested + CHECK_ALL_AUTH_DNS=false + run get_auth_dns www.duckdns.org + assert_output --regexp 'set primary_ns = ns.*\.awsdns.*\.com' +} + + +@test "Check get_auth_dns using dig CNAME (duckdns)" { + # Test that get_auth_dns() handles scenario where CNAME query returns authority section containing NS records + # + # ************** EXAMPLE DIG OUTPUT ************** + # + # ;; ANSWER SECTION: + # www.duckdns.org. 600 IN CNAME DuckDNSAppELB-570522007.us-west-2.elb.amazonaws.com. + # + # ;; AUTHORITY SECTION: + # duckdns.org. 600 IN NS ns1.duckdns.org. + # duckdns.org. 600 IN NS ns2.duckdns.org. + # duckdns.org. 600 IN NS ns3.duckdns.org. + # + # ;; ADDITIONAL SECTION: + # ns1.duckdns.org. 600 IN A 54.187.92.222 + # ns2.duckdns.org. 600 IN A 54.191.117.119 + # ns3.duckdns.org. 600 IN A 52.26.169.94 + + PUBLIC_DNS_SERVER=ns1.duckdns.org + CHECK_ALL_AUTH_DNS=false + + run get_auth_dns www.duckdns.org + + # Assert that we've found the primary_ns server + assert_output --regexp 'set primary_ns = ns[1-3]+\.duckdns\.org' + + # Assert that we found a CNAME but didn't use dig NS + assert_line --partial 'Using dig CNAME' + refute_line --partial 'Using dig NS' + + # Check all Authoritive DNS servers are returned if requested + CHECK_ALL_AUTH_DNS=true + run get_auth_dns www.duckdns.org + assert_output --regexp 'set primary_ns = ns[1-3]+\.duckdns\.org ns[1-3]+\.duckdns\.org ns[1-3]+\.duckdns\.org' +}