2013-12-23 15:43:29 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
#
|
|
|
|
# A pdns-qof compliant passive DNS interface for the pdns-toolkit
|
|
|
|
#
|
|
|
|
# https://github.com/adulau/pdns-qof-server/
|
|
|
|
# https://github.com/adulau/pdns-toolkit/
|
|
|
|
#
|
|
|
|
# The pdns-qof - Passive DNS Query Output Format Description are described at
|
|
|
|
#
|
|
|
|
# https://github.com/adulau/pdns-qof
|
|
|
|
#
|
|
|
|
# Software is free software released under the "Modified BSD license"
|
|
|
|
#
|
|
|
|
# Copyright (c) 2013 Alexandre Dulaunoy - a@foo.be
|
|
|
|
|
2013-12-24 13:14:01 +00:00
|
|
|
import tornado.escape
|
|
|
|
import tornado.web
|
2016-08-29 14:53:53 +00:00
|
|
|
import tornado.process
|
2016-08-29 21:23:29 +00:00
|
|
|
from tornado.ioloop import IOLoop
|
2016-08-29 14:53:53 +00:00
|
|
|
from tornado.concurrent import run_on_executor
|
2013-12-24 13:14:01 +00:00
|
|
|
|
2016-08-29 21:23:29 +00:00
|
|
|
from concurrent.futures import ThreadPoolExecutor
|
2016-08-29 14:53:53 +00:00
|
|
|
import argparse
|
2016-08-29 13:19:42 +00:00
|
|
|
import sys
|
2016-08-29 14:53:53 +00:00
|
|
|
import signal
|
2016-08-29 21:23:29 +00:00
|
|
|
from ipaddress import ip_address
|
2016-08-29 14:53:53 +00:00
|
|
|
|
2016-08-31 16:01:51 +00:00
|
|
|
from qos_server.query import QueryRecords
|
2016-08-29 15:45:41 +00:00
|
|
|
|
2016-08-29 14:53:53 +00:00
|
|
|
|
|
|
|
def handle_signal(sig, frame):
|
|
|
|
IOLoop.instance().add_callback(IOLoop.instance().stop)
|
2013-12-23 15:43:29 +00:00
|
|
|
|
2016-08-29 13:19:42 +00:00
|
|
|
|
2016-08-29 21:23:29 +00:00
|
|
|
def is_ip(q):
|
|
|
|
try:
|
|
|
|
ip_address(q)
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2013-12-24 13:14:01 +00:00
|
|
|
class InfoHandler(tornado.web.RequestHandler):
|
|
|
|
def get(self):
|
2016-08-29 21:23:29 +00:00
|
|
|
response = {'version': 'git', 'software': 'pdns-qof-server'}
|
2013-12-24 13:14:01 +00:00
|
|
|
self.write(response)
|
|
|
|
|
2016-08-29 13:19:42 +00:00
|
|
|
|
2013-12-24 13:14:01 +00:00
|
|
|
class QueryHandler(tornado.web.RequestHandler):
|
2016-08-29 14:14:47 +00:00
|
|
|
|
|
|
|
# Default value in Python 3.5
|
|
|
|
# https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor
|
|
|
|
nb_threads = tornado.process.cpu_count() * 5
|
|
|
|
executor = ThreadPoolExecutor(nb_threads)
|
|
|
|
|
|
|
|
@run_on_executor
|
|
|
|
def run_request(self, q):
|
2016-08-29 21:23:29 +00:00
|
|
|
if is_ip(q):
|
|
|
|
q = query.getAssociatedRecords(q)
|
2013-12-24 13:14:01 +00:00
|
|
|
else:
|
2016-08-29 21:23:29 +00:00
|
|
|
q = [q]
|
|
|
|
return [query.getRecord(x) for x in q]
|
2016-08-29 14:14:47 +00:00
|
|
|
|
|
|
|
@tornado.gen.coroutine
|
|
|
|
def get(self, q):
|
|
|
|
print("query: " + q)
|
|
|
|
try:
|
|
|
|
responses = yield self.run_request(q)
|
|
|
|
for r in responses:
|
|
|
|
self.write(r)
|
|
|
|
except Exception as e:
|
|
|
|
print('Something went wrong with {}:\n{}'.format(q, e))
|
|
|
|
finally:
|
|
|
|
self.finish()
|
2016-08-29 13:19:42 +00:00
|
|
|
|
2013-12-24 13:14:01 +00:00
|
|
|
|
2016-08-29 13:19:42 +00:00
|
|
|
def main():
|
2016-08-29 15:45:41 +00:00
|
|
|
global query
|
2016-08-29 14:53:53 +00:00
|
|
|
signal.signal(signal.SIGINT, handle_signal)
|
|
|
|
signal.signal(signal.SIGTERM, handle_signal)
|
|
|
|
argParser = argparse.ArgumentParser(description='qof-server server')
|
2016-08-29 15:05:33 +00:00
|
|
|
argParser.add_argument('-o', default='https://www.circl.lu/pdns/', help='Origin of the PDNS (default: https://www.circl.lu/pdns/)')
|
2016-08-29 14:53:53 +00:00
|
|
|
argParser.add_argument('-p', default=8888, help='qof-server TCP port (default 8888)')
|
2016-08-29 15:05:33 +00:00
|
|
|
argParser.add_argument('-l', default='localhost', help='qof-server listen address (default localhost)')
|
|
|
|
argParser.add_argument('-rp', default=6379, help='redis-server TCP port (default 8888)')
|
|
|
|
argParser.add_argument('-rl', default='localhost', help='redis-server listen address (default localhost)')
|
|
|
|
argParser.add_argument('-rd', default=0, help='redis-server database (default 0)')
|
2016-08-29 14:53:53 +00:00
|
|
|
args = argParser.parse_args()
|
2016-08-29 21:23:29 +00:00
|
|
|
|
2016-08-29 15:05:33 +00:00
|
|
|
origin = args.o
|
2016-08-29 14:53:53 +00:00
|
|
|
port = args.p
|
|
|
|
listen = args.l
|
2016-08-29 15:05:33 +00:00
|
|
|
redis_port = args.rp
|
|
|
|
redis_listen = args.rl
|
|
|
|
redis_db = args.rd
|
2016-08-29 14:53:53 +00:00
|
|
|
|
2016-08-29 21:23:29 +00:00
|
|
|
query = QueryRecords(redis_listen, redis_port, redis_db, origin)
|
2016-08-29 13:36:59 +00:00
|
|
|
|
2016-08-29 21:23:29 +00:00
|
|
|
application = tornado.web.Application([(r"/query/(.*)", QueryHandler),
|
|
|
|
(r"/info", InfoHandler)])
|
2016-08-29 13:36:59 +00:00
|
|
|
|
2016-08-29 14:53:53 +00:00
|
|
|
application.listen(port, address=listen)
|
|
|
|
IOLoop.instance().start()
|
|
|
|
IOLoop.instance().stop()
|
|
|
|
return 0
|
2016-08-29 13:19:42 +00:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
sys.exit(main())
|
|
|
|
elif __name__ == "test":
|
2016-08-29 15:45:41 +00:00
|
|
|
query = Query('localhost', 6379, 0, 'https://www.circl.lu/pdns/')
|
2013-12-24 09:26:40 +00:00
|
|
|
qq = ["foo.be", "8.8.8.8"]
|
|
|
|
|
|
|
|
for q in qq:
|
2016-08-29 21:23:29 +00:00
|
|
|
if is_ip(q):
|
2016-08-29 15:45:41 +00:00
|
|
|
for x in query.getAssociatedRecords(q):
|
|
|
|
print(query.getRecord(x))
|
2013-12-24 09:26:40 +00:00
|
|
|
else:
|
2016-08-29 15:45:41 +00:00
|
|
|
print(query.getRecord(t=q))
|