Timeouts in HTTP requests

This commit is contained in:
Stephane Bortzmeyer 2021-07-07 11:57:27 +02:00
parent a3a1f8c0d4
commit 6b4f5b228e
3 changed files with 40 additions and 13 deletions

View File

@ -43,10 +43,10 @@ domain = None
critical_t = datetime.timedelta(days=2) critical_t = datetime.timedelta(days=2)
warning_t = datetime.timedelta(days=7) warning_t = datetime.timedelta(days=7)
unixtime = False unixtime = False
# TODO implement timeout for HTTPS requests. -t option. Does Requests allow it? timeout = 20 # Seconds
def usage(msg=None): def usage(msg=None):
print("Usage: %s -H domain-name [-c critical -w warning -u]" % sys.argv[0], end="") print("Usage: %s -H domain-name [-c critical -w warning -u -t timeout]" % sys.argv[0], end="")
if msg is not None and msg != "": if msg is not None and msg != "":
print(" (%s)" % msg) print(" (%s)" % msg)
else: else:
@ -73,6 +73,13 @@ def warning(msg=None):
details() details()
sys.exit(STATE_WARNING) sys.exit(STATE_WARNING)
def unknown(msg=None):
if msg is None:
msg = "Unknown"
print("%s UNKNOWN: %s" % (domain, msg), end="")
details()
sys.exit(STATE_UNKNOWN)
def ok(msg=None): def ok(msg=None):
if msg is None: if msg is None:
msg = "Unknown message but everything is OK" msg = "Unknown message but everything is OK"
@ -81,8 +88,10 @@ def ok(msg=None):
sys.exit(STATE_OK) sys.exit(STATE_OK)
try: try:
optlist, args = getopt.getopt (sys.argv[1:], "c:hH:uvVw:", optlist, args = getopt.getopt (sys.argv[1:], "c:hH:t:uvVw:",
["critical=", "expiration", "help", "unixtime", "verbose", "version", "warning="]) ["critical=", "expiration", "help",
"timeout=", "unixtime", "verbose",
"version", "warning="])
for option, value in optlist: for option, value in optlist:
if option == "--critical" or option == "-c": if option == "--critical" or option == "-c":
critical_t = datetime.timedelta(days=int(value)) critical_t = datetime.timedelta(days=int(value))
@ -91,6 +100,10 @@ try:
sys.exit(STATE_OK) sys.exit(STATE_OK)
elif option == "--hostname" or option == "-H": elif option == "--hostname" or option == "-H":
domain = value domain = value
elif option == "--timeout" or option == "-t":
timeout = int(value)
elif option == "--unixtime" or option == "-u":
unixtime = True
elif option == "--verbose" or option == "-v": elif option == "--verbose" or option == "-v":
verbose = True verbose = True
elif option == "--version" or option == "-V": elif option == "--version" or option == "-V":
@ -98,8 +111,6 @@ try:
sys.exit(STATE_OK) sys.exit(STATE_OK)
elif option == "--warning" or option == "-w": elif option == "--warning" or option == "-w":
warning_t = datetime.timedelta(days=int(value)) warning_t = datetime.timedelta(days=int(value))
elif option == "--unixtime" or option == "-u":
unixtime = True
else: else:
# Should never occur, it is trapped by getopt # Should never occur, it is trapped by getopt
print("Unknown option %s" % option) print("Unknown option %s" % option)
@ -113,13 +124,19 @@ if len(args) != 0:
if domain is None: if domain is None:
usage("-H is mandatory") usage("-H is mandatory")
sys.exit(STATE_UNKNOWN) sys.exit(STATE_UNKNOWN)
database = ianardap.IanaRDAPDatabase() try:
database = ianardap.IanaRDAPDatabase()
except Exception as e:
unknown("Exception when retrieving the IANA database: \"%s\"" % e)
server = database.find(domain) server = database.find(domain)
if server is None: if server is None:
error("No RDAP server found for %s" % domain) unknown("No RDAP server found for %s" % domain)
if server.endswith("/"): if server.endswith("/"):
server = server[:-1] # Donuts RDAP server balks when there are two slashes and reply 404 server = server[:-1] # Donuts RDAP server balks when there are two slashes and reply 404
response = requests.get("%s/domain/%s" % (server, domain)) try:
response = requests.get("%s/domain/%s" % (server, domain), timeout=timeout)
except requests.exceptions.Timeout:
unknown("Timeout when trying to reach %s" % server)
if response.status_code != 200: if response.status_code != 200:
error("Invalid RDAP return code: %s" % response.status_code) error("Invalid RDAP return code: %s" % response.status_code)
rdap = json.loads(response.content) rdap = json.loads(response.content)
@ -136,8 +153,7 @@ for event in rdap["events"]:
dt = re.sub(r"\+([0-9]{2}):([0-9]{2})$", r"+\1\2", event["eventDate"]) dt = re.sub(r"\+([0-9]{2}):([0-9]{2})$", r"+\1\2", event["eventDate"])
expiration = datetime.datetime.strptime(dt, RFC3339TZ) expiration = datetime.datetime.strptime(dt, RFC3339TZ)
else: else:
print("No recognized format for datetime \"%s\"" % event["eventDate"]) unknown("No recognized format for datetime \"%s\"" % event["eventDate"])
sys.exit(STATE_UNKNOWN)
now = datetime.datetime.now(tz=UTCINFO) now = datetime.datetime.now(tz=UTCINFO)
if unixtime == True: if unixtime == True:
print(int(expiration.strftime("%s"))) print(int(expiration.strftime("%s")))

View File

@ -17,6 +17,7 @@ import fcntl
IANABASE = "https://data.iana.org/rdap/dns.json" IANABASE = "https://data.iana.org/rdap/dns.json"
CACHE = os.environ["HOME"] + "/.ianardapcache.json" CACHE = os.environ["HOME"] + "/.ianardapcache.json"
MAXAGE = 24 # Hours MAXAGE = 24 # Hours
IANATIMEOUT = 10
class IanaRDAPDatabase(): class IanaRDAPDatabase():
@ -36,7 +37,7 @@ class IanaRDAPDatabase():
self.unlock() self.unlock()
else: else:
self.unlock() self.unlock()
response = requests.get(IANABASE) response = requests.get(IANABASE, timeout=IANATIMEOUT)
if response.status_code != 200: if response.status_code != 200:
raise Exception("Invalid HTTPS return code when trying to get %s: %s" % (IANABASE, response.status_code)) raise Exception("Invalid HTTPS return code when trying to get %s: %s" % (IANABASE, response.status_code))
content = response.content content = response.content

View File

@ -33,7 +33,7 @@ tests:
args: args:
- '-H' - '-H'
- 'bie.re' - 'bie.re'
retcode: 2 retcode: 3
partstdout: 'No RDAP server' partstdout: 'No RDAP server'
# 2021-07-05: no expiration in RDAP for this TLD (but there is one # 2021-07-05: no expiration in RDAP for this TLD (but there is one
@ -45,6 +45,16 @@ tests:
retcode: 2 retcode: 2
partstdout: 'No expiration found' partstdout: 'No expiration found'
# Far away and slow, timeout is expected
- exe: './check_expire'
args:
- '-t'
- '1'
- '-H'
- 'nic.ar'
retcode: 3
partstdout: 'Timeout'
- exe: './check_expire' - exe: './check_expire'
args: args:
- '-H' - '-H'