88import re
99import sys
1010import bz2
11- import pathlib
1211import requests
12+ from datetime import datetime , timedelta
13+ from pathlib import Path
1314
15+ from intelmq import VAR_STATE_PATH
1416from intelmq .lib .bot import ExpertBot
1517from intelmq .lib .exceptions import MissingDependencyError
1618from intelmq .lib .utils import get_bots_settings , create_request_session
2527
2628class ASNLookupExpertBot (ExpertBot ):
2729 """Add ASN and netmask information from a local BGP dump"""
28- database = None # TODO: should be pathlib.Path
30+ database : str = f' { VAR_STATE_PATH } asn_lookup/ipasn.dat' # TODO: should be pathlib.Path
2931 autoupdate_cached_database : bool = True # Activate/deactivate update-database functionality
3032
3133 def init (self ):
@@ -35,11 +37,11 @@ def init(self):
3537 try :
3638 self ._database = pyasn .pyasn (self .database )
3739 except OSError :
38- self .logger .error ("pyasn data file does not exist or could not be "
39- "accessed in %r." , self .database )
40- self .logger .error ("Read 'bots/experts/asn_lookup/README' and "
41- "follow the procedure." )
40+ raise ValueError (f"pyasn data file does not exist or could not be accessed in { self .database !r} . " ,
41+ "Please see https://docs.intelmq.org/latest/user/bots/#asn-lookup" )
4242 self .stop ()
43+ if not Path (self .database ).is_file ():
44+ raise ValueError ('Database file does not exist or is not a file.' )
4345
4446 def process (self ):
4547 event = self .receive_message ()
@@ -66,12 +68,20 @@ def process(self):
6668
6769 @staticmethod
6870 def check (parameters ):
69- if not os .path .exists (parameters .get ('database' , '' )):
70- return [["error" , "File given as parameter 'database' does not exist." ]]
71+ database_path = Path (parameters .get ('database' , '' ))
72+ if not database_path .exists ():
73+ return [["warning" , f"File given as parameter 'database' ({ database_path !s} ) does not exist. You may need to trigger first downloading manually. See: https://docs.intelmq.org/latest/user/bots/#asn-lookup." ]]
74+ elif not database_path .is_file ():
75+ return [["error" , f"Parameter 'database' ({ database_path !s} ) exists, but is not a file." ]]
7176 try :
7277 pyasn .pyasn (parameters ['database' ])
7378 except Exception as exc :
74- return [["error" , "Error reading database: %r." % exc ]]
79+ return [["error" , f"Error reading database ({ database_path !s} ): { exc !r} ." ]]
80+
81+ # Check the age of the database file
82+ # use local time zone for both time operations
83+ if datetime .now () - datetime .fromtimestamp (database_path .stat ().st_mtime ) < timedelta (weeks = 1 ):
84+ return [["warning" , f"Database ({ database_path !s} ) is older than one week. Check the auto update, see: https://docs.intelmq.org/latest/user/bots/#asn-lookup." ]]
7585
7686 @classmethod
7787 def run (cls , parsed_args = None ):
@@ -112,6 +122,12 @@ def update_database(cls, verbose=False):
112122 if pyasn is None :
113123 raise MissingDependencyError ("pyasn" )
114124
125+ for database_path in set (bots .values ()):
126+ if not Path (database_path ).is_file ():
127+ raise ValueError ('Database file does not exist or is not a file.' )
128+ elif not os .access (database_path , os .W_OK ):
129+ raise ValueError ('Database file is not writeable.' )
130+
115131 try :
116132 if verbose :
117133 print ("Searching for the latest database update..." )
@@ -159,7 +175,7 @@ def update_database(cls, verbose=False):
159175 prefixes = pyasn .mrtx .parse_mrt_file (archive , print_progress = False , skip_record_on_error = True )
160176
161177 for database_path in set (bots .values ()):
162- database_dir = pathlib . Path (database_path ).parent
178+ database_dir = Path (database_path ).parent
163179 database_dir .mkdir (parents = True , exist_ok = True )
164180 pyasn .mrtx .dump_prefixes_to_file (prefixes , database_path )
165181
0 commit comments