remove ratelimit and stats page
parent
1ea796363b
commit
0f6bcede69
|
@ -44,11 +44,9 @@ from SearchPage import BookSearchPage, AuthorSearchPage, SubjectSearchPage, Book
|
|||
from BibrecPage import BibrecPage
|
||||
import CoverPages
|
||||
import QRCodePage
|
||||
import StatsPage
|
||||
import CaptchaPage
|
||||
import Sitemap
|
||||
import Formatters
|
||||
import RateLimiter
|
||||
|
||||
import Timer
|
||||
|
||||
|
@ -140,12 +138,6 @@ def main ():
|
|||
Formatters.init ()
|
||||
cherrypy.log ("Continuing App Init", context = 'ENGINE', severity = logging.INFO)
|
||||
|
||||
try:
|
||||
cherrypy.tools.rate_limiter = RateLimiter.RateLimiterTool ()
|
||||
except Exception as e:
|
||||
tb = traceback.format_exc ()
|
||||
cherrypy.log (tb, context = 'ENGINE', severity = logging.ERROR)
|
||||
|
||||
cherrypy.log ("Continuing App Init", context = 'ENGINE', severity = logging.INFO)
|
||||
cherrypy.tools.I18nTool = i18n_tool.I18nTool ()
|
||||
|
||||
|
@ -169,8 +161,6 @@ def main ():
|
|||
cherrypy.engine, params = GutenbergDatabase.get_connection_params (cherrypy.config))
|
||||
cherrypy.engine.pool.subscribe ()
|
||||
|
||||
plugins.RateLimiterReset (cherrypy.engine).subscribe ()
|
||||
plugins.RateLimiterDatabase (cherrypy.engine).subscribe ()
|
||||
plugins.Timer (cherrypy.engine).subscribe ()
|
||||
|
||||
cherrypy.log ("Daemonizing", context = 'ENGINE', severity = logging.INFO)
|
||||
|
@ -263,16 +253,7 @@ def main ():
|
|||
controller = Page.NullPage ())
|
||||
|
||||
d.connect ('stats', r'/stats/',
|
||||
controller = StatsPage.StatsPage ())
|
||||
|
||||
d.connect ('block', r'/stats/block/',
|
||||
controller = RateLimiter.BlockPage ())
|
||||
|
||||
d.connect ('unblock', r'/stats/unblock/',
|
||||
controller = RateLimiter.UnblockPage ())
|
||||
|
||||
d.connect ('traceback', r'/stats/traceback/',
|
||||
controller = RateLimiter.TracebackPage ())
|
||||
controller = Page.NullPage (), _static = True)
|
||||
|
||||
d.connect ('honeypot_send', r'/ebooks/send/megaupload/{id:\d+}.{filetype}',
|
||||
controller = Page.NullPage (), _static = True)
|
||||
|
|
1124
RateLimiter-new.py
1124
RateLimiter-new.py
File diff suppressed because it is too large
Load Diff
1131
RateLimiter.py
1131
RateLimiter.py
File diff suppressed because it is too large
Load Diff
82
StatsPage.py
82
StatsPage.py
|
@ -1,82 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- mode: python; indent-tabs-mode: nil; -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
StatsPage.py
|
||||
|
||||
Copyright 2009-2014 by Marcello Perathoner
|
||||
|
||||
Distributable under the GNU General Public License Version 3 or newer.
|
||||
|
||||
The appserver stats page.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import cherrypy
|
||||
|
||||
import BaseSearcher
|
||||
import TemplatedPage
|
||||
import asyncdns
|
||||
import ipinfo
|
||||
|
||||
|
||||
class StatsPage (TemplatedPage.TemplatedPage):
|
||||
""" Output some statistics. """
|
||||
|
||||
CONTENT_TYPE = 'application/xhtml+xml; charset=UTF-8'
|
||||
FORMATTER = 'html'
|
||||
|
||||
def index (self, **kwargs):
|
||||
""" Output stats. """
|
||||
|
||||
backends = int (BaseSearcher.sql_get ("SELECT count (*) from pg_stat_activity"))
|
||||
active_backends = int (BaseSearcher.sql_get (
|
||||
"SELECT count (*) - 1 from pg_stat_activity where current_query !~ '^<IDLE>'"))
|
||||
|
||||
ipsessions = list (cherrypy.tools.rate_limiter.cache.values ()) # pylint: disable=E1101
|
||||
|
||||
adns = asyncdns.AsyncDNS ()
|
||||
|
||||
# blocked IPs
|
||||
blocked = sorted ([s for s in ipsessions if s.get ('blocked', 0) >= 2],
|
||||
key = lambda s: s.ips.sort_key ())
|
||||
if 'resolve' in kwargs:
|
||||
for d in blocked:
|
||||
if d.ips.ipinfo is None:
|
||||
d.ips.ipinfo = ipinfo.IPInfo (adns, d.ips.get_ip_to_block ())
|
||||
|
||||
# active IPs
|
||||
active = sorted ([s for s in ipsessions if s.get ('active', False)],
|
||||
key = lambda s: s.ips.sort_key ())
|
||||
|
||||
# busiest IPs
|
||||
busiest = sorted ([s for s in active if s.get ('blocked', 0) < 2],
|
||||
key = lambda x: -x.get ('rhits'))[:10]
|
||||
if 'resolve' in kwargs:
|
||||
for d in busiest:
|
||||
if d.ips.ipinfo is None:
|
||||
d.ips.ipinfo = ipinfo.IPInfo (adns, d.ips.get_ip_to_block ())
|
||||
|
||||
# IPs with most sessions
|
||||
most_sessions = sorted ([s for s in active
|
||||
if not s.ips.whitelisted and len (s.sessions) > 1],
|
||||
key = lambda s: -len (s.sessions))[:10]
|
||||
if 'resolve' in kwargs:
|
||||
for d in most_sessions:
|
||||
if d.ips.ipinfo is None:
|
||||
d.ips.ipinfo = ipinfo.IPInfo (adns, d.ips.get_ip_to_block ())
|
||||
|
||||
adns.wait ()
|
||||
adns.cancel ()
|
||||
|
||||
return self.output ('stats',
|
||||
active = active,
|
||||
blocked = blocked,
|
||||
busiest = busiest,
|
||||
most_sessions = most_sessions,
|
||||
resolve = 'resolve' in kwargs,
|
||||
rl = cherrypy.tools.rate_limiter, # pylint: disable=E1101
|
||||
backends = backends,
|
||||
active_backends = active_backends)
|
200
asyncdns.py
200
asyncdns.py
|
@ -1,200 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- mode: python; indent-tabs-mode: nil; -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
asyncdns.py
|
||||
|
||||
Copyright 2013-14 by Marcello Perathoner
|
||||
|
||||
Distributable under the GNU General Public License Version 3 or newer.
|
||||
|
||||
Higher level interface to the GNU asynchronous DNS library.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import sys
|
||||
import time
|
||||
|
||||
import adns
|
||||
|
||||
# pass this to __init__ to use Google Public DNS
|
||||
RESOLV_CONF = 'nameserver 8.8.8.8'
|
||||
|
||||
# http://www.ietf.org/rfc/rfc1035.txt Domain Names
|
||||
# http://www.ietf.org/rfc/rfc3490.txt IDNA
|
||||
# http://www.ietf.org/rfc/rfc3492.txt Punycode
|
||||
|
||||
class AsyncDNS (object):
|
||||
""" An asynchronous DNS resolver. """
|
||||
|
||||
def __init__ (self, resolv_conf = None):
|
||||
if resolv_conf:
|
||||
self.resolver = adns.init (
|
||||
adns.iflags.noautosys + adns.iflags.noerrprint,
|
||||
sys.stderr, # FIXME: adns version 1.2.2 will allow keyword params
|
||||
resolv_conf)
|
||||
else:
|
||||
self.resolver = adns.init (
|
||||
adns.iflags.noautosys + adns.iflags.noerrprint)
|
||||
|
||||
self._queries = {} # keeps query objects alive
|
||||
|
||||
def query (self, query, callback, rr = adns.rr.A):
|
||||
""" Queue a query.
|
||||
|
||||
:param query: the query string (may contain unicode characters)
|
||||
:param callback: function taking a tuple of answers
|
||||
:param rr: the query rr type code
|
||||
|
||||
"""
|
||||
|
||||
if rr not in (adns.rr.PTR, adns.rr.PTRraw):
|
||||
query = self.encode (query)
|
||||
if rr in (adns.rr.PTR, adns.rr.PTRraw):
|
||||
self._queries [self.resolver.submit_reverse (query, rr)] = callback, rr
|
||||
else:
|
||||
self._queries [self.resolver.submit (query, rr)] = callback, rr
|
||||
|
||||
def query_dnsbl (self, query, zone, callback, rr = adns.rr.A):
|
||||
""" Queue a reverse dnsbl-type query. """
|
||||
self._queries [self.resolver.submit_reverse_any (query, zone, rr)] = callback, rr
|
||||
|
||||
def done (self):
|
||||
""" Are all queued queries answered? """
|
||||
return not self._queries
|
||||
|
||||
def wait (self, timeout = 10):
|
||||
""" Wait for the queries to complete. """
|
||||
|
||||
timeout += time.time ()
|
||||
while self._queries and time.time () < timeout:
|
||||
for q in self.resolver.completed (1):
|
||||
answer = q.check ()
|
||||
callback, rr = self._queries[q]
|
||||
del self._queries[q]
|
||||
|
||||
# print (answer)
|
||||
|
||||
a0 = answer[0]
|
||||
if a0 == 0:
|
||||
callback (self.decode_answer (rr, answer[3]))
|
||||
elif a0 == 101 and rr == adns.rr.A:
|
||||
# got CNAME, wanted A: resubmit
|
||||
self.query (answer[1], callback, rr)
|
||||
# else
|
||||
# pass
|
||||
|
||||
|
||||
def decode_answer (self, rr, answers):
|
||||
""" Decode the answer to unicode.
|
||||
|
||||
Supports only some rr types. You may override this to support
|
||||
some more.
|
||||
|
||||
"""
|
||||
|
||||
if rr in (adns.rr.A, adns.rr.TXT):
|
||||
# A records are ip addresses that need no decoding.
|
||||
# TXT records may be anything, even binary data,
|
||||
# so leave decoding to the caller.
|
||||
return answers
|
||||
|
||||
if rr in (adns.rr.PTR, adns.rr.PTRraw, adns.rr.CNAME, adns.rr.NSraw):
|
||||
return [ self.decode (host) for host in answers ]
|
||||
|
||||
if rr == adns.rr.MXraw:
|
||||
return [ (prio, self.decode (host)) for (prio, host) in answers ]
|
||||
|
||||
if rr == adns.rr.SRVraw:
|
||||
return [ (prio, weight, port, self.decode (host))
|
||||
for (prio, weight, port, host) in answers ]
|
||||
|
||||
if rr in (adns.rr.SOA, adns.rr.SOAraw):
|
||||
return [ (self.decode (mname), self.decode (rname),
|
||||
serial, refresh, retry, expire, minimum)
|
||||
for (mname, rname, serial, refresh,
|
||||
retry, expire, minimum) in answers ]
|
||||
|
||||
# unsupported HINFO, RP, RPraw, NS, SRV, MX
|
||||
|
||||
return answers
|
||||
|
||||
|
||||
@staticmethod
|
||||
def encode (query):
|
||||
""" Encode a unicode query to idna.
|
||||
|
||||
Result will still be of type unicode/str.
|
||||
"""
|
||||
return query.encode ('idna').decode ('ascii')
|
||||
|
||||
|
||||
@staticmethod
|
||||
def decode (answer):
|
||||
""" Decode an answer to unicode. """
|
||||
try:
|
||||
return answer.decode ('idna')
|
||||
except ValueError:
|
||||
return answer.decode ('ascii', 'replace')
|
||||
|
||||
|
||||
def cancel (self):
|
||||
""" Cancel all pending queries. """
|
||||
|
||||
for q in self._queries.keys ():
|
||||
q.cancel ()
|
||||
self._queries.clear ()
|
||||
|
||||
|
||||
def bulk_query (self, query_dict, rr):
|
||||
""" Bulk lookup.
|
||||
|
||||
:param dict: on entry { query1: None, query2: None }
|
||||
on exit { query1: (answer1, ), query2: (answer2a, answer2b) }
|
||||
|
||||
Note: you must call wait () after bulk_query () for the answers to appear
|
||||
|
||||
"""
|
||||
|
||||
def itemsetter (query):
|
||||
""" Return a callable object that puts the answer into
|
||||
the dictionary under the right key. """
|
||||
def g (answer):
|
||||
""" Put the answer into the dictionary. """
|
||||
query_dict[query] = answer
|
||||
# print "put: " + answer
|
||||
return g
|
||||
|
||||
for query in query_dict.keys ():
|
||||
if query:
|
||||
self.query (query, itemsetter (query), rr)
|
||||
|
||||
|
||||
def bulk_query (dict_, rr = adns.rr.A, timeout = 10):
|
||||
""" Perform bulk lookup. """
|
||||
a = AsyncDNS ()
|
||||
a.bulk_query (dict_, rr)
|
||||
a.wait (timeout)
|
||||
a.cancel ()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import netaddr
|
||||
|
||||
queries = dict ()
|
||||
for i in range (64, 64 + 32):
|
||||
ip = '66.249.%d.42' % i # google assigned netblock
|
||||
queries[ip] = None
|
||||
|
||||
bulk_query (queries, adns.rr.PTR)
|
||||
|
||||
ipset = netaddr.IPSet ()
|
||||
for ip in sorted (queries):
|
||||
if queries[ip] and 'proxy' in queries[ip][0]:
|
||||
print (ip)
|
||||
ipset.add (ip + '/24')
|
||||
|
||||
for cidr in ipset.iter_cidrs ():
|
||||
print (cidr)
|
321
ipinfo.py
321
ipinfo.py
|
@ -1,321 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- mode: python; indent-tabs-mode: nil; -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
ipinfo.py
|
||||
|
||||
Copyright 2013-14 by Marcello Perathoner
|
||||
|
||||
Distributable under the GNU General Public License Version 3 or newer.
|
||||
|
||||
Find information about an IP, eg. hostname, whois, DNS blocklists.
|
||||
|
||||
|
||||
The Spamhaus Block List (SBL) Advisory is a database of IP
|
||||
addresses from which Spamhaus does not recommend the acceptance of
|
||||
electronic mail.
|
||||
|
||||
The Spamhaus Exploits Block List (XBL) is a realtime database
|
||||
of IP addresses of hijacked PCs infected by illegal 3rd party
|
||||
exploits, including open proxies (HTTP, socks, AnalogX, wingate,
|
||||
etc), worms/viruses with built-in spam engines, and other types of
|
||||
trojan-horse exploits.
|
||||
|
||||
The Spamhaus PBL is a DNSBL database of end-user IP address
|
||||
ranges which should not be delivering unauthenticated SMTP email
|
||||
to any Internet mail server except those provided for specifically
|
||||
by an ISP for that customer's use. The PBL helps networks enforce
|
||||
their Acceptable Use Policy for dynamic and non-MTA customer IP
|
||||
ranges.
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import asyncdns
|
||||
|
||||
# pylint: disable=R0903
|
||||
|
||||
class DNSBL (object):
|
||||
""" Base class for DNS blocklists. """
|
||||
|
||||
zone = ''
|
||||
blackhat_tags = {}
|
||||
dialup_tags = {}
|
||||
|
||||
|
||||
### TOR ###
|
||||
# see:
|
||||
# https://www.torproject.org/projects/tordnsel.html.en
|
||||
# https://www.dan.me.uk/dnsbl
|
||||
|
||||
class TorProject (DNSBL):
|
||||
""" A TOR exitnode list. """
|
||||
|
||||
# note: reverse IP of www.gutenberg.org:80
|
||||
zone = '80.47.134.19.152.ip-port.exitlist.torproject.org'
|
||||
blackhat_tags = {
|
||||
'127.0.0.2': 'TOR',
|
||||
}
|
||||
|
||||
class TorDanme (DNSBL):
|
||||
""" A TOR exitnode list. """
|
||||
|
||||
zone = 'torexit.dan.me.uk'
|
||||
blackhat_tags = {
|
||||
'127.0.0.100': 'TOR',
|
||||
}
|
||||
|
||||
|
||||
### SPAMHAUS ###
|
||||
# see: http://www.spamhaus.org/faq/answers.lasso?section=DNSBL%20Usage#202
|
||||
|
||||
class Spamhaus (DNSBL):
|
||||
""" A DNS blocklist. """
|
||||
|
||||
zone = 'zen.spamhaus.org'
|
||||
blackhat_tags = {
|
||||
'127.0.0.2': 'SPAMHAUS_SBL',
|
||||
'127.0.0.3': 'SPAMHAUS_SBL_CSS',
|
||||
'127.0.0.4': 'SPAMHAUS_XBL_CBL',
|
||||
}
|
||||
dialup_tags = {
|
||||
'127.0.0.10': 'SPAMHAUS_PBL_ISP',
|
||||
'127.0.0.11': 'SPAMHAUS_PBL',
|
||||
}
|
||||
lookup = 'http://www.spamhaus.org/query/ip/{ip}'
|
||||
|
||||
|
||||
### SORBS ###
|
||||
# see: http://www.sorbs.net/using.shtml
|
||||
|
||||
class SORBS (DNSBL):
|
||||
""" A DNS blocklist. """
|
||||
|
||||
zone = 'dnsbl.sorbs.net'
|
||||
blackhat_tags = {
|
||||
'127.0.0.2': 'SORBS_HTTP_PROXY',
|
||||
'127.0.0.3': 'SORBS_SOCKS_PROXY',
|
||||
'127.0.0.4': 'SORBS_MISC_PROXY',
|
||||
'127.0.0.5': 'SORBS_SMTP_RELAY',
|
||||
'127.0.0.6': 'SORBS_SPAMMER',
|
||||
'127.0.0.7': 'SORBS_WEB', # formmail etc.
|
||||
'127.0.0.8': 'SORBS_BLOCK',
|
||||
'127.0.0.9': 'SORBS_ZOMBIE',
|
||||
'127.0.0.11': 'SORBS_BADCONF',
|
||||
'127.0.0.12': 'SORBS_NOMAIL',
|
||||
}
|
||||
dialup_tags = {
|
||||
'127.0.0.10': 'SORBS_DUL',
|
||||
}
|
||||
|
||||
|
||||
### mailspike.net ###
|
||||
# see: http://mailspike.net/usage.html
|
||||
|
||||
class MailSpike (DNSBL):
|
||||
""" A DNS blocklist. """
|
||||
|
||||
zone = 'bl.mailspike.net'
|
||||
blackhat_tags = {
|
||||
'127.0.0.2': 'MAILSPIKE_DISTRIBUTED_SPAM',
|
||||
'127.0.0.10': 'MAILSPIKE_WORST_REPUTATION',
|
||||
'127.0.0.11': 'MAILSPIKE_VERY_BAD_REPUTATION',
|
||||
'127.0.0.12': 'MAILSPIKE_BAD_REPUTATION',
|
||||
}
|
||||
|
||||
|
||||
### shlink.org ###
|
||||
# see: http://shlink.org/
|
||||
|
||||
class BlShlink (DNSBL):
|
||||
""" A DNS blocklist. """
|
||||
|
||||
zone = 'bl.shlink.org'
|
||||
blackhat_tags = {
|
||||
'127.0.0.2': 'SHLINK_SPAM_SENDER',
|
||||
'127.0.0.4': 'SHLINK_SPAM_ORIGINATOR',
|
||||
'127.0.0.5': 'SHLINK_POLICY_BLOCK',
|
||||
'127.0.0.6': 'SHLINK_ATTACKER',
|
||||
}
|
||||
|
||||
class DynShlink (DNSBL):
|
||||
""" A DNS dul list. """
|
||||
|
||||
zone = 'dyn.shlink.org'
|
||||
dialup_tags = {
|
||||
'127.0.0.3': 'SHLINK_DUL',
|
||||
}
|
||||
|
||||
|
||||
### barracudacentral.org ###
|
||||
# see: http://www.barracudacentral.org/rbl/how-to-usee
|
||||
|
||||
class Barracuda (DNSBL):
|
||||
""" A DNS blocklist. """
|
||||
|
||||
zone = 'b.barracudacentral.org'
|
||||
blackhat_tags = {
|
||||
'127.0.0.2': 'BARRACUDA_BLOCK',
|
||||
}
|
||||
|
||||
|
||||
### SHADOWSERVER ###
|
||||
# http://www.shadowserver.org/wiki/pmwiki.php/Services/IP-BGP
|
||||
|
||||
class ShadowServer (DNSBL):
|
||||
""" A DNS-based whois service. """
|
||||
|
||||
zone = 'origin.asn.shadowserver.org'
|
||||
peer_zone = 'peer.asn.shadowserver.org'
|
||||
fields = 'asn cidr org2 country org1 org'.split ()
|
||||
|
||||
|
||||
# TEAMCYMRU
|
||||
# http://www.team-cymru.org/Services/ip-to-asn.html
|
||||
|
||||
class TeamCymru (DNSBL):
|
||||
""" A DNS-based whois service. """
|
||||
|
||||
zone = 'origin.asn.cymru.com'
|
||||
asn_zone = 'asn.cymru.com'
|
||||
fields = 'asn cidr country registry date'.split ()
|
||||
|
||||
|
||||
class IPInfo (object):
|
||||
""" Holds DNSBL information for one IP. """
|
||||
|
||||
dnsbl = [ Spamhaus, SORBS, MailSpike, BlShlink, DynShlink, Barracuda,
|
||||
TorProject, TorDanme ]
|
||||
""" Which blocklists to consider. """
|
||||
|
||||
def __init__ (self, aresolver, ip):
|
||||
self.hostname = None
|
||||
self.whois = {}
|
||||
self.blackhat_tags = set ()
|
||||
self.dialup_tags = set ()
|
||||
|
||||
ip = str (ip)
|
||||
rr = asyncdns.adns.rr
|
||||
|
||||
try:
|
||||
aresolver.query (ip, self._hostnamesetter (), rr.PTR)
|
||||
|
||||
for dnsbl in self.dnsbl:
|
||||
aresolver.query_dnsbl (ip, dnsbl.zone, self._tagsetter (dnsbl))
|
||||
|
||||
# ShadowServer seems down: March 2014
|
||||
aresolver.query_dnsbl (ip, ShadowServer.zone, self._whoissetter_ss (), rr.TXT)
|
||||
# aresolver.query_dnsbl (ip, TeamCymru.zone, self._whoissetter_tc (aresolver), rr.TXT)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
@property
|
||||
def tags (self):
|
||||
""" All tags (bad and dialup). """
|
||||
return self.blackhat_tags | self.dialup_tags
|
||||
|
||||
|
||||
def is_blackhat (self):
|
||||
""" Return true if this is probably a blackhat IP. """
|
||||
return bool (self.blackhat_tags)
|
||||
|
||||
|
||||
def is_dialup (self):
|
||||
""" Test if this IP is a dialup. """
|
||||
return bool (self.dialup_tags)
|
||||
|
||||
|
||||
def is_tor_exit (self):
|
||||
""" Test if this is a Tor exit node. """
|
||||
return 'TOR' in self.blackhat_tags
|
||||
|
||||
|
||||
def _hostnamesetter (self):
|
||||
""" Return a callable object that puts the answer into
|
||||
the hostname attribute. """
|
||||
def g (answer):
|
||||
""" Store answer. """
|
||||
self.hostname = answer[0]
|
||||
return g
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _filter (answers, tag_dict):
|
||||
""" Lookup answers in tag_dict, return values of matches. """
|
||||
return [ tag_dict[ip] for ip in answers if ip in tag_dict ]
|
||||
|
||||
|
||||
def _tagsetter (self, dnsbl):
|
||||
""" Return a callable object that puts the answer into
|
||||
our *tags attributes. """
|
||||
def g (answer):
|
||||
""" Store answer. """
|
||||
self.blackhat_tags.update (self._filter (answer, dnsbl.blackhat_tags))
|
||||
self.dialup_tags.update (self._filter (answer, dnsbl.dialup_tags))
|
||||
return g
|
||||
|
||||
|
||||
@staticmethod
|
||||
def _decode_txt (answer):
|
||||
""" Helper: decode / unpack whois answer. """
|
||||
try:
|
||||
answer = answer[0][0].decode ('utf-8')
|
||||
except UnicodeError:
|
||||
answer = answer[0][0].decode ('iso-8859-1')
|
||||
answer = answer.strip ('"').split ('|')
|
||||
return [ a.strip () for a in answer if a ]
|
||||
|
||||
|
||||
def _whoissetter_ss (self):
|
||||
""" Return a callable object that puts the answer into
|
||||
the whois dict. """
|
||||
def g (answer):
|
||||
""" Store answer. """
|
||||
self.whois = dict (zip (ShadowServer.fields, self._decode_txt (answer)))
|
||||
return g
|
||||
|
||||
|
||||
def _whoissetter_tc (self, aresolver):
|
||||
""" Return a callable object that puts the answer into
|
||||
the right attribute. """
|
||||
def g (answer):
|
||||
""" Store answer. """
|
||||
self.whois = dict (zip (TeamCymru.fields, self._decode_txt (answer)))
|
||||
self.whois['org'] = None
|
||||
# maybe there's still more info?
|
||||
aresolver.query ('AS' + self.whois['asn'] + '.' + TeamCymru.asn_zone,
|
||||
self._whoissetter_tc2 (), asyncdns.adns.rr.TXT)
|
||||
return g
|
||||
|
||||
|
||||
def _whoissetter_tc2 (self):
|
||||
""" Return a callable object that puts the answer into
|
||||
the right attribute. """
|
||||
def g (answer):
|
||||
""" Store answer. """
|
||||
self.whois['org'] = self._decode_txt (answer)[-1]
|
||||
return g
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
# test IP 127.0.0.2 should give all positives
|
||||
|
||||
a = asyncdns.AsyncDNS (asyncdns.RESOLV_CONF)
|
||||
i = IPInfo (a, sys.argv[1])
|
||||
a.wait ()
|
||||
a.cancel ()
|
||||
|
||||
print ('hostname: %s' % i.hostname)
|
||||
for k in sorted (i.whois.keys ()):
|
||||
print ("%s: %s" % (k, i.whois[k]))
|
||||
for tag in sorted (i.tags):
|
||||
print (tag)
|
||||
if i.is_blackhat ():
|
||||
print ('BLACKHAT')
|
||||
if i.is_dialup ():
|
||||
print ('DUL')
|
Loading…
Reference in New Issue