From 6cc73f2af81ceff6d9724c48f5625bbcee3b1bb6 Mon Sep 17 00:00:00 2001 From: guyddr Date: Mon, 20 Jan 2020 22:08:42 +0100 Subject: [PATCH 1/3] python 3 compat --- dnsdb_query.py | 123 +++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 59 deletions(-) diff --git a/dnsdb_query.py b/dnsdb_query.py index 9c5ad12..4e7c7c2 100755 --- a/dnsdb_query.py +++ b/dnsdb_query.py @@ -16,6 +16,7 @@ import calendar import errno +import json import locale import optparse import os @@ -23,13 +24,9 @@ import sys import time import urllib -import urllib2 -from cStringIO import StringIO +from io import StringIO -try: - import json -except ImportError: - import simplejson as json +import urllib3 DEFAULT_CONFIG_FILES = filter(os.path.isfile, ('/etc/dnsdb-query.conf', os.path.expanduser('~/.dnsdb-query.conf'))) DEFAULT_DNSDB_SERVER = 'https://api.dnsdb.info' @@ -38,13 +35,15 @@ cfg = None options = None -debug = False # set to True to print raw queries and responses +debug = False # set to True to print raw queries and responses locale.setlocale(locale.LC_ALL, '') + class QueryError(Exception): pass + class DnsdbClient(object): def __init__(self, server, apikey, limit=None, http_proxy=None, https_proxy=None): self.server = server @@ -91,41 +90,38 @@ def _query(self, path, before=None, after=None): if after: params['time_last_after'] = after if params: - url += '?{0}'.format(urllib.urlencode(params)) + url += '?{0}'.format(urllib.parse.urlencode(params)) - req = urllib2.Request(url) - req.add_header('Accept', 'application/json') - req.add_header('X-Api-Key', self.apikey) - - proxy_args = {} - if self.http_proxy: - proxy_args['http'] = self.http_proxy - if self.https_proxy: - proxy_args['https'] = self.https_proxy - proxy_handler = urllib2.ProxyHandler(proxy_args) - opener = urllib2.build_opener(proxy_handler) + http = urllib3.PoolManager() + headers = { + 'Accept': 'application/json', + 'X-Api-Key': self.apikey + } if debug: - print >>sys.stderr, ";; query URL =", url + sys.stderr.write(";; query URL =" + url) try: - http = opener.open(req) - while True: - line = http.readline() - if not line: - break - if debug: - print >>sys.stderr, ";; response =", line.strip() - yield json.loads(line) - except (urllib2.HTTPError, urllib2.URLError), e: - raise QueryError, str(e), sys.exc_traceback + r = http.request('GET', url, headers=headers) + + json_data = r.data.decode('utf-8') + if json_data: + json_list = json_data.splitlines() + for line in json_list: + yield json.loads(line) + + except (urllib3.exceptions.HTTPError) as e: + raise QueryError(str(e)) + def quote(path): - return urllib.quote(path, safe='') + return urllib.parse.quote(path, safe='') + def sec_to_text(ts): return time.strftime('%Y-%m-%d %H:%M:%S -0000', time.gmtime(ts)) + def rrset_to_text(m): s = StringIO() @@ -155,9 +151,11 @@ def rrset_to_text(m): finally: s.close() + def rdata_to_text(m): return '%s IN %s %s' % (m['rrname'], m['rrtype'], m['rdata']) + def parse_config(cfg_files): config = {} @@ -172,6 +170,7 @@ def parse_config(cfg_files): return config + def time_parse(s): try: epoch = int(s) @@ -193,14 +192,15 @@ def time_parse(s): m = re.match(r'^(?=\d)(?:(\d+)w)?(?:(\d+)d)?(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?$', s, re.I) if m: - return -1*(int(m.group(1) or 0)*604800 + \ - int(m.group(2) or 0)*86400+ \ - int(m.group(3) or 0)*3600+ \ - int(m.group(4) or 0)*60+ \ - int(m.group(5) or 0)) + return -1 * (int(m.group(1) or 0) * 604800 + \ + int(m.group(2) or 0) * 86400 + \ + int(m.group(3) or 0) * 3600 + \ + int(m.group(4) or 0) * 60 + \ + int(m.group(5) or 0)) raise ValueError('Invalid time: "%s"' % s) + def epipe_wrapper(func): def f(*args, **kwargs): try: @@ -209,34 +209,37 @@ def f(*args, **kwargs): if e.errno == errno.EPIPE: sys.exit(e.errno) raise + return f + @epipe_wrapper def main(): global cfg global options global debug - parser = optparse.OptionParser(epilog='Time formats are: "%Y-%m-%d", "%Y-%m-%d %H:%M:%S", "%d" (UNIX timestamp), "-%d" (Relative time in seconds), BIND format (e.g. 1w1h, (w)eek, (d)ay, (h)our, (m)inute, (s)econd)') - parser.add_option('-c', '--config', dest='config', - help='config file', action='append') + parser = optparse.OptionParser( + epilog='Time formats are: "%Y-%m-%d", "%Y-%m-%d %H:%M:%S", "%d" (UNIX timestamp), "-%d" (Relative time in seconds), BIND format (e.g. 1w1h, (w)eek, (d)ay, (h)our, (m)inute, (s)econd)') + parser.add_option('-c', '--config', dest='config', + help='config file', action='append') parser.add_option('-r', '--rrset', dest='rrset', type='string', - help='rrset [/[/BAILIWICK]]') + help='rrset [/[/BAILIWICK]]') parser.add_option('-n', '--rdataname', dest='rdata_name', type='string', - help='rdata name [/]') + help='rdata name [/]') parser.add_option('-i', '--rdataip', dest='rdata_ip', type='string', - help='rdata ip ') + help='rdata ip ') parser.add_option('-t', '--rrtype', dest='rrtype', type='string', - help='rrset or rdata rrtype') + help='rrset or rdata rrtype') parser.add_option('-b', '--bailiwick', dest='bailiwick', type='string', - help='rrset bailiwick') + help='rrset bailiwick') parser.add_option('-s', '--sort', dest='sort', type='string', help='sort key') parser.add_option('-R', '--reverse', dest='reverse', action='store_true', default=False, - help='reverse sort') + help='reverse sort') parser.add_option('-j', '--json', dest='json', action='store_true', default=False, - help='output in JSON format') + help='output in JSON format') parser.add_option('-l', '--limit', dest='limit', type='int', default=0, - help='limit number of results') + help='limit number of results') parser.add_option('-d', '--debug', dest='debug', action='store_true', default=False, help='print debug output') @@ -253,19 +256,19 @@ def main(): try: if options.before: options.before = time_parse(options.before) - except ValueError, e: - print 'Could not parse before: {}'.format(options.before) + except ValueError as e: + print('Could not parse before: {}'.format(options.before)) try: if options.after: options.after = time_parse(options.after) - except ValueError, e: - print 'Could not parse after: {}'.format(options.after) + except ValueError as e: + print('Could not parse after: {}'.format(options.after)) try: cfg = parse_config(options.config or DEFAULT_CONFIG_FILES) - except IOError, e: - print >>sys.stderr, str(e) + except IOError as e: + sys.stderr.writable(str(e)) sys.exit(1) if not 'DNSDB_SERVER' in cfg: @@ -279,9 +282,9 @@ def main(): sys.exit(1) client = DnsdbClient(cfg['DNSDB_SERVER'], cfg['APIKEY'], - limit=options.limit, - http_proxy=cfg['HTTP_PROXY'], - https_proxy=cfg['HTTPS_PROXY']) + limit=options.limit, + http_proxy=cfg['HTTP_PROXY'], + https_proxy=cfg['HTTPS_PROXY']) if options.rrset: if options.rrtype or options.bailiwick: qargs = (options.rrset, options.rrtype, options.bailiwick) @@ -315,14 +318,16 @@ def main(): if not options.sort in results[0]: sort_keys = results[0].keys() sort_keys.sort() - sys.stderr.write('dnsdb_query: invalid sort key "%s". valid sort keys are %s\n' % (options.sort, ', '.join(sort_keys))) + sys.stderr.write('dnsdb_query: invalid sort key "%s". valid sort keys are %s\n' % ( + options.sort, ', '.join(sort_keys))) sys.exit(1) results.sort(key=lambda r: r[options.sort], reverse=options.reverse) for res in results: sys.stdout.write('%s\n' % fmt_func(res)) - except QueryError, e: - print >>sys.stderr, e.message + except QueryError as e: + sys.stderr.write(e.message) sys.exit(1) + if __name__ == '__main__': main() From 424078e5338c7be260eae2f4ba2afe4adeb63fd6 Mon Sep 17 00:00:00 2001 From: guyddr Date: Wed, 22 Jan 2020 15:25:34 +0100 Subject: [PATCH 2/3] Updated README.md to reflect upgrade to python 3 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93f3b84..a532fd7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Requirements ------------ * Linux, BSD, OS X * Curl - * Python 2.7.x + * Python 3.x * Farsight DNSDB API key Installation From 3b0974825824e384a891fef0d061f9ac3952916b Mon Sep 17 00:00:00 2001 From: guyddr Date: Thu, 23 Jan 2020 11:34:37 +0100 Subject: [PATCH 3/3] Added Python 3 version of proxy support, as per comment by djw1149. --- dnsdb_query.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/dnsdb_query.py b/dnsdb_query.py index 4e7c7c2..cb72b6e 100755 --- a/dnsdb_query.py +++ b/dnsdb_query.py @@ -92,7 +92,13 @@ def _query(self, path, before=None, after=None): if params: url += '?{0}'.format(urllib.parse.urlencode(params)) - http = urllib3.PoolManager() + if self.https_proxy: + manager = urllib3.ProxyManager(self.https_proxy) + elif self.http_proxy: + manager = urllib3.ProxyManager(self.http_proxy) + else: + manager = urllib3.PoolManager() + headers = { 'Accept': 'application/json', 'X-Api-Key': self.apikey @@ -102,7 +108,7 @@ def _query(self, path, before=None, after=None): sys.stderr.write(";; query URL =" + url) try: - r = http.request('GET', url, headers=headers) + r = manager.request(method='GET', url=url, headers=headers) json_data = r.data.decode('utf-8') if json_data: