diff --git a/parsedmarc/__init__.py b/parsedmarc/__init__.py index aaa05f3..6fd53ea 100644 --- a/parsedmarc/__init__.py +++ b/parsedmarc/__init__.py @@ -785,7 +785,8 @@ def parse_report_email(input_, nameservers=None, dns_timeout=2.0, def parse_report_file(input_, nameservers=None, dns_timeout=2.0, - strip_attachment_payloads=False, parallel=False): + strip_attachment_payloads=False, + offline=False, parallel=False): """Parses a DMARC aggregate or forensic file at the given path, a file-like object. or bytes @@ -796,12 +797,14 @@ def parse_report_file(input_, nameservers=None, dns_timeout=2.0, dns_timeout (float): Sets the DNS timeout in seconds strip_attachment_payloads (bool): Remove attachment payloads from forensic report results + offline (bool): Do not make online queries for geolocation or DNS parallel (bool): Parallel processing Returns: OrderedDict: The parsed DMARC report """ if type(input_) == str: + logger.debug("Parsing {0}".format(input_)) file_object = open(input_, "rb") elif type(input_) == bytes: file_object = BytesIO(input_) diff --git a/parsedmarc/cli.py b/parsedmarc/cli.py index 425f35d..7c48cd9 100644 --- a/parsedmarc/cli.py +++ b/parsedmarc/cli.py @@ -30,13 +30,15 @@ def _str_to_list(s): return list(map(lambda i: i.lstrip(), _list)) -def cli_parse(file_path, sa, nameservers, dns_timeout, parallel=False): +def cli_parse(file_path, sa, nameservers, dns_timeout, offline=False, + parallel=False): """Separated this function for multiprocessing""" try: file_results = parse_report_file(file_path, nameservers=nameservers, dns_timeout=dns_timeout, strip_attachment_payloads=sa, + offline=offline, parallel=parallel) except ParserError as error: return error, file_path @@ -165,6 +167,9 @@ def _main(): "from DNS (default: 2.0)", type=float, default=2.0) + arg_parser.add_argument("--offline", action="store_true", + help="Do not make online queries for geolocation " + " or DNS") arg_parser.add_argument("-s", "--silent", action="store_true", help="only print errors and warnings") arg_parser.add_argument("--debug", action="store_true", @@ -180,6 +185,7 @@ def _main(): args = arg_parser.parse_args() opts = Namespace(file_path=args.file_path, config_file=args.config_file, + offline=args.offline, strip_attachment_payloads=args.strip_attachment_payloads, output=args.output, nameservers=args.nameservers, @@ -243,6 +249,8 @@ def _main(): config.read(args.config_file) if "general" in config.sections(): general_config = config["general"] + if "offline" in general_config: + opts.offline = general_config["offline"] if "strip_attachment_payloads" in general_config: opts.strip_attachment_payloads = general_config[ "strip_attachment_payloads"] diff --git a/parsedmarc/utils.py b/parsedmarc/utils.py index 8fde08a..b4b3141 100644 --- a/parsedmarc/utils.py +++ b/parsedmarc/utils.py @@ -257,7 +257,7 @@ def human_timestamp_to_timestamp(human_timestamp): return human_timestamp_to_datetime(human_timestamp).timestamp() -def get_ip_address_country(ip_address, parallel=False): +def get_ip_address_country(ip_address, parallel=False, offline=False): """ Uses the MaxMind Geolite2 Country database to return the ISO code for the country associated with the given IPv4 or IPv6 address @@ -265,6 +265,7 @@ def get_ip_address_country(ip_address, parallel=False): Args: ip_address (str): The IP address to query for parallel (bool): Parallel processing + offline (bool): Do not make online queries for geolocation and DNS Returns: str: And ISO country code associated with the given IP address @@ -275,7 +276,7 @@ def get_ip_address_country(ip_address, parallel=False): Args: location (str): Local location for the database file """ - if parallel: + if parallel or offline: logging.warning("GeoLite2-Country.mmdb is missing." "please install and run geoipupdate as root to " "get the latest version.") @@ -340,14 +341,15 @@ def get_ip_address_country(ip_address, parallel=False): return country -def get_ip_address_info(ip_address, cache=None, nameservers=None, - timeout=2.0, parallel=False): +def get_ip_address_info(ip_address, cache=None, offline=False, + nameservers=None, timeout=2.0, parallel=False): """ Returns reverse DNS and country information for the given IP address Args: ip_address (str): The IP address to check cache (ExpiringDict): Cache storage + offline (bool): Do not make online queries for geolocation or DNS nameservers (list): A list of one or more nameservers to use (Cloudflare's public DNS resolvers by default) timeout (float): Sets the DNS timeout in seconds @@ -364,9 +366,12 @@ def get_ip_address_info(ip_address, cache=None, nameservers=None, return info info = OrderedDict() info["ip_address"] = ip_address - reverse_dns = get_reverse_dns(ip_address, - nameservers=nameservers, - timeout=timeout) + if offline: + reverse_dns = None + else: + reverse_dns = get_reverse_dns(ip_address, + nameservers=nameservers, + timeout=timeout) country = get_ip_address_country(ip_address, parallel=parallel) info["country"] = country info["reverse_dns"] = reverse_dns