From 70d94330bbc848028496425978251fbcae56ed94 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Thu, 20 May 2010 00:55:46 +0200 Subject: [PATCH] Aggiunto modulo necessario. --- pywhois.py | 263 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 pywhois.py diff --git a/pywhois.py b/pywhois.py new file mode 100644 index 0000000..f55d388 --- /dev/null +++ b/pywhois.py @@ -0,0 +1,263 @@ +# +# -*- coding: utf-8 -*- +# +# Whois module for the pywhoisd server + +import SocketServer, re, math, syslog +from ipcalc import IP, Network + +def FormatOutput(field, value): + """ + Format a field, value pair for the output + from the server. + """ + output = (field + ":").ljust(24) + output += value + "\n" + return " "*4 + output + +def FormatMessage(message): + """ + Prepare a message to be written from the + server. + """ + output = "\n" + for line in message.split("\n"): + line = line.strip() + output += """\n %% """ + line.ljust(65) + """ %%""" + return output + "\n\n" + + +class Logger(): + # + # Logger class that allow pywhoisd to log + # everything on syslog. + def __init__(self, verbose = False): + self.verbose = verbose + + def Log(self, message): + """Log a message to syslog""" + syslog.syslog ("[pywhoisd] " + message) + if self.verbose: + print message + + def __call__(self, message): + self.Log (message) + +class Config(): + # + # Config class manage configuration contained + # in the config file and acts like a dictionary + # that provides data to other classes + # + def __init__(self, config_file): + """ + Load config file and save data in memory + """ + self.config = {} + f = open(config_file, 'r') + content = f.read() + f.close() + for (key, value) in re.findall(r"([^\s]+)\s*=\s*([^;]+)\s*;", content): + self.config[key] = value + + def __getitem__(self, key): + if self.config.has_key(key): + return self.config[key] + else: + return None + + def has_key(self, key): + return self.config.has_key(key) + + +class WhoisRequestHandler(SocketServer.StreamRequestHandler): + """ + This handler answers to the whois request + """ + + def handle(self): + # Come prima cosa salutiamo + hello = self.server.config['welcome_message'] + if hello: + response = FormatMessage(hello) + else: + response = "" + + # Obtain the whois request + request = self.rfile.readline().strip() + + if re.search(r"\d+\.\d+\.\d+\.\d+", request.strip()): + response += self.server.ResolveAddress(request.split("/")[0]) + else: + response += self.server.ResolveDomain(request) + response += FormatMessage("Bye") + + self.request.send (response) + return + + +class WhoisServer(SocketServer.ThreadingTCPServer): + # + # The real server. We allow reusing of address + # so we can stop and start in a moment. + allow_reuse_address = True + def __init__(self, (host, port), logger, config): + + SocketServer.ThreadingTCPServer.__init__(self, (host, port), + WhoisRequestHandler) + self.logger = logger + self.config = config + self.ip_database = {} + self.domain_database = {} + self.LoadDatabase(config['database_file']) + + def LoadDatabase(self, database_file): + """ + Populate server database with the data in the database + file + """ + self.logger.Log ("Populating database with entry in %s" % database_file) + try: + f = open(database_file, 'r') + database_data = f.read() + except IOError: + self.logger.Log ("Error while loading config file. exiting") + + nets = re.findall (r"net\s+(\d+\.\d+\.\d+\.\d+[/\d]*)[\s|\n]+\{([^\}]+)\};", + database_data) + for net in nets: + self.logger.Log ("Loading net %s" % net[0]) + fields = re.findall(r"(\w+)\s*=\s*([^;]+);", net[1]) + name, owner, ns = None, None, None + data = {} + for field, value in fields: + if field.lower() == 'name': + name = value.strip() + elif field.lower() == 'owner': + owner = value.strip() + elif field.lower() == 'ns': + ns = value.strip() + else: + data[field] = value + self.ip_database[net[0]] = Net(name = name, owner = owner, ns = ns, + data = data) + + domains = re.findall(r"domain\s+([^\s]+)[\s|\n]+\{([^\}]+)\};", + database_data) + for domain in domains: + self.logger.Log ("Loading domain %s" % domain[0]) + fields = re.findall(r"(\w+)\s*=\s*([^;]+);", domain[1]) + name, owner, ns = None, None, None + data = {} + for field, value in fields: + if field.lower() == 'name': + name = value.strip() + elif field.lower() == 'owner': + owner = value.strip() + elif field.lower() == 'ns': + ns = value.strip() + else: + data[field] = value + self.domain_database[domain[0]] = Domain(name = name, + owner = owner, + ns = ns, + data = data) + + def ResolveDomain(self, domain): + """ + Find domain data and return them ready for output + for the server + """ + domain = domain.strip(".") + output = "" + domains = self.GetParentDomains(domain) + for d in domains: + output += FormatMessage("GNet whoisd answering for domain %s" % d) + output += FormatOutput ("Domain", d) + domain = self.domain_database[d] + if domain.name is not None: + output += FormatOutput ("Name", domain.name) + if domain.owner is not None: + output += FormatOutput ("Owner", domain.owner) + if domain.ns is not None: + output += FormatOutput ("Nameserver", domain.ns) + if len(domain.data.items()) > 0: + output += FormatMessage("Additional data") + for k, v in domain.data.items(): + output += FormatOutput (k.capitalize(),v) + if len(domains) == 0: + return FormatMessage("No domain found for %s" % domain) + return output + + + def GetParentDomains(self, domain): + """ + Return a list of domains that contain the domain + passed as argument + """ + interesting_domains = [] + for domain_name, domain_data in self.domain_database.items(): + if domain.endswith(domain_name): + interesting_domains.append (domain_name) + return interesting_domains + + def ResolveAddress(self, ip): + """ + Resolve an ip: it searches all the data that match it + (i.e. all the subnets that contain it) and return + output text ready for the server response. + """ + output = "" + nets = self.GetParentNetworks(ip) + for net in nets: + output += FormatMessage("GNet whoisd answering for ip %s" % ip) + output += FormatOutput ("Range", net) + net = self.ip_database[net] + if net.name is not None: + output += FormatOutput ("Name", net.name) + if net.owner is not None: + output += FormatOutput ("Owner", net.owner) + if net.ns is not None: + output += FormatOutput ("Nameserver", net.ns) + if len(net.data.items()) > 0: + output += FormatMessage("Additional data") + for k, v in net.data.items(): + output += FormatOutput (k.capitalize(),v) + if len(nets) == 0: + output = FormatMessage("Address %s not found\n" % ip) + return output + + def GetParentNetworks(self, ip): + """ + Get network in which the given ip is + """ + interesting_networks = [] + for (address, net) in self.ip_database.items(): + try: + if IP(ip) in Network(address): + interesting_networks.append (address) + except: + continue + return interesting_networks + +class Net(): + # + # Net is a class representing the network + # contained in the local database and the + # net obtained from other whois server. + # + # It act as a C struct containing only the + # data and no method. + def __init__(self, name, owner, ns, data): + self.name = name + self.owner = owner + self.ns = ns + self.data = data + +class Domain(): + # + # + # + def __init__(self, name, owner, ns, data): + self.name, self.owner, self.ns = name, owner, ns + self.data = data -- 2.1.4