aboutsummaryrefslogtreecommitdiffstats
path: root/report.py
blob: 98d50a9e0569e5a1838bbe4a88c4513ac1e30f0a (plain)
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