Skip to content

Commit 4983dec

Browse files
committed
bug fix: ssl timeout issues
1 parent 46e40d6 commit 4983dec

File tree

1 file changed

+119
-77
lines changed

1 file changed

+119
-77
lines changed

plogical/customACME.py

Lines changed: 119 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ def _finalize_order(self, csr):
631631

632632
if response.status_code == 200:
633633
# Wait for order to be processed
634-
max_attempts = 30
634+
max_attempts = 10
635635
delay = 2
636636
for attempt in range(max_attempts):
637637
if not self._get_nonce():
@@ -667,7 +667,7 @@ def _finalize_order(self, csr):
667667
f'Order status check failed, attempt {attempt + 1}/{max_attempts}')
668668
time.sleep(delay)
669669

670-
logging.CyberCPLogFileWriter.writeToFile('Order processing timed out')
670+
logging.CyberCPLogFileWriter.writeToFile('Order processing timed out after 20 seconds')
671671
return False
672672
return False
673673
except Exception as e:
@@ -709,7 +709,7 @@ def _download_certificate(self):
709709
logging.CyberCPLogFileWriter.writeToFile(f'Error downloading certificate: {str(e)}')
710710
return None
711711

712-
def _wait_for_challenge_validation(self, challenge_url, max_attempts=30, delay=2):
712+
def _wait_for_challenge_validation(self, challenge_url, max_attempts=10, delay=2):
713713
"""Wait for challenge to be validated by the ACME server"""
714714
try:
715715
logging.CyberCPLogFileWriter.writeToFile(f'Waiting for challenge validation at URL: {challenge_url}')
@@ -736,14 +736,36 @@ def _wait_for_challenge_validation(self, challenge_url, max_attempts=30, delay=2
736736
logging.CyberCPLogFileWriter.writeToFile('Challenge validated successfully')
737737
return True
738738
elif challenge_status == 'invalid':
739-
logging.CyberCPLogFileWriter.writeToFile('Challenge validation failed')
739+
# Check for DNS-related errors in the response
740+
response_data = response.json()
741+
error_detail = response_data.get('error', {}).get('detail', '')
742+
743+
# Common DNS-related error patterns
744+
dns_errors = [
745+
'NXDOMAIN',
746+
'DNS problem',
747+
'No valid IP addresses',
748+
'could not be resolved',
749+
'DNS resolution',
750+
'Timeout during connect',
751+
'Connection refused',
752+
'no such host'
753+
]
754+
755+
is_dns_error = any(err.lower() in error_detail.lower() for err in dns_errors)
756+
if is_dns_error:
757+
logging.CyberCPLogFileWriter.writeToFile(
758+
f'Challenge validation failed due to DNS issue: {error_detail}')
759+
else:
760+
logging.CyberCPLogFileWriter.writeToFile(
761+
f'Challenge validation failed: {error_detail}')
740762
return False
741763

742764
logging.CyberCPLogFileWriter.writeToFile(
743765
f'Challenge still pending, attempt {attempt + 1}/{max_attempts}')
744766
time.sleep(delay)
745767

746-
logging.CyberCPLogFileWriter.writeToFile('Challenge validation timed out')
768+
logging.CyberCPLogFileWriter.writeToFile('Challenge validation timed out after 20 seconds')
747769
return False
748770
except Exception as e:
749771
logging.CyberCPLogFileWriter.writeToFile(f'Error waiting for challenge validation: {str(e)}')
@@ -768,95 +790,115 @@ def _check_dns_record(self, domain):
768790
try:
769791
logging.CyberCPLogFileWriter.writeToFile(f'Checking DNS records for domain: {domain}')
770792

771-
# List of public DNS servers to check against
793+
# List of public DNS servers to check against (reduced to 2 for faster checks)
772794
dns_servers = [
773795
'8.8.8.8', # Google DNS
774-
'1.1.1.1', # Cloudflare DNS
775-
'208.67.222.222' # OpenDNS
796+
'1.1.1.1' # Cloudflare DNS
776797
]
777798

778-
# Function to check DNS record with specific DNS server
779-
def check_with_dns_server(server, record_type='A'):
780-
try:
781-
# Create a new socket for each check
782-
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
783-
sock.settimeout(5) # 5 second timeout
784-
785-
# Set the DNS server
786-
sock.connect((server, 53))
787-
788-
# Create DNS query
789-
query = bytearray()
790-
# DNS header
791-
query += b'\x00\x01' # Transaction ID
792-
query += b'\x01\x00' # Flags: Standard query
793-
query += b'\x00\x01' # Questions: 1
794-
query += b'\x00\x00' # Answer RRs: 0
795-
query += b'\x00\x00' # Authority RRs: 0
796-
query += b'\x00\x00' # Additional RRs: 0
797-
798-
# Domain name
799-
for part in domain.split('.'):
800-
query.append(len(part))
801-
query.extend(part.encode())
802-
query += b'\x00' # End of domain name
803-
804-
# Query type and class
805-
if record_type == 'A':
806-
query += b'\x00\x01' # Type: A
807-
else: # AAAA
808-
query += b'\x00\x1c' # Type: AAAA
809-
query += b'\x00\x01' # Class: IN
810-
811-
# Send query
812-
sock.send(query)
813-
814-
# Receive response
815-
response = sock.recv(1024)
816-
817-
# Check if we got a valid response
818-
if len(response) > 12: # Minimum DNS response size
819-
# Check if there are answers in the response
820-
answer_count = int.from_bytes(response[6:8], 'big')
821-
if answer_count > 0:
822-
return True
823-
824-
return False
825-
except Exception as e:
826-
logging.CyberCPLogFileWriter.writeToFile(f'Error checking DNS with server {server}: {str(e)}')
827-
return False
828-
finally:
829-
sock.close()
830-
831-
# Check A records (IPv4) with multiple DNS servers
799+
# Use system's DNS resolver as primary check (faster and respects local config)
832800
a_record_found = False
833-
for server in dns_servers:
834-
if check_with_dns_server(server, 'A'):
835-
a_record_found = True
836-
break
837-
838-
# Check AAAA records (IPv6) with multiple DNS servers
839801
aaaa_record_found = False
840-
for server in dns_servers:
841-
if check_with_dns_server(server, 'AAAA'):
842-
aaaa_record_found = True
843-
break
844802

845-
# Also check with system's DNS resolver as a fallback
846803
try:
847-
# Try to resolve A record (IPv4)
804+
# Try to resolve A record (IPv4) with timeout
805+
old_timeout = socket.getdefaulttimeout()
806+
socket.setdefaulttimeout(3) # 3 second timeout
848807
socket.gethostbyname(domain)
849808
a_record_found = True
809+
socket.setdefaulttimeout(old_timeout)
850810
except socket.gaierror:
811+
socket.setdefaulttimeout(old_timeout)
812+
pass
813+
except socket.timeout:
814+
socket.setdefaulttimeout(old_timeout)
851815
pass
852816

853817
try:
854-
# Try to resolve AAAA record (IPv6)
818+
# Try to resolve AAAA record (IPv6) with timeout
819+
old_timeout = socket.getdefaulttimeout()
820+
socket.setdefaulttimeout(3) # 3 second timeout
855821
socket.getaddrinfo(domain, None, socket.AF_INET6)
856822
aaaa_record_found = True
823+
socket.setdefaulttimeout(old_timeout)
857824
except socket.gaierror:
825+
socket.setdefaulttimeout(old_timeout)
826+
pass
827+
except socket.timeout:
828+
socket.setdefaulttimeout(old_timeout)
858829
pass
859830

831+
# If system resolver fails, try public DNS servers as fallback
832+
if not a_record_found and not aaaa_record_found:
833+
# Function to check DNS record with specific DNS server
834+
def check_with_dns_server(server, record_type='A'):
835+
try:
836+
# Create a new socket for each check
837+
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
838+
sock.settimeout(2) # 2 second timeout
839+
840+
# Set the DNS server
841+
sock.connect((server, 53))
842+
843+
# Create DNS query
844+
query = bytearray()
845+
# DNS header
846+
query += b'\x00\x01' # Transaction ID
847+
query += b'\x01\x00' # Flags: Standard query
848+
query += b'\x00\x01' # Questions: 1
849+
query += b'\x00\x00' # Answer RRs: 0
850+
query += b'\x00\x00' # Authority RRs: 0
851+
query += b'\x00\x00' # Additional RRs: 0
852+
853+
# Domain name
854+
for part in domain.split('.'):
855+
query.append(len(part))
856+
query.extend(part.encode())
857+
query += b'\x00' # End of domain name
858+
859+
# Query type and class
860+
if record_type == 'A':
861+
query += b'\x00\x01' # Type: A
862+
else: # AAAA
863+
query += b'\x00\x1c' # Type: AAAA
864+
query += b'\x00\x01' # Class: IN
865+
866+
# Send query
867+
sock.send(query)
868+
869+
# Receive response
870+
response = sock.recv(1024)
871+
872+
# Check if we got a valid response
873+
if len(response) > 12: # Minimum DNS response size
874+
# Check if there are answers in the response
875+
answer_count = int.from_bytes(response[6:8], 'big')
876+
if answer_count > 0:
877+
return True
878+
879+
return False
880+
except Exception as e:
881+
logging.CyberCPLogFileWriter.writeToFile(f'Error checking DNS with server {server}: {str(e)}')
882+
return False
883+
finally:
884+
try:
885+
sock.close()
886+
except:
887+
pass
888+
889+
# Check A records (IPv4) with first available DNS server only
890+
for server in dns_servers:
891+
if check_with_dns_server(server, 'A'):
892+
a_record_found = True
893+
break
894+
895+
# Only check AAAA if A record wasn't found and we still have time
896+
if not a_record_found:
897+
for server in dns_servers:
898+
if check_with_dns_server(server, 'AAAA'):
899+
aaaa_record_found = True
900+
break
901+
860902
# Log the results
861903
if a_record_found:
862904
logging.CyberCPLogFileWriter.writeToFile(f'IPv4 DNS record found for domain: {domain}')
@@ -870,7 +912,7 @@ def check_with_dns_server(server, record_type='A'):
870912
logging.CyberCPLogFileWriter.writeToFile(f'Error checking DNS records: {str(e)}')
871913
return False
872914

873-
def _wait_for_order_processing(self, max_attempts=30, delay=2):
915+
def _wait_for_order_processing(self, max_attempts=10, delay=2):
874916
"""Wait for order to be processed"""
875917
try:
876918
logging.CyberCPLogFileWriter.writeToFile('Waiting for order processing...')
@@ -910,7 +952,7 @@ def _wait_for_order_processing(self, max_attempts=30, delay=2):
910952
f'Order status check failed, attempt {attempt + 1}/{max_attempts}')
911953
time.sleep(delay)
912954

913-
logging.CyberCPLogFileWriter.writeToFile('Order processing timed out')
955+
logging.CyberCPLogFileWriter.writeToFile('Order processing timed out after 20 seconds')
914956
return False
915957
except Exception as e:
916958
logging.CyberCPLogFileWriter.writeToFile(f'Error waiting for order processing: {str(e)}')

0 commit comments

Comments
 (0)