-
Notifications
You must be signed in to change notification settings - Fork 0
/
logtag.py
170 lines (129 loc) · 4.15 KB
/
logtag.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import re, sys, os
from lookup import protocol_num, num_protocol
class ParseError(Exception):
def __init__(self, line_value, msg, line_num = None, curr_file = None):
self.line_value = line_value
self.msg = msg
self.line_num = line_num
self.curr_file = curr_file
message = f"Error parsing \n\t{line_value}"
if line_num != None:
message += f"at line {line_num}, "
if curr_file != None:
message += f"in {curr_file}: "
message += msg
super().__init__(message)
def add_tag(tag_table, tagline):
parts = re.split(r'\s*,\s*', tagline.strip())
if len(parts) != 3:
return tag_table
port, prot, tag = parts
if not re.match(r'\d+$', port):
raise ParseError(tagline, f"{port} is not a valid port number")
port = int(port)
protnum = protocol_num(prot.upper())
if protnum == -1:
raise ParseError(tagline, f"{prot} is not a valid protocol")
key = (port, protnum)
if key in tag_table:
tag_table[key].add(tag)
else:
tag_table[key] = [tag]
return tag_table
def parse_log_line(logline):
columns = re.split(r'\s+', logline.strip())
dstport = columns[6]
if not re.match(r'\d+$', dstport):
raise ParseError(logline, f'{dstport} is not a valid port number')
else:
dstport = int(dstport)
protocol = columns[7]
if not re.match(r'\d+$', protocol):
raise ParseError(logline, f'{protocol} is not a valid protocol number')
else:
protocol = int(protocol)
return (dstport, protocol)
def tag_log(tag_counts, dest_counts, tag_table, log_entry):
if log_entry in tag_table:
for tag in tag_table[log_entry]:
if tag in tag_counts:
tag_counts[tag] += 1
else:
tag_counts[tag] = 1
else:
if "Untagged" in tag_counts:
tag_counts["Untagged"] += 1
else:
tag_counts["Untagged"] = 1
if log_entry in dest_counts:
dest_counts[log_entry] += 1
else:
dest_counts[log_entry] = 1
def make_tag_table(tag_file):
with open(tag_file, 'r') as tagf:
tf = enumerate(tagf)
out = {}
next(tf) # skip headers
for linenum, tagline in tf:
try:
add_tag(out, tagline)
except ParseError as e:
raise ParseError(e.line_value, e.msg, linenum, tag_file)
return out
def process_logfile(tag_table, log_file):
with open(log_file, 'r') as logf:
lf = enumerate(logf)
tag_counts = {}
dest_counts = {}
for linenum, logline in lf:
try:
dest = parse_log_line(logline)
tag_log(tag_counts, dest_counts, tag_table, dest)
except ParseError as e:
raise ParseError(e.line_value, e.msg, linenum, log_file)
return tag_counts, dest_counts
def pushline(dest_file, string):
dest_file.write(string + "\n")
def tag_res_str(tag_counts, tag):
if tag in tag_counts:
return f"{tag},{tag_counts[tag]}"
else:
return f"{tag},0"
def print_tags(tag_counts, of):
# Set up our tags in alphebetical order, but with Untagged last
tags = list(tag_counts.keys())
tags.remove("Untagged")
tags = list(tags)
tags.sort()
tags.append("Untagged")
pushline(of, "Tag Counts:")
pushline(of, "Tag,Count")
for tag in tags:
pushline(of, tag_res_str(tag_counts, tag))
def print_dests(dest_counts, of):
dests = list(dest_counts.keys())
dests.sort() # should do by port than protocol, as desired
pushline(of, "Port/Protocol Combination Counts:")
pushline(of, "Port,Protocol,Count")
for port, prot in dests:
count = dest_counts[(port, prot)]
prot = num_protocol(prot)
pushline(of, f"{port},{prot},{count}")
if __name__ == '__main__':
l = len(sys.argv)
if l != 4:
print(f"Error: logtag.py expects 3 arguments, got {l - 1}", file=sys.stderr)
exit(1)
# Error message on these two should be clear if they don't exist
tag_file = sys.argv[1]
log_file = sys.argv[2]
out_file = sys.argv[3]
tag_table = make_tag_table(tag_file)
tcounts, dcounts = process_logfile(tag_table, log_file)
if os.path.isfile(out_file):
print(f"Error: {out_file} already exists! Logtag will not clobber existing results.", file=sys.stderr)
exit(1)
with open(out_file, 'a') as of:
print_tags(tcounts, of)
pushline(of, "")
print_dests(dcounts, of)