10 log
= logging
.getLogger()
12 class LoggerError(Exception):
16 "Write some packets to a pcap file"
17 def __init__(self
, path
):
23 sigfigs
= 0 # Get this from the reconciliator? Tricky because there
24 # are significant figures relative to real time and
25 # significant figures relative to other packes. we really
26 # should ask each client's NTP for the clock jitter...
28 linktype
= 1 # DLT_ETHER
30 hdr
= struct
.pack("@IHHIIII", magic
, majv
, minv
, timewarp
, sigfigs
,
32 self
.file = open(path
, "w")
35 def write(self
, packet
, timestamp
):
37 usec
= int((timestamp
- sec
)*1000000)
38 # Two fake MAC addresses followed by 0x0800 for an IPv4 packet
39 ethhdr
= "\xaa" * 6 + "\xbb" * 6 + "\x08\x00"
40 length
= len(packet
) + len(ethhdr
)
41 pkthdr
= struct
.pack("@IIII", sec
, usec
, length
, length
)
42 self
.file.write(pkthdr
)
43 self
.file.write(ethhdr
)
44 self
.file.write(packet
)
49 This device organises the elaborate switzerland logging structure, which
50 is a standard log containing references to a directory of incident-specific
54 # XXXXXX fix this default before release
55 def __init__(self
, log_dir
):
56 self
.lock
= threading
.RLock()
57 self
.make_or_check_directory(log_dir
, "log dir")
58 #ts = self.timestamp()
59 self
.log_dir
= log_dir
60 # XXX do not expect this to be secure if log_dir is world writeable
61 # on a multi-user system
62 self
.make_or_check_directory(self
.log_dir
, "pcap log dir")
64 def make_or_check_directory(self
, path
, alias
="directory"):
69 assert not os
.path
.islink(path
), alias
+ path
+ " should not be a symlink!"
70 assert os
.path
.isdir(path
), "cannot create " + alias
+ path
+ ":\n"+`e`
72 def new_flow(self
, flow
, id):
73 log
.info("New bidirectional flow %d : %s\n" % (id,`flow`
))
75 def timestamp(self
, t
=None):
78 frac
= `t
- int(t
)`
[2:5]
79 return time
.strftime("%Y%m%d%H%M%S", time
.localtime(t
)) + frac
81 def log_forged_in(self
, context
, id):
84 in_path
, out_path
= self
.__gen
_filenames
(context
)
85 pcap
= PcapWriter(in_path
)
86 self
.log_to_pcap(context
, pcap
)
92 def log_forged_out(self
, context
, out_path
):
95 pcap
= PcapWriter(out_path
)
96 self
.log_to_pcap(context
, pcap
)
101 def __gen_filenames(self
, context
):
102 "Determine the filenames for the inbound and outbound logs"
104 ts
= self
.timestamp(context
[0][0])
105 filename1
= ts
+ "-in.pcap"
106 filename2
= ts
+ "-out.pcap"
107 path1
= self
.log_dir
+ os
.path
.sep
+ filename1
108 path2
= self
.log_dir
+ os
.path
.sep
+ filename2
110 while os
.path
.exists(path1
):
111 # This inbound filename has already been used; find another
112 filename1
= ts
+ "-" + `n`
+ "-in.pcap"
113 filename2
= ts
+ "-" + `n`
+ "-out.pcap"
114 path1
= self
.log_dir
+ os
.path
.sep
+ filename1
115 path2
= self
.log_dir
+ os
.path
.sep
+ filename2
117 log
.info("Recording inbound modified packets & context in %s\n" % path1
)
121 def log_to_pcap(self
, packets
, pcap_log
):
122 ## consider adding linktype= to this:
124 for timestamp
, hash, packet
in packets
:
125 # be careful what we feed to scapy!
126 if type(packet
) != types
.StringType
:
127 raise LoggerError
, "Packet data %s is not a string!\n" % packet
130 pcap_log
.write(packet
,timestamp
)
132 log
.error("Tripped on %s", `pcap_log`
)
134 pcap_log
.file.flush()
136 if __name__
== "__main__":
137 l
= PcapLogger("/var/log/switzerland/")
138 logging
.basicConfig()
139 log
= logging
.getLogger()
140 log
.setLevel(logging
.DEBUG
)
141 l
.log_forged_in([(2,"0x0x", "yjfoisjfoidsjfseehayee"), (3,"0y0y", "yejsidofjsoidhooyee")], 1)