Skip to content

Commit 4a51194

Browse files
authored
Merge branch 'master' into fix-domain-template-url
2 parents 6fe3119 + 03d60ff commit 4a51194

16 files changed

+415
-95
lines changed

.github/workflows/run-all-tests.yml

+9-1
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,16 @@ jobs:
2121
- uses: actions/checkout@v1
2222
- name: Build the docker-compose stack
2323
run: docker-compose up -d --build
24-
- name: Run test suite on centos6
24+
- name: Run test suite on CentOS6
2525
run: test/run-test.sh centos6
26+
test-centos7:
27+
runs-on: ubuntu-latest
28+
steps:
29+
- uses: actions/checkout@v1
30+
- name: Build the docker-compose stack
31+
run: docker-compose up -d --build
32+
- name: Run test suite on CentOS7
33+
run: test/run-test.sh centos7
2634
test-centos7-duckdns:
2735
runs-on: ubuntu-latest
2836
steps:

dns_scripts/dns_add_challtestsrv

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
fulldomain="${1}"
55
token="${2}"
66

7-
curl -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\", \"value\": \"${token}\"}" http://10.30.50.3:8055/set-txt
7+
curl --silent -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\", \"value\": \"${token}\"}" http://10.30.50.3:8055/set-txt

getssl

+170-76
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,10 @@
214214
# 2020-02-13 Fix bug with copying to all locations when creating RSA and ECDSA certs (2.20)
215215
# 2020-02-22 Change sign_string to use openssl asn1parse (better fix for #424)
216216
# 2020-02-23 Add dig to config check for systems without drill (ubuntu)
217-
# 2020-03-23 Fix staging server URL in domain template
217+
# 2020-03-11 Use dig +trace to find primary name server and improve dig parsing of CNAME
218+
# 2020-03-12 Fix bug with DNS validation and multiple domains (#524)
219+
# 2020-03-24 Find primary ns using all dns utils (dig, host, nslookup)
220+
# 2020-03-23 Fix staging server URL in domain template (2.21)
218221
# ----------------------------------------------------------------------------------------
219222

220223
PROGNAME=${0##*/}
@@ -234,7 +237,7 @@ CSR_SUBJECT="/"
234237
CURL_USERAGENT="${PROGNAME}/${VERSION}"
235238
DEACTIVATE_AUTH="false"
236239
DEFAULT_REVOKE_CA="https://acme-v02.api.letsencrypt.org"
237-
DNS_EXTRA_WAIT=""
240+
DNS_EXTRA_WAIT=60
238241
DNS_WAIT=10
239242
DOMAIN_KEY_LENGTH=4096
240243
DUAL_RSA_ECDSA="false"
@@ -750,13 +753,37 @@ create_order() {
750753
OrderLink=$(echo "$responseHeaders" | grep -i location | awk '{print $2}'| tr -d '\r\n ')
751754
debug "Order link $OrderLink"
752755
FinalizeLink=$(json_get "$response" "finalize")
753-
dn=0
754-
for d in $alldomains; do
755-
# get authorizations link
756-
AuthLink[$dn]=$(json_get "$response" "identifiers" "value" "$d" "authorizations" "x")
757-
debug "authorizations link for $d - ${AuthLink[$dn]}"
758-
((dn++))
759-
done
756+
757+
if [[ $API -eq 1 ]]; then
758+
dn=0
759+
for d in $alldomains; do
760+
# get authorizations link
761+
AuthLink[$dn]=$(json_get "$response" "identifiers" "value" "$d" "authorizations" "x")
762+
debug "authorizations link for $d - ${AuthLink[$dn]}"
763+
((dn++))
764+
done
765+
else
766+
# Authorization links are unsorted, so fetch the authorization link, find the domain, save response in the correct array position
767+
AuthLinks=$(json_get "$response" "authorizations")
768+
AuthLinkResponse=()
769+
AuthLinkResponseHeader=()
770+
for l in $AuthLinks; do
771+
debug "Requesting authorizations link for $l"
772+
send_signed_request "$l" ""
773+
# Get domain from response
774+
authdomain=$(json_get "$response" "identifier" "value")
775+
# find array position (This is O(n2) but that doubt we'll see performance issues)
776+
dn=0
777+
for d in $alldomains; do
778+
if [ "$d" == "$authdomain" ]; then
779+
debug "Saving authorization response for $authdomain for domain alldomains[$dn]"
780+
AuthLinkResponse[$dn]=$response
781+
AuthLinkResponseHeader[$dn]=$responseHeaders
782+
fi
783+
((dn++))
784+
done
785+
done
786+
fi
760787
}
761788

762789
date_epoc() { # convert the date into epoch time
@@ -801,6 +828,29 @@ error_exit() { # give error message on error exit
801828
exit 1
802829
}
803830

831+
find_dns_utils() {
832+
HAS_NSLOOKUP=false
833+
HAS_DIG_OR_DRILL=""
834+
HAS_HOST=false
835+
if [[ -n "$(command -v nslookup)" ]]; then
836+
debug "HAS NSLOOKUP=true"
837+
HAS_NSLOOKUP=true
838+
fi
839+
840+
if [[ -n "$(command -v drill)" ]]; then
841+
debug "HAS DIG_OR_DRILL=drill"
842+
HAS_DIG_OR_DRILL="drill"
843+
elif [[ -n "$(command -v dig)" ]]; then
844+
debug "HAS DIG_OR_DRILL=dig"
845+
HAS_DIG_OR_DRILL="dig"
846+
fi
847+
848+
if [[ -n "$(command -v host)" ]]; then
849+
debug "HAS HOST=true"
850+
HAS_HOST=true
851+
fi
852+
}
853+
804854
fulfill_challenges() {
805855
dn=0
806856
for d in $alldomains; do
@@ -823,7 +873,9 @@ for d in $alldomains; do
823873
error_exit "new-authz error: $response"
824874
fi
825875
else
826-
send_signed_request "${AuthLink[$dn]}" ""
876+
response=${AuthLinkResponse[$dn]}
877+
responseHeaders=${AuthLinkResponseHeader[$dn]}
878+
response_status=$(json_get "$response" status)
827879
fi
828880

829881
if [[ $response_status == "valid" ]]; then
@@ -841,16 +893,14 @@ for d in $alldomains; do
841893
if [[ $VALIDATE_VIA_DNS == "true" ]]; then # set up the correct DNS token for verification
842894
if [[ $API -eq 1 ]]; then
843895
# get the dns component of the ACME response
844-
# get the token from the dns component
896+
# get the token and uri from the dns component
845897
token=$(json_get "$response" "token" "dns-01")
846-
# get the uri from the dns component
847898
uri=$(json_get "$response" "uri" "dns-01")
848899
debug uri "$uri"
849900
else # APIv2
850901
debug "authlink response = $response"
851-
# get the token from the http-01 component
902+
# get the token and uri from the dns-01 component
852903
token=$(json_get "$response" "challenges" "type" "dns-01" "token")
853-
# get the uri from the http component
854904
uri=$(json_get "$response" "challenges" "type" "dns-01" "url")
855905
debug uri "$uri"
856906
fi
@@ -901,7 +951,6 @@ for d in $alldomains; do
901951
uri=$(json_get "$response" "uri" "http-01")
902952
debug uri "$uri"
903953
else # APIv2
904-
send_signed_request "${AuthLink[$dn]}" ""
905954
debug "authlink response = $response"
906955
# get the token from the http-01 component
907956
token=$(json_get "$response" "challenges" "type" "http-01" "token")
@@ -998,8 +1047,9 @@ if [[ $VALIDATE_VIA_DNS == "true" ]]; then
9981047
| grep ^_acme -A2\
9991048
| grep '"'|awk -F'"' '{ print $2}')
10001049
elif [[ "$DNS_CHECK_FUNC" == "drill" ]] || [[ "$DNS_CHECK_FUNC" == "dig" ]]; then
1050+
debug "$DNS_CHECK_FUNC" TXT "_acme-challenge.${d}" "@${ns}"
10011051
check_result=$($DNS_CHECK_FUNC TXT "_acme-challenge.${d}" "@${ns}" \
1002-
| grep 'IN TXT'|awk -F'"' '{ print $2}')
1052+
| grep 'IN\WTXT'|awk -F'"' '{ print $2}')
10031053
elif [[ "$DNS_CHECK_FUNC" == "host" ]]; then
10041054
check_result=$($DNS_CHECK_FUNC -t TXT "_acme-challenge.${d}" "${ns}" \
10051055
| grep 'descriptive text'|awk -F'"' '{ print $2}')
@@ -1054,10 +1104,11 @@ fi
10541104
}
10551105

10561106
get_auth_dns() { # get the authoritative dns server for a domain (sets primary_ns )
1057-
gad_d="$1" # domain name
1107+
orig_gad_d="$1" # domain name
10581108
gad_s="$PUBLIC_DNS_SERVER" # start with PUBLIC_DNS_SERVER
10591109

10601110
if [[ "$os" == "cygwin" ]]; then
1111+
gad_d="$orig_gad_d"
10611112
all_auth_dns_servers=$(nslookup -type=soa "${d}" ${PUBLIC_DNS_SERVER} 2>/dev/null \
10621113
| grep "primary name server" \
10631114
| awk '{print $NF}')
@@ -1068,85 +1119,125 @@ get_auth_dns() { # get the authoritative dns server for a domain (sets primary_n
10681119
return
10691120
fi
10701121

1071-
if [[ "$DNS_CHECK_FUNC" == "drill" ]] || [[ "$DNS_CHECK_FUNC" == "dig" ]]; then
1072-
if [[ -z "$gad_s" ]]; then #checking for CNAMEs
1073-
res=$($DNS_CHECK_FUNC CNAME "$gad_d"| grep "^$gad_d")
1074-
else
1075-
res=$($DNS_CHECK_FUNC CNAME "$gad_d" "@$gad_s"| grep "^$gad_d")
1076-
fi
1077-
if [[ -n "$res" ]]; then # domain is a CNAME so get main domain
1078-
gad_d=$(echo "$res"| awk '{print $5}' |sed 's/\.$//g')
1079-
fi
1080-
if [[ -z "$gad_s" ]]; then #checking for CNAMEs
1081-
res=$($DNS_CHECK_FUNC NS "$gad_d"| grep "^$gad_d")
1122+
if [[ -n "$HAS_DIG_OR_DRILL" ]]; then
1123+
gad_d="$orig_gad_d"
1124+
debug Using "$HAS_DIG_OR_DRILL SOA +trace +nocomments $gad_d @$gad_s" to find primary nameserver
1125+
# Use SOA +trace to find the name server
1126+
if [[ -z "$gad_s" ]]; then
1127+
res=$($HAS_DIG_OR_DRILL SOA +trace +nocomments "$gad_d" 2>/dev/null | grep "IN\WNS\W" | tail -1)
10821128
else
1083-
res=$($DNS_CHECK_FUNC NS "$gad_d" "@$gad_s"| grep "^$gad_d")
1129+
res=$($HAS_DIG_OR_DRILL SOA +trace +nocomments "$gad_d" "@$gad_s" 2>/dev/null | grep "IN\WNS\W" | tail -1)
10841130
fi
1131+
1132+
# fallback to existing code
10851133
if [[ -z "$res" ]]; then
1086-
error_exit "couldn't find primary DNS server - please set AUTH_DNS_SERVER in config"
1087-
else
1088-
all_auth_dns_servers=$(echo "$res" | awk '$4 ~ "NS" {print $5}' | sed 's/\.$//g'|tr '\n' ' ')
1134+
debug Checking for CNAME using "$HAS_DIG_OR_DRILL CNAME $gad_d @$gad_s"
1135+
if [[ -z "$gad_s" ]]; then #checking for CNAMEs (need grep as dig 9.11 sometimes returns everything not just CNAME entries)
1136+
res=$($HAS_DIG_OR_DRILL CNAME "$gad_d"| grep "^$gad_d" | grep CNAME)
1137+
else
1138+
res=$($HAS_DIG_OR_DRILL CNAME "$gad_d" "@$gad_s"| grep "^$gad_d" | grep CNAME)
1139+
fi
1140+
if [[ -n "$res" ]]; then # domain is a CNAME so get main domain
1141+
gad_d=$(echo "$res"| awk '{print $5}' |sed 's/\.$//g')
1142+
debug Domain is a CNAME, actual domain is "$gad_d"
1143+
fi
1144+
# If gad_d is an A record then this returns the SOA for the root domain, e.g. without the www
1145+
# dig NS ubuntu.getssl.text
1146+
# > getssl.test. IN SOA ns1.duckdns.org
1147+
# If gad_d is a CNAME record then this returns the NS for the domain pointed to by $gad_d
1148+
# dig NS www.getssl.text
1149+
# > www.getssl.test. IN CNAME getssl.test
1150+
# > getssl.test. IN NS ns1.duckdns.org
1151+
debug Using "$HAS_DIG_OR_DRILL NS $gad_d @$gad_s" to find primary nameserver
1152+
if [[ -z "$gad_s" ]]; then
1153+
res=$($HAS_DIG_OR_DRILL NS "$gad_d"| grep -E "IN\W(NS|SOA)\W" | tail -1)
1154+
else
1155+
res=$($HAS_DIG_OR_DRILL NS "$gad_d" "@$gad_s"| grep -E "IN\W(NS|SOA)\W" | tail -1)
1156+
fi
10891157
fi
1090-
if [[ $CHECK_ALL_AUTH_DNS == "true" ]]; then
1091-
primary_ns="$all_auth_dns_servers"
1092-
else
1093-
primary_ns=$(echo "$all_auth_dns_servers" | awk '{print $1}')
1158+
if [[ -n "$res" ]]; then
1159+
all_auth_dns_servers=$(echo "$res" | awk '$4 ~ "NS" {print $5}' | sed 's/\.$//g'|tr '\n' ' ')
1160+
if [[ $CHECK_ALL_AUTH_DNS == "true" ]]; then
1161+
primary_ns="$all_auth_dns_servers"
1162+
else
1163+
primary_ns=$(echo "$all_auth_dns_servers" | awk '{print $1}')
1164+
fi
1165+
return
10941166
fi
1095-
return
10961167
fi
10971168

1098-
if [[ "$DNS_CHECK_FUNC" == "host" ]]; then
1169+
if [[ "$HAS_HOST" == true ]]; then
1170+
gad_d="$orig_gad_d"
1171+
debug Using "host -t NS" to find primary name server for "$gad_d"
10991172
if [[ -z "$gad_s" ]]; then
1100-
res=$($DNS_CHECK_FUNC -t NS "$gad_d"| grep "name server")
1173+
res=$(host -t NS "$gad_d"| grep "name server")
11011174
else
1102-
res=$($DNS_CHECK_FUNC -t NS "$gad_d" "$gad_s"| grep "name server")
1175+
res=$(host -t NS "$gad_d" "$gad_s"| grep "name server")
11031176
fi
1104-
if [[ -z "$res" ]]; then
1105-
error_exit "couldn't find primary DNS server - please set AUTH_DNS_SERVER in config"
1106-
else
1177+
if [[ -n "$res" ]]; then
11071178
all_auth_dns_servers=$(echo "$res" | awk '{print $4}' | sed 's/\.$//g'|tr '\n' ' ')
1179+
if [[ $CHECK_ALL_AUTH_DNS == "true" ]]; then
1180+
primary_ns="$all_auth_dns_servers"
1181+
else
1182+
primary_ns=$(echo "$all_auth_dns_servers" | awk '{print $1}')
1183+
fi
1184+
return
11081185
fi
1109-
if [[ $CHECK_ALL_AUTH_DNS == "true" ]]; then
1110-
primary_ns="$all_auth_dns_servers"
1111-
else
1112-
primary_ns=$(echo "$all_auth_dns_servers" | awk '{print $1}')
1113-
fi
1114-
return
11151186
fi
11161187

1117-
res=$(nslookup -debug -type=soa -type=ns "$gad_d" ${gad_s})
1188+
if [[ "$HAS_NSLOOKUP" == true ]]; then
1189+
gad_d="$orig_gad_d"
1190+
debug Using "nslookup -debug -type=soa -type=ns $gad_d $gad_s" to find primary name server
1191+
res=$(nslookup -debug -type=soa -type=ns "$gad_d" ${gad_s})
1192+
1193+
if [[ "$(echo "$res" | grep -c "Non-authoritative")" -gt 0 ]]; then
1194+
# this is a Non-authoritative server, need to check for an authoritative one.
1195+
gad_s=$(echo "$res" | awk '$2 ~ "nameserver" {print $4; exit }' |sed 's/\.$//g')
1196+
if [[ "$(echo "$res" | grep -c "an't find")" -gt 0 ]]; then
1197+
# if domain name doesn't exist, then find auth servers for next level up
1198+
gad_s=$(echo "$res" | awk '$1 ~ "origin" {print $3; exit }')
1199+
gad_d=$(echo "$res" | awk '$1 ~ "->" {print $2; exit}')
1200+
# handle scenario where awk returns nothing
1201+
if [[ -z "$gad_d" ]]; then
1202+
gad_d="$orig_gad_d"
1203+
fi
1204+
fi
11181205

1119-
if [[ "$(echo "$res" | grep -c "Non-authoritative")" -gt 0 ]]; then
1120-
# this is a Non-authoritative server, need to check for an authoritative one.
1121-
gad_s=$(echo "$res" | awk '$2 ~ "nameserver" {print $4; exit }' |sed 's/\.$//g')
1122-
if [[ "$(echo "$res" | grep -c "an't find")" -gt 0 ]]; then
1123-
# if domain name doesn't exist, then find auth servers for next level up
1124-
gad_s=$(echo "$res" | awk '$1 ~ "origin" {print $3; exit }')
1125-
gad_d=$(echo "$res" | awk '$1 ~ "->" {print $2; exit}')
1206+
# shellcheck disable=SC2086
1207+
res=$(nslookup -debug -type=soa -type=ns "$gad_d" ${gad_s})
11261208
fi
1127-
fi
11281209

1129-
if [[ -z "$gad_s" ]]; then
1130-
res=$(nslookup -debug -type=soa -type=ns "$gad_d")
1131-
else
1132-
res=$(nslookup -debug -type=soa -type=ns "$gad_d" "${gad_s}")
1133-
fi
1210+
if [[ "$(echo "$res" | grep -c "canonical name")" -gt 0 ]]; then
1211+
gad_d=$(echo "$res" | awk ' $2 ~ "canonical" {print $5; exit }' |sed 's/\.$//g')
1212+
elif [[ "$(echo "$res" | grep -c "an't find")" -gt 0 ]]; then
1213+
gad_s=$(echo "$res" | awk ' $1 ~ "origin" {print $3; exit }')
1214+
gad_d=$(echo "$res"| awk '$1 ~ "->" {print $2; exit}')
1215+
# handle scenario where awk returns nothing
1216+
if [[ -z "$gad_d" ]]; then
1217+
gad_d="$orig_gad_d"
1218+
fi
1219+
fi
11341220

1135-
if [[ "$(echo "$res" | grep -c "canonical name")" -gt 0 ]]; then
1136-
gad_d=$(echo "$res" | awk ' $2 ~ "canonical" {print $5; exit }' |sed 's/\.$//g')
1137-
elif [[ "$(echo "$res" | grep -c "an't find")" -gt 0 ]]; then
1138-
gad_s=$(echo "$res" | awk ' $1 ~ "origin" {print $3; exit }')
1139-
gad_d=$(echo "$res"| awk '$1 ~ "->" {print $2; exit}')
1140-
fi
1221+
# shellcheck disable=SC2086
1222+
# not quoting gad_s fixes the nslookup: couldn't get address for '': not found warning (#332)
1223+
all_auth_dns_servers=$(nslookup -debug -type=soa -type=ns "$gad_d" $gad_s \
1224+
| awk '$1 ~ "nameserver" {print $3}' \
1225+
| sed 's/\.$//g'| tr '\n' ' ')
11411226

1142-
all_auth_dns_servers=$(nslookup -type=soa -type=ns "$gad_d" "$gad_s" \
1143-
| awk ' $2 ~ "nameserver" {print $4}' \
1144-
| sed 's/\.$//g'| tr '\n' ' ')
1145-
if [[ $CHECK_ALL_AUTH_DNS == "true" ]]; then
1146-
primary_ns="$all_auth_dns_servers"
1147-
else
1148-
primary_ns=$(echo "$all_auth_dns_servers" | awk '{print $1}')
1227+
if [[ -n "$all_auth_dns_servers" ]]; then
1228+
if [[ $CHECK_ALL_AUTH_DNS == "true" ]]; then
1229+
primary_ns="$all_auth_dns_servers"
1230+
else
1231+
primary_ns=$(echo "$all_auth_dns_servers" | awk '{print $1}')
1232+
fi
1233+
return
1234+
fi
11491235
fi
1236+
1237+
# nslookup on alpine/ubuntu containers doesn't support -debug, print a warning in this case
1238+
# This means getssl cannot check that the DNS record has been updated on the primary name server
1239+
info "Warning: Couldn't find primary DNS server - please set PUBLIC_DNS_SERVER or AUTH_DNS_SERVER in config"
1240+
info "This means getssl cannot check the DNS entry has been updated"
11501241
}
11511242

11521243
get_certificate() { # get certificate for csr, if all domains validated.
@@ -2248,6 +2339,9 @@ set_server_type
22482339
# check config for typical errors.
22492340
check_config
22502341

2342+
# check what dns utils are installed
2343+
find_dns_utils
2344+
22512345
if [[ -e "$DOMAIN_DIR/FORCE_RENEWAL" ]]; then
22522346
rm -f "$DOMAIN_DIR/FORCE_RENEWAL" || error_exit "problem deleting file $DOMAIN_DIR/FORCE_RENEWAL"
22532347
_FORCE_RENEW=1

0 commit comments

Comments
 (0)