This repository has been archived by the owner on Aug 30, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
sniff.py
executable file
·130 lines (118 loc) · 4.73 KB
/
sniff.py
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
#!/usr/bin/python
# regex
import re
# packet sniffing and decoding
import scapy.all as scapy
import scapy_http.http as shttp
# cache
from cachetools import TTLCache
import random
# threading
import threading
import time
import datetime
# Counting caches
from collections import Counter
import argparse
# For capturing SIGINT
import signal
import sys
class Sniff:
# check if alert still valid on cache removal and, if not, turn off
def alert(self):
if self.__alerted:
hits = list(self.alert.values()).count(self.alertSection)
if hits <= self.alertSize:
print('High traffic resolved an alert - hits = ' +
str(hits) +
', triggered at ' +
str(datetime.datetime.now()))
self.__alerted = False
# loop to print summary every 10 seconds
def summary(self):
next_call = time.time()
self.summary_run = threading.Event()
self.summary_run.set()
while self.summary_run.isSet():
if self.cache.currsize != 0:
print("Summary\nSite: # of hits")
counter = Counter(list(self.cache.values()))
for site in Counter(list(self.cache.values())).most_common():
print(site[0] + ": " + str(site[1]))
totalhits = sum(counter.values())
print("Total hits: " + str(totalhits) +
" Hits per second: " + str(totalhits/self.cache.ttl))
# prevent drift by taking summary runtime into account
next_call = next_call+self.cache.ttl
time.sleep(next_call - time.time())
# thread to trigger alert cache experation
def expire(self):
# trigger experation on signal or timeout
self.e.wait(timeout=self.alert.ttl)
self.alert.expire()
def pkt(self, pkt):
if shttp.HTTPRequest in pkt:
# get website section
host = pkt['HTTPRequest'].Host.decode("utf-8")
# regex for site section
pathre = r'^((\/\w+)\/?)'
matches = re.match(pathre, pkt['HTTPRequest'].Path.decode("utf-8"))
if matches:
host += matches.group(2)
# add entries to both caches
self.cache[random.randint(0, self.cache.maxsize)] = host
self.alert[random.randint(0, self.alert.maxsize)] = host
if host == self.alertSection:
hits = list(self.alert.values()).count(self.alertSection)
if hits > self.alertSize:
# if not alerted, activate
if not self.__alerted:
print('High traffic generated an alert - hits = ' +
str(hits) +
', triggered at ' +
str(datetime.datetime.now()))
self.__alerted = True
# if alerted, kill existing expire thread
elif self.__alerted:
self.e.set()
self.e.clear()
# start expire thread
expireThread = threading.Thread(target=self.expire)
expireThread.start()
def signal_handler(self, sig, frame):
print('Exiting')
# kill alert thread on exit
self.e.set()
sys.exit(0)
def __init__(self, alertsection=None, alertsize=0, maxcachesize=1024,
cttl=10, attl=120):
self.__alerted = False
self.cache = TTLCache(maxsize=maxcachesize, ttl=cttl)
self.alert = TTLCache(maxsize=maxcachesize, ttl=attl, cb=self.alert)
self.alertSection = alertsection
self.alertSize = alertsize
self.e = threading.Event()
signal.signal(signal.SIGINT, self.signal_handler)
def __call__(self):
# start summary thread
timerThread = threading.Thread(target=self.summary)
timerThread.daemon = True
timerThread.start()
# only look at tcp based http traffic to and from port 80 for speed
filter = "(tcp and dst port 80) or (tcp and src port 80)"
scapy.sniff(filter=filter, prn=self.pkt)
if __name__ == '__main__':
parse = argparse.ArgumentParser(
description='Sniff HTTP traffic for sections and alert'
)
parse.add_argument(
'--alertsection', type=str, required=True,
help='website section for alert (i.e. test.com/test or test.com)'
)
parse.add_argument(
'--alertsize', type=int, required=True,
help='number of hits within 2 minutes to generate alert'
)
args = parse.parse_args()
sniffer = Sniff(alertsection=args.alertsection, alertsize=args.alertsize)
sniffer()