Added beta whois plugin
This commit is contained in:
parent
8e5e77b521
commit
a8f754ddc1
44
plugins/util/pywhois/__init__.py
Normal file
44
plugins/util/pywhois/__init__.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
import re
|
||||
import sys
|
||||
import subprocess
|
||||
from parser import WhoisEntry
|
||||
from whois import NICClient
|
||||
|
||||
|
||||
def whois(url):
|
||||
# clean domain to expose netloc
|
||||
domain = extract_domain(url)
|
||||
try:
|
||||
# try native whois command first
|
||||
r = subprocess.Popen(['whois', domain], stdout=subprocess.PIPE)
|
||||
text = r.stdout.read()
|
||||
except OSError:
|
||||
# try experimental client
|
||||
nic_client = NICClient()
|
||||
text = nic_client.whois_lookup(None, domain, 0)
|
||||
return WhoisEntry.load(domain, text)
|
||||
|
||||
def extract_domain(url):
|
||||
"""Extract the domain from the given URL
|
||||
|
||||
>>> extract_domain('http://www.google.com.au/tos.html')
|
||||
'google.com.au'
|
||||
"""
|
||||
suffixes = 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'xn', 'ye', 'yt', 'za', 'zm', 'zw'
|
||||
url = re.sub('^.*://', '', url).split('/')[0].lower()
|
||||
domain = []
|
||||
for section in url.split('.'):
|
||||
if section in suffixes:
|
||||
domain.append(section)
|
||||
else:
|
||||
domain = [section]
|
||||
return '.'.join(domain)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
url = sys.argv[1]
|
||||
except IndexError:
|
||||
print 'Usage: %s url' % sys.argv[0]
|
||||
else:
|
||||
print whois(url)
|
357
plugins/util/pywhois/parser.py
Normal file
357
plugins/util/pywhois/parser.py
Normal file
|
@ -0,0 +1,357 @@
|
|||
# parser.py - Module for parsing whois response data
|
||||
# Copyright (c) 2008 Andrey Petrov
|
||||
#
|
||||
# This module is part of pywhois and is released under
|
||||
# the MIT license: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
|
||||
class PywhoisError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def cast_date(date_str):
|
||||
"""Convert any date string found in WHOIS to a time object.
|
||||
"""
|
||||
known_formats = [
|
||||
'%d-%b-%Y', # 02-jan-2000
|
||||
'%Y-%m-%d', # 2000-01-02
|
||||
'%d-%b-%Y %H:%M:%S %Z', # 24-Jul-2009 13:20:03 UTC
|
||||
'%a %b %d %H:%M:%S %Z %Y', # Tue Jun 21 23:59:59 GMT 2011
|
||||
'%Y-%m-%dT%H:%M:%SZ', # 2007-01-26T19:10:31Z
|
||||
]
|
||||
|
||||
for format in known_formats:
|
||||
try:
|
||||
return time.strptime(date_str.strip(), format)
|
||||
except ValueError, e:
|
||||
pass # Wrong format, keep trying
|
||||
return None
|
||||
|
||||
|
||||
class WhoisEntry(object):
|
||||
"""Base class for parsing a Whois entries.
|
||||
"""
|
||||
# regular expressions to extract domain data from whois profile
|
||||
# child classes will override this
|
||||
_regex = {
|
||||
'domain_name': 'Domain Name:\s?(.+)',
|
||||
'registrar': 'Registrar:\s?(.+)',
|
||||
'whois_server': 'Whois Server:\s?(.+)',
|
||||
'referral_url': 'Referral URL:\s?(.+)', # http url of whois_server
|
||||
'updated_date': 'Updated Date:\s?(.+)',
|
||||
'creation_date': 'Creation Date:\s?(.+)',
|
||||
'expiration_date': 'Expiration Date:\s?(.+)',
|
||||
'name_servers': 'Name Server:\s?(.+)', # list of name servers
|
||||
'status': 'Status:\s?(.+)', # list of statuses
|
||||
'emails': '[\w.-]+@[\w.-]+\.[\w]{2,4}', # list of email addresses
|
||||
}
|
||||
|
||||
def __init__(self, domain, text, regex=None):
|
||||
self.domain = domain
|
||||
self.text = text
|
||||
if regex is not None:
|
||||
self._regex = regex
|
||||
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""The first time an attribute is called it will be calculated here.
|
||||
The attribute is then set to be accessed directly by subsequent calls.
|
||||
"""
|
||||
whois_regex = self._regex.get(attr)
|
||||
if whois_regex:
|
||||
setattr(self, attr, re.findall(whois_regex, self.text))
|
||||
return getattr(self, attr)
|
||||
else:
|
||||
raise KeyError('Unknown attribute: %s' % attr)
|
||||
|
||||
def __str__(self):
|
||||
"""Print all whois properties of domain
|
||||
"""
|
||||
return '\n'.join('%s: %s' % (attr, str(getattr(self, attr))) for attr in self.attrs())
|
||||
|
||||
|
||||
def attrs(self):
|
||||
"""Return list of attributes that can be extracted for this domain
|
||||
"""
|
||||
return sorted(self._regex.keys())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def load(domain, text):
|
||||
"""Given whois output in ``text``, return an instance of ``WhoisEntry`` that represents its parsed contents.
|
||||
"""
|
||||
if text.strip() == 'No whois server is known for this kind of object.':
|
||||
raise PywhoisError(text)
|
||||
|
||||
if '.com' in domain:
|
||||
return WhoisCom(domain, text)
|
||||
elif '.net' in domain:
|
||||
return WhoisNet(domain, text)
|
||||
elif '.org' in domain:
|
||||
return WhoisOrg(domain, text)
|
||||
elif '.ru' in domain:
|
||||
return WhoisRu(domain, text)
|
||||
elif '.name' in domain:
|
||||
return WhoisName(domain, text)
|
||||
elif '.us' in domain:
|
||||
return WhoisUs(domain, text)
|
||||
elif '.me' in domain:
|
||||
return WhoisMe(domain, text)
|
||||
elif '.uk' in domain:
|
||||
return WhoisUk(domain, text)
|
||||
else:
|
||||
return WhoisEntry(domain, text)
|
||||
|
||||
|
||||
|
||||
class WhoisCom(WhoisEntry):
|
||||
"""Whois parser for .com domains
|
||||
"""
|
||||
def __init__(self, domain, text):
|
||||
if 'No match for "' in text:
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text)
|
||||
|
||||
class WhoisNet(WhoisEntry):
|
||||
"""Whois parser for .net domains
|
||||
"""
|
||||
def __init__(self, domain, text):
|
||||
if 'No match for "' in text:
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text)
|
||||
|
||||
class WhoisOrg(WhoisEntry):
|
||||
"""Whois parser for .org domains
|
||||
"""
|
||||
regex = {
|
||||
'domain_name': 'Domain Name:\s?(.+)',
|
||||
'registrar': 'Registrar:\s?(.+)',
|
||||
'whois_server': 'Whois Server:\s?(.+)',
|
||||
'referral_url': 'Referral URL:\s?(.+)', # http url of whois_server
|
||||
'updated_date': 'Updated Date:\s?(.+)',
|
||||
'creation_date': 'Created On:\s?(.+)',
|
||||
'expiration_date': 'Expiration Date:\s?(.+)',
|
||||
'name_servers': 'Name Server:\s?(.+)', # list of name servers
|
||||
'status': 'Status:\s?(.+)', # list of statuses
|
||||
'emails': '[\w.-]+@[\w.-]+\.[\w]{2,4}', # list of email addresses
|
||||
}
|
||||
def __init__(self, domain, text):
|
||||
if text.strip() == 'NOT FOUND':
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text, self.regex)
|
||||
|
||||
class WhoisRu(WhoisEntry):
|
||||
"""Whois parser for .ru domains
|
||||
"""
|
||||
regex = {
|
||||
'domain_name': 'domain:\s*(.+)',
|
||||
'registrar': 'registrar:\s*(.+)',
|
||||
'creation_date': 'created:\s*(.+)',
|
||||
'expiration_date': 'paid-till:\s*(.+)',
|
||||
'name_servers': 'nserver:\s*(.+)', # list of name servers
|
||||
'status': 'state:\s*(.+)', # list of statuses
|
||||
'emails': '[\w.-]+@[\w.-]+\.[\w]{2,4}', # list of email addresses
|
||||
}
|
||||
|
||||
def __init__(self, domain, text):
|
||||
if text.strip() == 'No entries found':
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text, self.regex)
|
||||
|
||||
class WhoisName(WhoisEntry):
|
||||
"""Whois parser for .name domains
|
||||
"""
|
||||
regex = {
|
||||
'domain_name_id': 'Domain Name ID:\s*(.+)',
|
||||
'domain_name': 'Domain Name:\s*(.+)',
|
||||
'registrar_id': 'Sponsoring Registrar ID:\s*(.+)',
|
||||
'registrar': 'Sponsoring Registrar:\s*(.+)',
|
||||
'registrant_id': 'Registrant ID:\s*(.+)',
|
||||
'admin_id': 'Admin ID:\s*(.+)',
|
||||
'technical_id': 'Tech ID:\s*(.+)',
|
||||
'billing_id': 'Billing ID:\s*(.+)',
|
||||
'creation_date': 'Created On:\s*(.+)',
|
||||
'expiration_date': 'Expires On:\s*(.+)',
|
||||
'updated_date': 'Updated On:\s*(.+)',
|
||||
'name_server_ids': 'Name Server ID:\s*(.+)', # list of name server ids
|
||||
'name_servers': 'Name Server:\s*(.+)', # list of name servers
|
||||
'status': 'Domain Status:\s*(.+)', # list of statuses
|
||||
}
|
||||
def __init__(self, domain, text):
|
||||
if 'No match.' in text:
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text, self.regex)
|
||||
|
||||
class WhoisUs(WhoisEntry):
|
||||
"""Whois parser for .us domains
|
||||
"""
|
||||
regex = {
|
||||
'domain_name': 'Domain Name:\s*(.+)',
|
||||
'domain__id': 'Domain ID:\s*(.+)',
|
||||
'registrar': 'Sponsoring Registrar:\s*(.+)',
|
||||
'registrar_id': 'Sponsoring Registrar IANA ID:\s*(.+)',
|
||||
'registrar_url': 'Registrar URL \(registration services\):\s*(.+)',
|
||||
'status': 'Domain Status:\s*(.+)', # list of statuses
|
||||
'registrant_id': 'Registrant ID:\s*(.+)',
|
||||
'registrant_name': 'Registrant Name:\s*(.+)',
|
||||
'registrant_address1': 'Registrant Address1:\s*(.+)',
|
||||
'registrant_address2': 'Registrant Address2:\s*(.+)',
|
||||
'registrant_city': 'Registrant City:\s*(.+)',
|
||||
'registrant_state_province': 'Registrant State/Province:\s*(.+)',
|
||||
'registrant_postal_code': 'Registrant Postal Code:\s*(.+)',
|
||||
'registrant_country': 'Registrant Country:\s*(.+)',
|
||||
'registrant_country_code': 'Registrant Country Code:\s*(.+)',
|
||||
'registrant_phone_number': 'Registrant Phone Number:\s*(.+)',
|
||||
'registrant_email': 'Registrant Email:\s*(.+)',
|
||||
'registrant_application_purpose': 'Registrant Application Purpose:\s*(.+)',
|
||||
'registrant_nexus_category': 'Registrant Nexus Category:\s*(.+)',
|
||||
'admin_id': 'Administrative Contact ID:\s*(.+)',
|
||||
'admin_name': 'Administrative Contact Name:\s*(.+)',
|
||||
'admin_address1': 'Administrative Contact Address1:\s*(.+)',
|
||||
'admin_address2': 'Administrative Contact Address2:\s*(.+)',
|
||||
'admin_city': 'Administrative Contact City:\s*(.+)',
|
||||
'admin_state_province': 'Administrative Contact State/Province:\s*(.+)',
|
||||
'admin_postal_code': 'Administrative Contact Postal Code:\s*(.+)',
|
||||
'admin_country': 'Administrative Contact Country:\s*(.+)',
|
||||
'admin_country_code': 'Administrative Contact Country Code:\s*(.+)',
|
||||
'admin_phone_number': 'Administrative Contact Phone Number:\s*(.+)',
|
||||
'admin_email': 'Administrative Contact Email:\s*(.+)',
|
||||
'admin_application_purpose': 'Administrative Application Purpose:\s*(.+)',
|
||||
'admin_nexus_category': 'Administrative Nexus Category:\s*(.+)',
|
||||
'billing_id': 'Billing Contact ID:\s*(.+)',
|
||||
'billing_name': 'Billing Contact Name:\s*(.+)',
|
||||
'billing_address1': 'Billing Contact Address1:\s*(.+)',
|
||||
'billing_address2': 'Billing Contact Address2:\s*(.+)',
|
||||
'billing_city': 'Billing Contact City:\s*(.+)',
|
||||
'billing_state_province': 'Billing Contact State/Province:\s*(.+)',
|
||||
'billing_postal_code': 'Billing Contact Postal Code:\s*(.+)',
|
||||
'billing_country': 'Billing Contact Country:\s*(.+)',
|
||||
'billing_country_code': 'Billing Contact Country Code:\s*(.+)',
|
||||
'billing_phone_number': 'Billing Contact Phone Number:\s*(.+)',
|
||||
'billing_email': 'Billing Contact Email:\s*(.+)',
|
||||
'billing_application_purpose': 'Billing Application Purpose:\s*(.+)',
|
||||
'billing_nexus_category': 'Billing Nexus Category:\s*(.+)',
|
||||
'tech_id': 'Technical Contact ID:\s*(.+)',
|
||||
'tech_name': 'Technical Contact Name:\s*(.+)',
|
||||
'tech_address1': 'Technical Contact Address1:\s*(.+)',
|
||||
'tech_address2': 'Technical Contact Address2:\s*(.+)',
|
||||
'tech_city': 'Technical Contact City:\s*(.+)',
|
||||
'tech_state_province': 'Technical Contact State/Province:\s*(.+)',
|
||||
'tech_postal_code': 'Technical Contact Postal Code:\s*(.+)',
|
||||
'tech_country': 'Technical Contact Country:\s*(.+)',
|
||||
'tech_country_code': 'Technical Contact Country Code:\s*(.+)',
|
||||
'tech_phone_number': 'Technical Contact Phone Number:\s*(.+)',
|
||||
'tech_email': 'Technical Contact Email:\s*(.+)',
|
||||
'tech_application_purpose': 'Technical Application Purpose:\s*(.+)',
|
||||
'tech_nexus_category': 'Technical Nexus Category:\s*(.+)',
|
||||
'name_servers': 'Name Server:\s*(.+)', # list of name servers
|
||||
'created_by_registrar': 'Created by Registrar:\s*(.+)',
|
||||
'last_updated_by_registrar': 'Last Updated by Registrar:\s*(.+)',
|
||||
'creation_date': 'Domain Registration Date:\s*(.+)',
|
||||
'expiration_date': 'Domain Expiration Date:\s*(.+)',
|
||||
'updated_date': 'Domain Last Updated Date:\s*(.+)',
|
||||
}
|
||||
def __init__(self, domain, text):
|
||||
if 'Not found:' in text:
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text, self.regex)
|
||||
|
||||
class WhoisMe(WhoisEntry):
|
||||
"""Whois parser for .me domains
|
||||
"""
|
||||
regex = {
|
||||
'domain_id': 'Domain ID:(.+)',
|
||||
'domain_name': 'Domain Name:(.+)',
|
||||
'creation_date': 'Domain Create Date:(.+)',
|
||||
'updated_date': 'Domain Last Updated Date:(.+)',
|
||||
'expiration_date': 'Domain Expiration Date:(.+)',
|
||||
'transfer_date': 'Last Transferred Date:(.+)',
|
||||
'trademark_name': 'Trademark Name:(.+)',
|
||||
'trademark_country': 'Trademark Country:(.+)',
|
||||
'trademark_number': 'Trademark Number:(.+)',
|
||||
'trademark_application_date': 'Date Trademark Applied For:(.+)',
|
||||
'trademark_registration_date': 'Date Trademark Registered:(.+)',
|
||||
'registrar': 'Sponsoring Registrar:(.+)',
|
||||
'created_by': 'Created by:(.+)',
|
||||
'updated_by': 'Last Updated by Registrar:(.+)',
|
||||
'status': 'Domain Status:(.+)', # list of statuses
|
||||
'registrant_id': 'Registrant ID:(.+)',
|
||||
'registrant_name': 'Registrant Name:(.+)',
|
||||
'registrant_org': 'Registrant Organization:(.+)',
|
||||
'registrant_address': 'Registrant Address:(.+)',
|
||||
'registrant_address2': 'Registrant Address2:(.+)',
|
||||
'registrant_address3': 'Registrant Address3:(.+)',
|
||||
'registrant_city': 'Registrant City:(.+)',
|
||||
'registrant_state_province': 'Registrant State/Province:(.+)',
|
||||
'registrant_country': 'Registrant Country/Economy:(.+)',
|
||||
'registrant_postal_code': 'Registrant Postal Code:(.+)',
|
||||
'registrant_phone': 'Registrant Phone:(.+)',
|
||||
'registrant_phone_ext': 'Registrant Phone Ext\.:(.+)',
|
||||
'registrant_fax': 'Registrant FAX:(.+)',
|
||||
'registrant_fax_ext': 'Registrant FAX Ext\.:(.+)',
|
||||
'registrant_email': 'Registrant E-mail:(.+)',
|
||||
'admin_id': 'Admin ID:(.+)',
|
||||
'admin_name': 'Admin Name:(.+)',
|
||||
'admin_org': 'Admin Organization:(.+)',
|
||||
'admin_address': 'Admin Address:(.+)',
|
||||
'admin_address2': 'Admin Address2:(.+)',
|
||||
'admin_address3': 'Admin Address3:(.+)',
|
||||
'admin_city': 'Admin City:(.+)',
|
||||
'admin_state_province': 'Admin State/Province:(.+)',
|
||||
'admin_country': 'Admin Country/Economy:(.+)',
|
||||
'admin_postal_code': 'Admin Postal Code:(.+)',
|
||||
'admin_phone': 'Admin Phone:(.+)',
|
||||
'admin_phone_ext': 'Admin Phone Ext\.:(.+)',
|
||||
'admin_fax': 'Admin FAX:(.+)',
|
||||
'admin_fax_ext': 'Admin FAX Ext\.:(.+)',
|
||||
'admin_email': 'Admin E-mail:(.+)',
|
||||
'tech_id': 'Tech ID:(.+)',
|
||||
'tech_name': 'Tech Name:(.+)',
|
||||
'tech_org': 'Tech Organization:(.+)',
|
||||
'tech_address': 'Tech Address:(.+)',
|
||||
'tech_address2': 'Tech Address2:(.+)',
|
||||
'tech_address3': 'Tech Address3:(.+)',
|
||||
'tech_city': 'Tech City:(.+)',
|
||||
'tech_state_province': 'Tech State/Province:(.+)',
|
||||
'tech_country': 'Tech Country/Economy:(.+)',
|
||||
'tech_postal_code': 'Tech Postal Code:(.+)',
|
||||
'tech_phone': 'Tech Phone:(.+)',
|
||||
'tech_phone_ext': 'Tech Phone Ext\.:(.+)',
|
||||
'tech_fax': 'Tech FAX:(.+)',
|
||||
'tech_fax_ext': 'Tech FAX Ext\.:(.+)',
|
||||
'tech_email': 'Tech E-mail:(.+)',
|
||||
'name_servers': 'Nameservers:(.+)', # list of name servers
|
||||
}
|
||||
def __init__(self, domain, text):
|
||||
if 'NOT FOUND' in text:
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text, self.regex)
|
||||
|
||||
class WhoisUk(WhoisEntry):
|
||||
"""Whois parser for .uk domains
|
||||
"""
|
||||
regex = {
|
||||
'domain_name': 'Domain name:\n\s*(.+)',
|
||||
'registrar': 'Registrar:\n\s*(.+)',
|
||||
'registrar_url': 'URL:\s*(.+)',
|
||||
'status': 'Registration status:\n\s*(.+)', # list of statuses
|
||||
'registrant_name': 'Registrant:\n\s*(.+)',
|
||||
'creation_date': 'Registered on:\s*(.+)',
|
||||
'expiration_date': 'Renewal date:\s*(.+)',
|
||||
'updated_date': 'Last updated:\s*(.+)',
|
||||
}
|
||||
def __init__(self, domain, text):
|
||||
if 'Not found:' in text:
|
||||
raise PywhoisError(text)
|
||||
else:
|
||||
WhoisEntry.__init__(self, domain, text, self.regex)
|
232
plugins/util/pywhois/whois.py
Normal file
232
plugins/util/pywhois/whois.py
Normal file
|
@ -0,0 +1,232 @@
|
|||
"""
|
||||
Whois client for python
|
||||
|
||||
transliteration of:
|
||||
http://www.opensource.apple.com/source/adv_cmds/adv_cmds-138.1/whois/whois.c
|
||||
|
||||
Copyright (c) 2010 Chris Wolf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Last edited by: $Author$
|
||||
on: $DateTime$
|
||||
Revision: $Revision$
|
||||
Id: $Id$
|
||||
Author: Chris Wolf
|
||||
"""
|
||||
import sys
|
||||
import socket
|
||||
import optparse
|
||||
#import pdb
|
||||
|
||||
|
||||
class NICClient(object) :
|
||||
|
||||
ABUSEHOST = "whois.abuse.net"
|
||||
NICHOST = "whois.crsnic.net"
|
||||
INICHOST = "whois.networksolutions.com"
|
||||
DNICHOST = "whois.nic.mil"
|
||||
GNICHOST = "whois.nic.gov"
|
||||
ANICHOST = "whois.arin.net"
|
||||
LNICHOST = "whois.lacnic.net"
|
||||
RNICHOST = "whois.ripe.net"
|
||||
PNICHOST = "whois.apnic.net"
|
||||
MNICHOST = "whois.ra.net"
|
||||
QNICHOST_TAIL = ".whois-servers.net"
|
||||
SNICHOST = "whois.6bone.net"
|
||||
BNICHOST = "whois.registro.br"
|
||||
NORIDHOST = "whois.norid.no"
|
||||
IANAHOST = "whois.iana.org"
|
||||
GERMNICHOST = "de.whois-servers.net"
|
||||
DEFAULT_PORT = "nicname"
|
||||
WHOIS_SERVER_ID = "Whois Server:"
|
||||
WHOIS_ORG_SERVER_ID = "Registrant Street1:Whois Server:"
|
||||
|
||||
|
||||
WHOIS_RECURSE = 0x01
|
||||
WHOIS_QUICK = 0x02
|
||||
|
||||
ip_whois = [ LNICHOST, RNICHOST, PNICHOST, BNICHOST ]
|
||||
|
||||
def __init__(self) :
|
||||
self.use_qnichost = False
|
||||
|
||||
def findwhois_server(self, buf, hostname):
|
||||
"""Search the initial TLD lookup results for the regional-specifc
|
||||
whois server for getting contact details.
|
||||
"""
|
||||
nhost = None
|
||||
parts_index = 1
|
||||
start = buf.find(NICClient.WHOIS_SERVER_ID)
|
||||
if (start == -1):
|
||||
start = buf.find(NICClient.WHOIS_ORG_SERVER_ID)
|
||||
parts_index = 2
|
||||
|
||||
if (start > -1):
|
||||
end = buf[start:].find('\n')
|
||||
whois_line = buf[start:end+start]
|
||||
whois_parts = whois_line.split(':')
|
||||
nhost = whois_parts[parts_index].strip()
|
||||
elif (hostname == NICClient.ANICHOST):
|
||||
for nichost in NICClient.ip_whois:
|
||||
if (buf.find(nichost) != -1):
|
||||
nhost = nichost
|
||||
break
|
||||
return nhost
|
||||
|
||||
def whois(self, query, hostname, flags):
|
||||
"""Perform initial lookup with TLD whois server
|
||||
then, if the quick flag is false, search that result
|
||||
for the region-specifc whois server and do a lookup
|
||||
there for contact details
|
||||
"""
|
||||
#pdb.set_trace()
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.connect((hostname, 43))
|
||||
if (hostname == NICClient.GERMNICHOST):
|
||||
s.send("-T dn,ace -C US-ASCII " + query + "\r\n")
|
||||
else:
|
||||
s.send(query + "\r\n")
|
||||
response = ''
|
||||
while True:
|
||||
d = s.recv(4096)
|
||||
response += d
|
||||
if not d:
|
||||
break
|
||||
s.close()
|
||||
#pdb.set_trace()
|
||||
nhost = None
|
||||
if (flags & NICClient.WHOIS_RECURSE and nhost == None):
|
||||
nhost = self.findwhois_server(response, hostname)
|
||||
if (nhost != None):
|
||||
response += self.whois(query, nhost, 0)
|
||||
return response
|
||||
|
||||
def choose_server(self, domain):
|
||||
"""Choose initial lookup NIC host"""
|
||||
if (domain.endswith("-NORID")):
|
||||
return NICClient.NORIDHOST
|
||||
pos = domain.rfind('.')
|
||||
if (pos == -1):
|
||||
return None
|
||||
tld = domain[pos+1:]
|
||||
if (tld[0].isdigit()):
|
||||
return NICClient.ANICHOST
|
||||
|
||||
return tld + NICClient.QNICHOST_TAIL
|
||||
|
||||
def whois_lookup(self, options, query_arg, flags):
|
||||
"""Main entry point: Perform initial lookup on TLD whois server,
|
||||
or other server to get region-specific whois server, then if quick
|
||||
flag is false, perform a second lookup on the region-specific
|
||||
server for contact records"""
|
||||
nichost = None
|
||||
#pdb.set_trace()
|
||||
# this would be the case when this function is called by other then main
|
||||
if (options == None):
|
||||
options = {}
|
||||
|
||||
if ( (not options.has_key('whoishost') or options['whoishost'] == None)
|
||||
and (not options.has_key('country') or options['country'] == None)):
|
||||
self.use_qnichost = True
|
||||
options['whoishost'] = NICClient.NICHOST
|
||||
if ( not (flags & NICClient.WHOIS_QUICK)):
|
||||
flags |= NICClient.WHOIS_RECURSE
|
||||
|
||||
if (options.has_key('country') and options['country'] != None):
|
||||
result = self.whois(query_arg, options['country'] + NICClient.QNICHOST_TAIL, flags)
|
||||
elif (self.use_qnichost):
|
||||
nichost = self.choose_server(query_arg)
|
||||
if (nichost != None):
|
||||
result = self.whois(query_arg, nichost, flags)
|
||||
else:
|
||||
result = self.whois(query_arg, options['whoishost'], flags)
|
||||
|
||||
return result
|
||||
#---- END OF NICClient class def ---------------------
|
||||
|
||||
def parse_command_line(argv):
|
||||
"""Options handling mostly follows the UNIX whois(1) man page, except
|
||||
long-form options can also be used.
|
||||
"""
|
||||
flags = 0
|
||||
|
||||
usage = "usage: %prog [options] name"
|
||||
|
||||
parser = optparse.OptionParser(add_help_option=False, usage=usage)
|
||||
parser.add_option("-a", "--arin", action="store_const",
|
||||
const=NICClient.ANICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.ANICHOST)
|
||||
parser.add_option("-A", "--apnic", action="store_const",
|
||||
const=NICClient.PNICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.PNICHOST)
|
||||
parser.add_option("-b", "--abuse", action="store_const",
|
||||
const=NICClient.ABUSEHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.ABUSEHOST)
|
||||
parser.add_option("-c", "--country", action="store",
|
||||
type="string", dest="country",
|
||||
help="Lookup using country-specific NIC")
|
||||
parser.add_option("-d", "--mil", action="store_const",
|
||||
const=NICClient.DNICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.DNICHOST)
|
||||
parser.add_option("-g", "--gov", action="store_const",
|
||||
const=NICClient.GNICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.GNICHOST)
|
||||
parser.add_option("-h", "--host", action="store",
|
||||
type="string", dest="whoishost",
|
||||
help="Lookup using specified whois host")
|
||||
parser.add_option("-i", "--nws", action="store_const",
|
||||
const=NICClient.INICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.INICHOST)
|
||||
parser.add_option("-I", "--iana", action="store_const",
|
||||
const=NICClient.IANAHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.IANAHOST)
|
||||
parser.add_option("-l", "--lcanic", action="store_const",
|
||||
const=NICClient.LNICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.LNICHOST)
|
||||
parser.add_option("-m", "--ra", action="store_const",
|
||||
const=NICClient.MNICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.MNICHOST)
|
||||
parser.add_option("-p", "--port", action="store",
|
||||
type="int", dest="port",
|
||||
help="Lookup using specified tcp port")
|
||||
parser.add_option("-Q", "--quick", action="store_true",
|
||||
dest="b_quicklookup",
|
||||
help="Perform quick lookup")
|
||||
parser.add_option("-r", "--ripe", action="store_const",
|
||||
const=NICClient.RNICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.RNICHOST)
|
||||
parser.add_option("-R", "--ru", action="store_const",
|
||||
const="ru", dest="country",
|
||||
help="Lookup Russian NIC")
|
||||
parser.add_option("-6", "--6bone", action="store_const",
|
||||
const=NICClient.SNICHOST, dest="whoishost",
|
||||
help="Lookup using host " + NICClient.SNICHOST)
|
||||
parser.add_option("-?", "--help", action="help")
|
||||
|
||||
|
||||
return parser.parse_args(argv)
|
||||
|
||||
if __name__ == "__main__":
|
||||
flags = 0
|
||||
nic_client = NICClient()
|
||||
(options, args) = parse_command_line(sys.argv)
|
||||
if (options.b_quicklookup is True):
|
||||
flags = flags|NICClient.WHOIS_QUICK
|
||||
print nic_client.whois_lookup(options.__dict__, args[1], flags)
|
19
plugins/whois.py
Normal file
19
plugins/whois.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from util import pywhois, hook
|
||||
|
||||
@hook.command
|
||||
def whois(inp, say=None):
|
||||
try:
|
||||
w = pywhois.whois(inp)
|
||||
except:
|
||||
return "Failed to check domain info. This domain may not exist."
|
||||
|
||||
print w
|
||||
|
||||
domain_name = w.domain_name[0]
|
||||
expiration_date = w.expiration_date[0]
|
||||
creation_date = w.creation_date[0]
|
||||
registrant_email = w.emails[0]
|
||||
administrative_email = w.emails[1]
|
||||
say('Domain recognised! %s was registered on \x02%s\x02 and will expire on \x02%s\x02' % (domain_name, creation_date, expiration_date))
|
||||
say('Registrant email: %s Administrative email: %s' % (registrant_email, administrative_email))
|
||||
|
Reference in a new issue