]> git.somenet.org - pub/jan/netsec2.git/blob - autocorr.py
GITOLITE.txt
[pub/jan/netsec2.git] / autocorr.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 import sys
5 from csv import reader, Sniffer
6 from os.path import exists
7 from argparse import ArgumentParser
8 from copy import copy
9
10 from rpy2.robjects.packages import importr
11 from rpy2.robjects.vectors import DataFrame, FloatVector
12
13
14 def _convert_to_dataframe(x):
15     """ Convert Python list of integers to R data frame. """
16     tmp = dict()
17     y = copy(x)
18     y = filter(None, y)
19     tmp['y'] = FloatVector(y)
20     return DataFrame(tmp)
21
22
23 def autocorrelation(f_in, field, source_ip, source_port, destination_ip,
24                     destination_port):
25     values = []
26
27     with open(f_in, 'r') as f:
28         csv = reader(f, delimiter=',', quotechar='"')
29
30         # Make sure that CSV file includes a header.
31         if not Sniffer().has_header(f.read(8192)):
32             sys.stderr.write("ERROR: CSV file has no header!\n")
33             sys.exit(2)
34         f.seek(0)
35
36         # Parse header of the input file
37         header = csv.next()
38         try:
39             feat_field = header.index(field)
40         except ValueError:
41             sys.stderr.write("ERROR: Cannot find column '%s' " % str(field) +
42                              "in CSV file!\n")
43             sys.stderr.write("These are the values that were found: " +
44                              "%s\n" % ", ".join(header))
45             sys.exit(2)
46
47         # Find field for source IP
48         if source_ip:
49             try:
50                 source_field = header.index("Source")
51             except ValueError:
52                 sys.stderr.write("ERROR: Cannot find column 'Source' " +
53                                  "in CSV file!\n")
54                 sys.stderr.write("These are the values that were found: " +
55                                  "%s\n" % ", ".join(header))
56                 sys.exit(2)
57
58         # Find field for source port
59         if source_port:
60             try:
61                 source_p_field = header.index("Source port")
62             except ValueError:
63                 sys.stderr.write("ERROR: Cannot find column 'Source port' " +
64                                  "in CSV file!\n")
65                 sys.stderr.write("These are the values that were found: " +
66                                  "%s\n" % ", ".join(header))
67                 sys.exit(2)
68
69         # Find field for destination port
70         if destination_port:
71             try:
72                 dest_p_field = header.index("Destination port")
73             except ValueError:
74                 sys.stderr.write("ERROR: Cannot find column " +
75                                  "'Destination port' in CSV file!\n")
76                 sys.stderr.write("These are the values that were found: " +
77                                  "%s\n" % ", ".join(header))
78                 sys.exit(2)
79
80         # Find field for destination IP
81         if destination_ip:
82             try:
83                 dest_field = header.index("Destination")
84             except ValueError:
85                 sys.stderr.write("ERROR: Cannot find column 'Destination' " +
86                                  "in CSV file!\n")
87                 sys.stderr.write("These are the values that were found: " +
88                                  "%s\n" % ", ".join(header))
89                 sys.exit(2)
90
91         # Parse CSV and add values
92         for row in csv:
93             if source_ip:
94                 if row[source_field] != source_ip:
95                     continue
96             if source_port:
97                 if row[source_p_field] != source_port:
98                     continue
99             if destination_ip:
100                 if row[dest_field] != destination_ip:
101                     continue
102             if destination_port:
103                 if row[dest_p_field] != destination_port:
104                     continue
105             values.append(row[feat_field])
106
107     if len(values) == 0:
108         print "ERROR: No values match your filtering criteria."
109         return
110     
111     if len(set(values)) == 1:
112         print "All values are identical (perfect self-correlation)."
113         return
114
115     r_stats = importr('stats')
116     acf = r_stats.acf(_convert_to_dataframe(values), plot=False)
117     autocorr = acf[0]
118     lag = acf[3]
119
120     autocorr_sum = 0
121     index = 0
122     for i in lag:
123         # ignore autocorrelation 0
124         if index == 0:
125             index += 1
126             continue
127         # we want only absolute values
128         autocorr_sum += abs(autocorr[index])
129         index += 1
130     # make sure we do not try to divide by zero
131     if len(lag) <= 1:
132         print "None"
133     else:
134         print autocorr_sum / (len(lag) - 1)
135
136
137 def _main():
138     # Argument handling
139     parser = ArgumentParser(description="Calculate sum of autocorrelation.",
140                             epilog='Example: %s --input ' % sys.argv[0] +
141                                     'file.csv --field TTL ' +
142                                     '--source-ip \\ "192.168.0.1" ' +
143                                     '--destination-port 80')
144     parser.add_argument("--input", type=str, required=True,
145                         help="Input CSV file.")
146     parser.add_argument("--field", type=str, required=True,
147                         help="Field for which autocorrelation is calculated.")
148     parser.add_argument("--source-ip", type=str, required=False,
149                         help="Restrict to a specific source IP address.")
150     parser.add_argument("--destination-ip", type=str, required=False,
151                         help="Restrict to a specific destination IP address.")
152     parser.add_argument("--source-port", type=str, required=False,
153                         help="Restrict to a specific source port.")
154     parser.add_argument("--destination-port", type=str, required=False,
155                         help="Restrict to a specific destination port.")
156
157     args = parser.parse_args()
158     if not exists(args.input):
159         sys.stderr.write("ERROR: Input file '%s' " % args.input +
160                          "does not exist!\n")
161         sys.exit(2)
162
163     autocorrelation(args.input, args.field, args.source_ip, args.source_port,
164                     args.destination_ip, args.destination_port)
165
166
167 if __name__ == '__main__':
168     _main()