1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
# -*- coding: utf-8 -*-
import dns.resolver as dns
import tabulate
from config import Config
class ReportDomain:
def __init__(self, conn):
"""
:param conn: sqlite connection object
"""
self.config = Config().load()
self.conn = conn
self.start = int()
self.stop = int()
def addtime(self, start, stop):
# add start and stop timestamps
self.start = start
self.stop = stop
def template(self, template: str, domain: str, query: list):
"""
method to retrieve and format the template file
:param template: string containing the abuse report template
:param domain: string containing a domain name
:param query: list of tuples containing the query results for the specified domain/s
:return: string containing the fully formatted abuse report
"""
name = self.config["name"]
# lookup and format srv target and ip
srv, ips = self.srv(domain)
summary = tabulate.tabulate(query, headers=["messages", "bots", "domain", "first seen", "last seen"],
tablefmt="github")
report_out = template.format(name=name, domain=domain, srv=srv, ips=ips, summary=summary)
return report_out
def jids(self, domain: str):
"""
method to collect all involved jids from the database
:param domain: string containing a domain name
:return: formatted result string
"""
sql = '''SELECT user || '@' || domain AS jid FROM spam
WHERE ts > :start
AND ts < :stop
AND domain = :domain
GROUP BY user ORDER BY 1;'''
param = {"domain": domain, "start": self.start, "stop":self.stop}
jids = self.conn.execute(sql, param).fetchall()
return tabulate.tabulate(jids, tablefmt="plain")
def logs(self, domain: str):
"""
method to collect all messages grouped by frequency
:param domain: string containing a domain name
:return: formatted string containing the result
"""
sql = '''SELECT CHAR(10) || MIN(ts) || ' - ' || MAX(ts) || char(10) || COUNT(*) || 'messages:' || char(10) ||
'========================================================================' || char(10) || message ||
char(10) || '========================================================================' FROM spam
WHERE ts > :start
AND ts < :stop
AND domain = :domain
GROUP BY message ORDER BY COUNT(*) DESC LIMIT 10;'''
param = {"domain": domain, "start": self.start, "stop": self.stop}
logs = self.conn.execute(sql, param).fetchall()
return tabulate.tabulate(logs, tablefmt="plain")
def srv(self, domain: str, only_highest: bool = True):
info = self._srvlookup(domain)
if only_highest:
target = info[0]["host"]
ips = info[0]["ip"]
return target, ips
return info
@staticmethod
def _getip(domain: str):
"""
method to query the a / aaaa record of a specified domain
:param domain: valid domain target
:return: filtered list of all a/ aaaa records
"""
# init records
a, a4 = None, None
try:
# query and join both a and aaaa records
a = ", ".join([ip.address for ip in dns.query(domain, "A")])
a4 = ", ".join([ip.address for ip in dns.query(domain, "AAAA")])
except (dns.NXDOMAIN, dns.NoAnswer):
# catch NXDOMAIN and NoAnswer tracebacks not really important
pass
return list(filter(None.__ne__, [a, a4]))
def _srvlookup(self, domain: str):
"""
srv lookup method for the domain provided, if no srv record is found the base domain is used
:param domain: provided domain to query srv records for
:return: sorted list of dictionaries containing host and ip info
"""
# init
results = list()
srv_records = None
try:
srv_records = dns.query('_xmpp-client._tcp.{}'.format(domain), 'SRV')
except (dns.NXDOMAIN, dns.NoAnswer):
# catch NXDOMAIN and NoAnswer tracebacks
pass
# extract record
if srv_records is not None:
# extract all available records
for record in srv_records:
info = dict()
# gather necessary info from srv records
info["host"] = record.target.to_text().rstrip('.')
info["port"] = record.port
info["weight"] = record.weight
info["priority"] = record.priority
info["ip"] = ", ".join(self._getip(record.target.to_text()))
results.append(info)
# return list sorted by priority and weightre
return sorted(results, key=lambda i: (i['priority'], i["weight"]))
# prevent empty info when srv records are not present
info = dict()
# gather necessary info from srv records
info["host"] = domain
info["ip"] = ", ".join(self._getip(domain))
results.append(info)
return results
|