Selaa lähdekoodia

[ACME] Validate AAAA, if any, before A - fail on AAAA mismatch (LE prioritization)

André 7 vuotta sitten
vanhempi
sitoutus
f88a72eedd

+ 1 - 0
data/Dockerfiles/acme/Dockerfile

@@ -14,5 +14,6 @@ RUN apk add --update --no-cache \
   tini
 
 COPY docker-entrypoint.sh /srv/docker-entrypoint.sh
+COPY expand6.sh /srv/expand6.sh
 
 CMD ["/sbin/tini", "-g", "--", "/srv/docker-entrypoint.sh"]

+ 50 - 9
data/Dockerfiles/acme/docker-entrypoint.sh

@@ -2,6 +2,9 @@
 set -o pipefail
 exec 5>&1
 
+# Thanks to https://github.com/cvmiller -> https://github.com/cvmiller/expand6
+source /srv/expand6.sh
+
 log_f() {
   if [[ ${2} == "no_nl" ]]; then
     echo -n "$(date) - ${1}"
@@ -69,8 +72,8 @@ get_ipv4(){
   IPV4_SRCS[2]="icanhazip.com"
   IPV4_SRCS[3]="v4.ident.me"
   IPV4_SRCS[4]="ipecho.net/plain"
-  IPV4_SRCS[5]="mailcow.email/ip.php"
-  until [[ ! -z ${IPV4} ]] || [[ ${TRY} -ge 100 ]]; do
+  IPV4_SRCS[5]="ip4.mailcow.email"
+  until [[ ! -z ${IPV4} ]] || [[ ${TRY} -ge 10 ]]; do
     IPV4=$(curl --connect-timeout 3 -m 10 -L4s ${IPV4_SRCS[$RANDOM % ${#IPV4_SRCS[@]} ]} | grep -E "^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$")
     [[ ! -z ${TRY} ]] && sleep 1
     TRY=$((TRY+1))
@@ -78,6 +81,22 @@ get_ipv4(){
   echo ${IPV4}
 }
 
+get_ipv6(){
+  local IPV6=
+  local IPV6_SRCS=
+  local TRY=
+  IPV6_SRCS[0]="ifconfig.co"
+  IPV6_SRCS[1]="icanhazip.com"
+  IPV6_SRCS[2]="v6.ident.me"
+  IPV6_SRCS[3]="ip6.mailcow.email"
+  until [[ ! -z ${IPV6} ]] || [[ ${TRY} -ge 10 ]]; do
+    IPV6=$(curl --connect-timeout 3 -m 10 -L6s ${IPV6_SRCS[$RANDOM % ${#IPV6_SRCS[@]} ]} | grep "^\([0-9a-fA-F]\{0,4\}:\)\{1,7\}[0-9a-fA-F]\{0,4\}$")
+    [[ ! -z ${TRY} ]] && sleep 1
+    TRY=$((TRY+1))
+  done
+  echo ${IPV6}
+}
+
 [[ ! -f ${ACME_BASE}/dhparams.pem ]] && cp ${SSL_EXAMPLE}/dhparams.pem ${ACME_BASE}/dhparams.pem
 
 if [[ -f ${ACME_BASE}/cert.pem ]] && [[ -f ${ACME_BASE}/key.pem ]]; then
@@ -112,8 +131,8 @@ else
   fi
 fi
 
+log_f "Waiting for database... "
 while ! mysqladmin ping --host mysql -u${DBUSER} -p${DBPASS} --silent; do
-  echo "Waiting for database to come up..."
   sleep 2
 done
 
@@ -128,7 +147,11 @@ while true; do
   declare -a VALIDATED_CONFIG_DOMAINS
   declare -a ADDITIONAL_VALIDATED_SAN
   IFS=',' read -r -a ADDITIONAL_SAN_ARR <<< "${ADDITIONAL_SAN}"
+  log_f "Detecting IP addresses... " no_nl
   IPV4=$(get_ipv4)
+  IPV6=$(get_ipv6)
+  log_f "OK" no_date
+
   # Container ids may have changed
   CONTAINERS_RESTART=($(curl --silent http://dockerapi:8080/containers/json | jq -r '.[] | {name: .Config.Labels["com.docker.compose.service"], id: .Id}' | jq -rc 'select( .name | tostring | contains("nginx-mailcow") or contains("postfix-mailcow") or contains("dovecot-mailcow")) | .id' | tr "\n" " "))
 
@@ -138,7 +161,7 @@ while true; do
     DOMAIN_TABLE=$(mysql -h mysql-mailcow -u ${DBUSER} -p${DBPASS} ${DBNAME} -e "SHOW TABLES LIKE 'domain'" -Bs)
     [[ -z ${DOMAIN_TABLE} ]] && sleep 10
   done
-  log_f "Found domain tables." no_date
+  log_f "OK" no_date
 
   while read domains; do
     SQL_DOMAIN_ARR+=("${domains}")
@@ -146,7 +169,16 @@ while true; do
 
   for SQL_DOMAIN in "${SQL_DOMAIN_ARR[@]}"; do
     A_CONFIG=$(dig A autoconfig.${SQL_DOMAIN} +short | tail -n 1)
-    if [[ ! -z ${A_CONFIG} ]]; then
+    AAAA_CONFIG=$(dig AAAA autoconfig.${SQL_DOMAIN} +short | tail -n 1)
+    if [[ ! -z ${AAAA_CONFIG} ]]; then
+      log_f "Found AAAA record for autoconfig.${SQL_DOMAIN}: ${AAAA_CONFIG} - skipping A record check"
+      if [[ $(expand ${IPV6:-"0000:0000:0000:0000:0000:0000:0000:0000"}) == $(expand ${AAAA_CONFIG}) ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
+        log_f "Confirmed AAAA record autoconfig.${SQL_DOMAIN}"
+        VALIDATED_CONFIG_DOMAINS+=("autoconfig.${SQL_DOMAIN}")
+      else
+        log_f "Cannot match your IP ${IPV6:-NO_IPV6_LINK} against hostname autoconfig.${SQL_DOMAIN} ($(expand ${AAAA_CONFIG}))"
+      fi
+    elif [[ ! -z ${A_CONFIG} ]]; then
       log_f "Found A record for autoconfig.${SQL_DOMAIN}: ${A_CONFIG}"
       if [[ ${IPV4:-ERR} == ${A_CONFIG} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
         log_f "Confirmed A record autoconfig.${SQL_DOMAIN}"
@@ -155,11 +187,20 @@ while true; do
         log_f "Cannot match your IP ${IPV4} against hostname autoconfig.${SQL_DOMAIN} (${A_CONFIG})"
       fi
     else
-      log_f "No A record for autoconfig.${SQL_DOMAIN} found"
+      log_f "No A or AAAA record found for hostname autoconfig.${SQL_DOMAIN}"
     fi
 
-        A_DISCOVER=$(dig A autodiscover.${SQL_DOMAIN} +short | tail -n 1)
-    if [[ ! -z ${A_DISCOVER} ]]; then
+    A_DISCOVER=$(dig A autodiscover.${SQL_DOMAIN} +short | tail -n 1)
+    AAAA_DISCOVER=$(dig AAAA autodiscover.${SQL_DOMAIN} +short | tail -n 1)
+    if [[ ! -z ${AAAA_DISCOVER} ]]; then
+      log_f "Found AAAA record for autodiscover.${SQL_DOMAIN}: ${AAAA_DISCOVER} - skipping A record check"
+      if [[ $(expand ${IPV6:-"0000:0000:0000:0000:0000:0000:0000:0000"}) == $(expand ${AAAA_DISCOVER}) ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
+        log_f "Confirmed AAAA record autodiscover.${SQL_DOMAIN}"
+        VALIDATED_CONFIG_DOMAINS+=("autodiscover.${SQL_DOMAIN}")
+      else
+        log_f "Cannot match your IP ${IPV6:-NO_IPV6_LINK} against hostname autodiscover.${SQL_DOMAIN} ($(expand ${AAAA_DISCOVER}))"
+      fi
+    elif [[ ! -z ${A_DISCOVER} ]]; then
       log_f "Found A record for autodiscover.${SQL_DOMAIN}: ${A_DISCOVER}"
       if [[ ${IPV4:-ERR} == ${A_DISCOVER} ]] || [[ ${SKIP_IP_CHECK} == "y" ]]; then
         log_f "Confirmed A record autodiscover.${SQL_DOMAIN}"
@@ -168,7 +209,7 @@ while true; do
         log_f "Cannot match your IP ${IPV4} against hostname autodiscover.${SQL_DOMAIN} (${A_DISCOVER})"
       fi
     else
-      log_f "No A record for autodiscover.${SQL_DOMAIN} found"
+      log_f "No A or AAAA record found for hostname autodiscover.${SQL_DOMAIN}"
     fi
   done
 

+ 131 - 0
data/Dockerfiles/acme/expand6.sh

@@ -0,0 +1,131 @@
+#!/bin/bash
+
+##################################################################################
+#
+#  Copyright (C) 2017 Craig Miller
+#
+#  See the file "LICENSE" for information on usage and redistribution
+#  of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#  Distributed under GPLv2 License
+#
+##################################################################################
+
+
+# IPv6 Address Expansion functions
+#
+# by Craig Miller   19 Feb 2017
+#
+# 16 Nov 2017 v0.93 - added CLI functionality
+
+
+VERSION=0.93
+
+empty_addr="0000:0000:0000:0000:0000:0000:0000:0000"
+empty_addr_len=${#empty_addr}
+
+function usage {
+               echo " $0 - expand compressed IPv6 addresss "
+         echo " e.g. $0 2001:db8:1:12:123::456 "
+         echo " "
+         echo " -t  self test"
+         echo " "
+         echo " By Craig Miller - Version: $VERSION"
+         exit 1
+           }
+
+if [ "$1" == "-h" ]; then
+  #call help
+  usage
+fi
+
+#
+# Expands IPv6 quibble to 4 digits with leading zeros e.g. db8 -> 0db8
+#
+# Returns string with expanded quibble
+
+function expand_quibble() {
+  addr=$1
+  # create array of quibbles
+  addr_array=(${addr//:/ })
+  addr_array_len=${#addr_array[@]}
+  # step thru quibbles
+  for ((i=0; i< $addr_array_len ; i++ ))
+  do
+    quibble=${addr_array[$i]}
+    quibble_len=${#quibble}
+    case $quibble_len in
+      1) quibble="000$quibble";;
+      2) quibble="00$quibble";;
+      3) quibble="0$quibble";;
+    esac
+    addr_array[$i]=$quibble 
+  done
+  # reconstruct addr from quibbles
+  return_str=${addr_array[*]}
+  return_str="${return_str// /:}"
+  echo $return_str
+}
+
+#
+# Expands IPv6 address :: format to full zeros
+#
+# Returns string with expanded address
+
+function expand() {
+  if [[ $1 == *"::"* ]]; then
+    # check for leading zeros on front_addr
+    if [[ $1 == "::"* ]]; then
+      front_addr=0
+    else
+      front_addr=$(echo $1 | sed -r 's;([^ ]+)::.*;\1;') 
+    fi
+    # check for trailing zeros on back_addr
+    if [[ $1 == *"::" ]]; then
+      back_addr=0
+    else
+      back_addr=$(echo $1 | sed -r 's;.*::([^ ]+);\1;') 
+    fi
+    front_addr=$(expand_quibble $front_addr)
+    back_addr=$(expand_quibble $back_addr)
+    
+    new_addr=$empty_addr
+    front_addr_len=${#front_addr}
+    back_addr_len=${#back_addr}
+    # calculate fill needed
+    num_zeros=$(($empty_addr_len - $front_addr_len - $back_addr_len - 1))
+
+    #fill_str=${empty_addr[0]:0:$num_zeros}
+    new_addr="$front_addr:${empty_addr[0]:0:$num_zeros}$back_addr"
+    
+    # return expanded address
+    echo $new_addr
+  else
+    # return input with expandd quibbles
+    expand_quibble $1
+  fi
+}
+
+# self test - call with '-t' parameter
+if [ "$1" == "-t" ]; then
+  # add address examples to test
+  expand fd11::1d70:cf84:18ef:d056
+  expand 2a01::1
+  expand fe80::f203:8cff:fe3f:f041
+  expand 2001:db8:123::5
+  expand 2001:470:ebbd:0:f203:8cff:fe3f:f041
+  # special cases
+  expand ::1
+  expand fd32:197d:3022:1101::
+  exit 1
+fi
+
+# allow script to be sourced (with no arguements)
+if [[ $1 != "" ]]; then
+  # validate input is an IPv6 address
+  if [[ $1 == *":"* ]]; then
+    expand $1
+  else
+    echo "ERROR: unregcognized IPv6 address $1"
+    exit 1
+  fi
+fi