2019-12-09 08:12:48 +01:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import argparse
|
2019-12-14 17:27:46 +01:00
|
|
|
import database
|
2019-12-13 00:11:21 +01:00
|
|
|
import logging
|
2019-12-14 17:27:46 +01:00
|
|
|
import sys
|
2019-12-13 12:36:11 +01:00
|
|
|
import typing
|
2019-12-14 23:59:50 +01:00
|
|
|
import enum
|
2019-12-14 17:27:46 +01:00
|
|
|
|
2019-12-14 23:59:50 +01:00
|
|
|
RecordType = enum.Enum('RecordType', 'A AAAA CNAME PTR')
|
|
|
|
Record = typing.Tuple[RecordType, int, str, str]
|
2019-12-14 17:27:46 +01:00
|
|
|
|
2019-12-15 15:56:26 +01:00
|
|
|
# select, write
|
2019-12-14 17:27:46 +01:00
|
|
|
FUNCTION_MAP: typing.Any = {
|
2019-12-14 23:59:50 +01:00
|
|
|
RecordType.A: (
|
2019-12-14 17:27:46 +01:00
|
|
|
database.Database.get_ip4,
|
|
|
|
database.Database.set_hostname,
|
|
|
|
),
|
2019-12-14 23:59:50 +01:00
|
|
|
RecordType.CNAME: (
|
2019-12-14 17:27:46 +01:00
|
|
|
database.Database.get_domain,
|
|
|
|
database.Database.set_hostname,
|
|
|
|
),
|
2019-12-14 23:59:50 +01:00
|
|
|
RecordType.PTR: (
|
2019-12-14 17:27:46 +01:00
|
|
|
database.Database.get_domain,
|
|
|
|
database.Database.set_ip4address,
|
|
|
|
),
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-12-14 23:59:50 +01:00
|
|
|
class Parser():
|
2019-12-15 15:56:26 +01:00
|
|
|
def __init__(self, buf: typing.Any) -> None:
|
2019-12-14 23:59:50 +01:00
|
|
|
self.buf = buf
|
2019-12-15 15:56:26 +01:00
|
|
|
self.log = logging.getLogger('parser')
|
|
|
|
self.db = database.Database()
|
2019-12-14 23:59:50 +01:00
|
|
|
|
2019-12-15 15:56:26 +01:00
|
|
|
def end(self) -> None:
|
|
|
|
self.db.save()
|
|
|
|
|
|
|
|
def register(self,
|
|
|
|
rtype: RecordType,
|
|
|
|
updated: int,
|
|
|
|
name: str,
|
|
|
|
value: str
|
|
|
|
) -> None:
|
2019-12-14 23:59:50 +01:00
|
|
|
|
2019-12-15 15:56:26 +01:00
|
|
|
self.db.enter_step('register')
|
|
|
|
select, write = FUNCTION_MAP[rtype]
|
2019-12-15 16:48:17 +01:00
|
|
|
for source in select(self.db, value):
|
|
|
|
# write(self.db, name, updated, source=source)
|
|
|
|
write(self.db, name, updated)
|
2019-12-14 23:59:50 +01:00
|
|
|
|
|
|
|
def consume(self) -> None:
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
|
|
class Rapid7Parser(Parser):
|
|
|
|
TYPES = {
|
|
|
|
'a': RecordType.A,
|
|
|
|
'aaaa': RecordType.AAAA,
|
|
|
|
'cname': RecordType.CNAME,
|
|
|
|
'ptr': RecordType.PTR,
|
|
|
|
}
|
|
|
|
|
|
|
|
def consume(self) -> None:
|
2019-12-15 16:38:01 +01:00
|
|
|
data = dict()
|
2019-12-14 23:59:50 +01:00
|
|
|
for line in self.buf:
|
|
|
|
self.db.enter_step('parse_rapid7')
|
2019-12-15 16:38:01 +01:00
|
|
|
split = line.split('"')
|
|
|
|
|
|
|
|
for k in range(1, 14, 4):
|
|
|
|
key = split[k]
|
|
|
|
val = split[k+2]
|
|
|
|
data[key] = val
|
|
|
|
|
2019-12-15 15:56:26 +01:00
|
|
|
self.register(
|
2019-12-14 23:59:50 +01:00
|
|
|
Rapid7Parser.TYPES[data['type']],
|
|
|
|
int(data['timestamp']),
|
|
|
|
data['name'],
|
|
|
|
data['value']
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
class DnsMassParser(Parser):
|
|
|
|
# dnsmass --output Snrql
|
|
|
|
# --retry REFUSED,SERVFAIL --resolvers nameservers-ipv4
|
|
|
|
TYPES = {
|
|
|
|
'A': (RecordType.A, -1, None),
|
|
|
|
'AAAA': (RecordType.AAAA, -1, None),
|
|
|
|
'CNAME': (RecordType.CNAME, -1, -1),
|
|
|
|
}
|
|
|
|
|
|
|
|
def consume(self) -> None:
|
|
|
|
self.db.enter_step('parse_dnsmass')
|
|
|
|
timestamp = 0
|
|
|
|
header = True
|
|
|
|
for line in self.buf:
|
|
|
|
line = line[:-1]
|
|
|
|
if not line:
|
|
|
|
header = True
|
|
|
|
continue
|
|
|
|
|
|
|
|
split = line.split(' ')
|
|
|
|
try:
|
|
|
|
if header:
|
|
|
|
timestamp = int(split[1])
|
|
|
|
header = False
|
|
|
|
else:
|
|
|
|
dtype, name_offset, value_offset = \
|
|
|
|
DnsMassParser.TYPES[split[1]]
|
2019-12-15 15:56:26 +01:00
|
|
|
self.register(
|
2019-12-14 23:59:50 +01:00
|
|
|
dtype,
|
|
|
|
timestamp,
|
|
|
|
split[0][:name_offset],
|
|
|
|
split[2][:value_offset],
|
|
|
|
)
|
|
|
|
self.db.enter_step('parse_dnsmass')
|
|
|
|
except KeyError:
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
PARSERS = {
|
|
|
|
'rapid7': Rapid7Parser,
|
|
|
|
'dnsmass': DnsMassParser,
|
|
|
|
}
|
|
|
|
|
2019-12-13 12:36:11 +01:00
|
|
|
if __name__ == '__main__':
|
|
|
|
|
|
|
|
# Parsing arguments
|
|
|
|
log = logging.getLogger('feed_dns')
|
2019-12-14 23:59:50 +01:00
|
|
|
args_parser = argparse.ArgumentParser(
|
2019-12-13 12:36:11 +01:00
|
|
|
description="TODO")
|
2019-12-14 23:59:50 +01:00
|
|
|
args_parser.add_argument(
|
|
|
|
'parser',
|
|
|
|
choices=PARSERS.keys(),
|
|
|
|
help="TODO")
|
|
|
|
args_parser.add_argument(
|
2019-12-13 12:36:11 +01:00
|
|
|
'-i', '--input', type=argparse.FileType('r'), default=sys.stdin,
|
|
|
|
help="TODO")
|
2019-12-14 23:59:50 +01:00
|
|
|
args = args_parser.parse_args()
|
2019-12-13 12:36:11 +01:00
|
|
|
|
2019-12-15 15:56:26 +01:00
|
|
|
parser = PARSERS[args.parser](args.input)
|
2019-12-09 08:12:48 +01:00
|
|
|
try:
|
2019-12-15 15:56:26 +01:00
|
|
|
parser.consume()
|
2019-12-09 08:12:48 +01:00
|
|
|
except KeyboardInterrupt:
|
2019-12-15 15:56:26 +01:00
|
|
|
pass
|
|
|
|
parser.end()
|
2019-12-13 12:36:11 +01:00
|
|
|
|