Update ipwhois to 1.1.0

This commit is contained in:
JonnyWong16 2019-11-23 18:55:41 -08:00
commit 84ce4758d1
13 changed files with 5041 additions and 649 deletions

View file

@ -1,4 +1,4 @@
# Copyright (c) 2013, 2014, 2015, 2016 Philip Hane
# Copyright (c) 2013-2019 Philip Hane
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@ -23,6 +23,8 @@
# POSSIBILITY OF SUCH DAMAGE.
from . import Net
from .asn import IPASN
from .nir import NIRWhois
import logging
log = logging.getLogger(__name__)
@ -34,22 +36,25 @@ class IPWhois:
IPv4 and IPv6 addresses.
Args:
address: An IPv4 or IPv6 address as a string, integer, IPv4Address, or
IPv6Address.
timeout: The default timeout for socket connections in seconds.
proxy_opener: The urllib.request.OpenerDirector request for proxy
support or None.
allow_permutations: allow net.Net() to use additional methods if DNS
lookups to Cymru fail.
address (:obj:`str`/:obj:`int`/:obj:`IPv4Address`/:obj:`IPv6Address`):
An IPv4 or IPv6 address
timeout (:obj:`int`): The default timeout for socket connections in
seconds. Defaults to 5.
proxy_opener (:obj:`urllib.request.OpenerDirector`): The request for
proxy support. Defaults to None.
allow_permutations (:obj:`bool`): Allow net.Net() to use additional
methods if DNS lookups to Cymru fail. *WARNING* deprecated in
favor of new argument asn_methods. Defaults to False.
"""
def __init__(self, address, timeout=5, proxy_opener=None,
allow_permutations=True):
allow_permutations=False):
self.net = Net(
address=address, timeout=timeout, proxy_opener=proxy_opener,
allow_permutations=allow_permutations
)
self.ipasn = IPASN(self.net)
self.address = self.net.address
self.timeout = self.net.timeout
@ -64,80 +69,101 @@ class IPWhois:
self.address_str, str(self.timeout), repr(self.net.opener)
)
def lookup(self, *args, **kwargs):
"""
Temporary wrapper for legacy whois lookups (moved to
IPWhois.lookup_whois()). This will be removed in a future
release (TBD).
"""
from warnings import warn
warn("IPWhois.lookup() has been deprecated and will be removed. "
"You should now use IPWhois.lookup_whois() for legacy whois "
"lookups.")
return self.lookup_whois(*args, **kwargs)
def lookup_whois(self, inc_raw=False, retry_count=3, get_referral=False,
extra_blacklist=None, ignore_referral_errors=False,
field_list=None, asn_alts=None, extra_org_map=None):
field_list=None, asn_alts=None, extra_org_map=None,
inc_nir=True, nir_field_list=None, asn_methods=None,
get_asn_description=True):
"""
The function for retrieving and parsing whois information for an IP
address via port 43 (WHOIS).
Args:
inc_raw: Boolean for whether to include the raw whois results in
the returned dictionary.
retry_count: The number of times to retry in case socket errors,
timeouts, connection resets, etc. are encountered.
get_referral: Boolean for whether to retrieve referral whois
information, if available.
extra_blacklist: A list of blacklisted whois servers in addition to
the global BLACKLIST.
ignore_referral_errors: Boolean for whether to ignore and continue
when an exception is encountered on referral whois lookups.
field_list: If provided, a list of fields to parse:
inc_raw (:obj:`bool`): Whether to include the raw whois results in
the returned dictionary. Defaults to False.
retry_count (:obj:`int`): The number of times to retry in case
socket errors, timeouts, connection resets, etc. are
encountered. Defaults to 3.
get_referral (:obj:`bool`): Whether to retrieve referral whois
information, if available. Defaults to False.
extra_blacklist (:obj:`list`): Blacklisted whois servers in
addition to the global BLACKLIST. Defaults to None.
ignore_referral_errors (:obj:`bool`): Whether to ignore and
continue when an exception is encountered on referral whois
lookups. Defaults to False.
field_list (:obj:`list`): If provided, a list of fields to parse:
['name', 'handle', 'description', 'country', 'state', 'city',
'address', 'postal_code', 'emails', 'created', 'updated']
asn_alts: Array of additional lookup types to attempt if the
If None, defaults to all.
asn_alts (:obj:`list`): Additional lookup types to attempt if the
ASN dns lookup fails. Allow permutations must be enabled.
Defaults to all ['whois', 'http'].
extra_org_map: Dictionary mapping org handles to RIRs. This is for
limited cases where ARIN REST (ASN fallback HTTP lookup) does
not show an RIR as the org handle e.g., DNIC (which is now the
built in ORG_MAP) e.g., {'DNIC': 'arin'}. Valid RIR values are
(note the case-sensitive - this is meant to match the REST
result): 'ARIN', 'RIPE', 'apnic', 'lacnic', 'afrinic'
If None, defaults to all ['whois', 'http']. *WARNING*
deprecated in favor of new argument asn_methods.
extra_org_map (:obj:`dict`): Dictionary mapping org handles to
RIRs. This is for limited cases where ARIN REST (ASN fallback
HTTP lookup) does not show an RIR as the org handle e.g., DNIC
(which is now the built in ORG_MAP) e.g., {'DNIC': 'arin'}.
Valid RIR values are (note the case-sensitive - this is meant
to match the REST result):
'ARIN', 'RIPE', 'apnic', 'lacnic', 'afrinic'
Defaults to None.
inc_nir (:obj:`bool`): Whether to retrieve NIR (National Internet
Registry) information, if registry is JPNIC (Japan) or KRNIC
(Korea). If True, extra network requests will be required.
If False, the information returned for JP or KR IPs is
severely restricted. Defaults to True.
nir_field_list (:obj:`list`): If provided and inc_nir, a list of
fields to parse:
['name', 'handle', 'country', 'address', 'postal_code',
'nameservers', 'created', 'updated', 'contacts']
If None, defaults to all.
asn_methods (:obj:`list`): ASN lookup types to attempt, in order.
If None, defaults to all ['dns', 'whois', 'http'].
get_asn_description (:obj:`bool`): Whether to run an additional
query when pulling ASN information via dns, in order to get
the ASN description. Defaults to True.
Returns:
Dictionary:
dict: The IP whois lookup results
:query: The IP address (String)
:asn: The Autonomous System Number (String)
:asn_date: The ASN Allocation date (String)
:asn_registry: The assigned ASN registry (String)
:asn_cidr: The assigned ASN CIDR (String)
:asn_country_code: The assigned ASN country code (String)
:nets: Dictionaries containing network information which consists
of the fields listed in the ipwhois.whois.RIR_WHOIS dictionary.
(List)
:raw: Raw whois results if the inc_raw parameter is True. (String)
:referral: Dictionary of referral whois information if get_referral
is True and the server isn't blacklisted. Consists of fields
listed in the ipwhois.whois.RWHOIS dictionary.
:raw_referral: Raw referral whois results if the inc_raw parameter
is True. (String)
::
{
'query' (str) - The IP address
'asn' (str) - The Autonomous System Number
'asn_date' (str) - The ASN Allocation date
'asn_registry' (str) - The assigned ASN registry
'asn_cidr' (str) - The assigned ASN CIDR
'asn_country_code' (str) - The assigned ASN country code
'asn_description' (str) - The ASN description
'nets' (list) - Dictionaries containing network
information which consists of the fields listed in the
ipwhois.whois.RIR_WHOIS dictionary.
'raw' (str) - Raw whois results if the inc_raw parameter
is True.
'referral' (dict) - Referral whois information if
get_referral is True and the server is not blacklisted.
Consists of fields listed in the ipwhois.whois.RWHOIS
dictionary.
'raw_referral' (str) - Raw referral whois results if the
inc_raw parameter is True.
'nir' (dict) - ipwhois.nir.NIRWhois() results if inc_nir
is True.
}
"""
from .whois import Whois
# Create the return dictionary.
results = {}
results = {'nir': None}
# Retrieve the ASN information.
log.debug('ASN lookup for {0}'.format(self.address_str))
asn_data, response = self.net.lookup_asn(
retry_count=retry_count, asn_alts=asn_alts,
extra_org_map=extra_org_map
asn_data = self.ipasn.lookup(
inc_raw=inc_raw, retry_count=retry_count, asn_alts=asn_alts,
extra_org_map=extra_org_map, asn_methods=asn_methods,
get_asn_description=get_asn_description
)
# Add the ASN information to the return dictionary.
@ -147,20 +173,42 @@ class IPWhois:
whois = Whois(self.net)
log.debug('WHOIS lookup for {0}'.format(self.address_str))
whois_data = whois.lookup(
inc_raw=inc_raw, retry_count=retry_count, response=response,
inc_raw=inc_raw, retry_count=retry_count, response=None,
get_referral=get_referral, extra_blacklist=extra_blacklist,
ignore_referral_errors=ignore_referral_errors, asn_data=asn_data,
field_list=field_list
)
# Add the RDAP information to the return dictionary.
# Add the WHOIS information to the return dictionary.
results.update(whois_data)
if inc_nir:
nir = None
if 'JP' == asn_data['asn_country_code']:
nir = 'jpnic'
elif 'KR' == asn_data['asn_country_code']:
nir = 'krnic'
if nir:
nir_whois = NIRWhois(self.net)
nir_data = nir_whois.lookup(
nir=nir, inc_raw=inc_raw, retry_count=retry_count,
response=None,
field_list=nir_field_list, is_offline=False
)
# Add the NIR information to the return dictionary.
results['nir'] = nir_data
return results
def lookup_rdap(self, inc_raw=False, retry_count=3, depth=0,
excluded_entities=None, bootstrap=False,
rate_limit_timeout=120, asn_alts=None, extra_org_map=None):
rate_limit_timeout=120, asn_alts=None, extra_org_map=None,
inc_nir=True, nir_field_list=None, asn_methods=None,
get_asn_description=True):
"""
The function for retrieving and parsing whois information for an IP
address via HTTP (RDAP).
@ -169,50 +217,84 @@ class IPWhois:
information to parse.**
Args:
inc_raw: Boolean for whether to include the raw whois results in
the returned dictionary.
retry_count: The number of times to retry in case socket errors,
timeouts, connection resets, etc. are encountered.
depth: How many levels deep to run queries when additional
referenced objects are found.
excluded_entities: A list of entity handles to not perform lookups.
bootstrap: If True, performs lookups via ARIN bootstrap rather
than lookups based on ASN data. ASN lookups are not performed
and no output for any of the asn* fields is provided.
rate_limit_timeout: The number of seconds to wait before retrying
when a rate limit notice is returned via rdap+json.
asn_alts: Array of additional lookup types to attempt if the
inc_raw (:obj:`bool`): Whether to include the raw whois results in
the returned dictionary. Defaults to False.
retry_count (:obj:`int`): The number of times to retry in case
socket errors, timeouts, connection resets, etc. are
encountered. Defaults to 3.
depth (:obj:`int`): How many levels deep to run queries when
additional referenced objects are found. Defaults to 0.
excluded_entities (:obj:`list`): Entity handles to not perform
lookups. Defaults to None.
bootstrap (:obj:`bool`): If True, performs lookups via ARIN
bootstrap rather than lookups based on ASN data. ASN lookups
are not performed and no output for any of the asn* fields is
provided. Defaults to False.
rate_limit_timeout (:obj:`int`): The number of seconds to wait
before retrying when a rate limit notice is returned via
rdap+json. Defaults to 120.
asn_alts (:obj:`list`): Additional lookup types to attempt if the
ASN dns lookup fails. Allow permutations must be enabled.
Defaults to all ['whois', 'http'].
extra_org_map: Dictionary mapping org handles to RIRs. This is for
limited cases where ARIN REST (ASN fallback HTTP lookup) does
not show an RIR as the org handle e.g., DNIC (which is now the
built in ORG_MAP) e.g., {'DNIC': 'arin'}. Valid RIR values are
(note the case-sensitive - this is meant to match the REST
result): 'ARIN', 'RIPE', 'apnic', 'lacnic', 'afrinic'
If None, defaults to all ['whois', 'http']. *WARNING*
deprecated in favor of new argument asn_methods.
extra_org_map (:obj:`dict`): Dictionary mapping org handles to
RIRs. This is for limited cases where ARIN REST (ASN fallback
HTTP lookup) does not show an RIR as the org handle e.g., DNIC
(which is now the built in ORG_MAP) e.g., {'DNIC': 'arin'}.
Valid RIR values are (note the case-sensitive - this is meant
to match the REST result):
'ARIN', 'RIPE', 'apnic', 'lacnic', 'afrinic'
Defaults to None.
inc_nir (:obj:`bool`): Whether to retrieve NIR (National Internet
Registry) information, if registry is JPNIC (Japan) or KRNIC
(Korea). If True, extra network requests will be required.
If False, the information returned for JP or KR IPs is
severely restricted. Defaults to True.
nir_field_list (:obj:`list`): If provided and inc_nir, a list of
fields to parse:
['name', 'handle', 'country', 'address', 'postal_code',
'nameservers', 'created', 'updated', 'contacts']
If None, defaults to all.
asn_methods (:obj:`list`): ASN lookup types to attempt, in order.
If None, defaults to all ['dns', 'whois', 'http'].
get_asn_description (:obj:`bool`): Whether to run an additional
query when pulling ASN information via dns, in order to get
the ASN description. Defaults to True.
Returns:
Dictionary:
dict: The IP RDAP lookup results
:query: The IP address (String)
:asn: The Autonomous System Number (String)
:asn_date: The ASN Allocation date (String)
:asn_registry: The assigned ASN registry (String)
:asn_cidr: The assigned ASN CIDR (String)
:asn_country_code: The assigned ASN country code (String)
:entities: List of entity handles referred by the top level query.
:network: Dictionary containing network information which consists
of the fields listed in the ipwhois.rdap._RDAPNetwork dict.
:objects: Dictionary of (entity handle: entity dict) which consists
of the fields listed in the ipwhois.rdap._RDAPEntity dict.
:raw: (Dictionary) - Whois results in json format if the inc_raw
parameter is True.
::
{
'query' (str) - The IP address
'asn' (str) - The Autonomous System Number
'asn_date' (str) - The ASN Allocation date
'asn_registry' (str) - The assigned ASN registry
'asn_cidr' (str) - The assigned ASN CIDR
'asn_country_code' (str) - The assigned ASN country code
'asn_description' (str) - The ASN description
'entities' (list) - Entity handles referred by the top
level query.
'network' (dict) - Network information which consists of
the fields listed in the ipwhois.rdap._RDAPNetwork
dict.
'objects' (dict) - Mapping of entity handle->entity dict
which consists of the fields listed in the
ipwhois.rdap._RDAPEntity dict. The raw result is
included for each object if the inc_raw parameter
is True.
'raw' (dict) - Whois results in json format if the inc_raw
parameter is True.
'nir' (dict) - ipwhois.nir.NIRWhois results if inc_nir is
True.
}
"""
from .rdap import RDAP
# Create the return dictionary.
results = {}
results = {'nir': None}
asn_data = None
response = None
@ -220,9 +302,10 @@ class IPWhois:
# Retrieve the ASN information.
log.debug('ASN lookup for {0}'.format(self.address_str))
asn_data, asn_response = self.net.lookup_asn(
retry_count=retry_count, asn_alts=asn_alts,
extra_org_map=extra_org_map
asn_data = self.ipasn.lookup(
inc_raw=inc_raw, retry_count=retry_count, asn_alts=asn_alts,
extra_org_map=extra_org_map, asn_methods=asn_methods,
get_asn_description=get_asn_description
)
# Add the ASN information to the return dictionary.
@ -241,4 +324,23 @@ class IPWhois:
# Add the RDAP information to the return dictionary.
results.update(rdap_data)
if inc_nir:
nir = None
if 'JP' == asn_data['asn_country_code']:
nir = 'jpnic'
elif 'KR' == asn_data['asn_country_code']:
nir = 'krnic'
if nir:
nir_whois = NIRWhois(self.net)
nir_data = nir_whois.lookup(
nir=nir, inc_raw=inc_raw, retry_count=retry_count,
response=None,
field_list=nir_field_list, is_offline=False
)
# Add the NIR information to the return dictionary.
results['nir'] = nir_data
return results