33
44"""Check if the domains is reported as malicious in Quad9 database"""
55
6- import logging
7- from typing import Tuple
86from urllib .parse import urlparse
97
108import requests
1412
1513from ..dns_responses import malicious_detector_response
1614
17- logger = logging .getLogger (__name__ )
18-
1915
2016class Quad9MaliciousDetector (classes .ObservableAnalyzer ):
2117 """Check if a domain is malicious by Quad9 public resolver.
@@ -27,9 +23,9 @@ class Quad9MaliciousDetector(classes.ObservableAnalyzer):
2723 we can guess that the domain was in the Quad9 blacklist.
2824 """
2925
30- HEADERS = {"Accept" : "application/dns-json" }
31- QUAD9_URL = "https://dns.quad9.net:5053/dns-query"
32- GOOGLE_URL = "https://dns.google.com/resolve"
26+ headers : dict = {"Accept" : "application/dns-json" }
27+ url : str = "https://dns.quad9.net:5053/dns-query"
28+ google_url : str = "https://dns.google.com/resolve"
3329
3430 def update (self ) -> bool :
3531 pass
@@ -40,7 +36,7 @@ def run(self):
4036 if self .observable_classification == self .ObservableTypes .URL :
4137 observable = urlparse (self .observable_name ).hostname
4238
43- quad9_answer , timeout = self ._quad9_dns_query (observable )
39+ quad9_answer = self ._quad9_dns_query (observable )
4440 # if Quad9 has not an answer the site could be malicious
4541 if not quad9_answer :
4642 # Google dns request
@@ -50,38 +46,35 @@ def run(self):
5046 if google_answer :
5147 return malicious_detector_response (self .observable_name , True )
5248
53- return malicious_detector_response (self .observable_name , False , timeout )
49+ return malicious_detector_response (self .observable_name , False )
5450
55- def _quad9_dns_query (self , observable ) -> Tuple [ bool , bool ] :
51+ def _quad9_dns_query (self , observable ) -> bool :
5652 """Perform a DNS query with Quad9 service, return True if Quad9 answer the
5753 DNS query with a non-empty response.
5854
5955 :param observable: domain to resolve
6056 :type observable: str
61- :return: True in case of answer for the DNS query else False.
62- :rtype: bool
6357 """
64- answer_found = False
65- timeout = False
6658 params = {"name" : observable }
6759
68- quad9_response = requests .get (
69- self .QUAD9_URL , headers = self .HEADERS , params = params
70- )
71- if quad9_response .status_code == 503 :
72- msg = (
73- "503 status code! "
74- "It may be normal for this service to"
75- " happen from time to time"
76- )
77- logger .info (msg )
78- self .report .errors .append (msg )
79- timeout = True
80- return answer_found , timeout
81- quad9_response .raise_for_status ()
82- answer_found = bool (quad9_response .json ().get ("Answer" , None ))
83-
84- return answer_found , timeout
60+ # sometimes it can respond with 503, I suppose to avoid DoS.
61+ # In 1k requests just 20 fails and at least with 30 requests between 2 failures
62+ # with 2 or 3 attemps the analyzer should get the data
63+ attempt_number = 3
64+ for attempt in range (0 , attempt_number ):
65+ try :
66+ quad9_response = requests .get (
67+ self .url , headers = self .headers , params = params , timeout = 10
68+ )
69+ except requests .exceptions .ConnectionError as exception :
70+ # if the last attempt fails, raise an error
71+ if attempt == attempt_number - 1 :
72+ raise exception
73+ else :
74+ quad9_response .raise_for_status ()
75+ break
76+
77+ return bool (quad9_response .json ().get ("Answer" , None ))
8578
8679 def _google_dns_query (self , observable ) -> bool :
8780 """Perform a DNS query with Google service, return True if Google answer the
@@ -93,7 +86,7 @@ def _google_dns_query(self, observable) -> bool:
9386 :rtype: bool
9487 """
9588 params = {"name" : observable }
96- google_response = requests .get (self .GOOGLE_URL , params = params )
89+ google_response = requests .get (self .google_url , params = params )
9790 google_response .raise_for_status ()
9891
9992 return bool (google_response .json ().get ("Answer" , None ))
0 commit comments