Matteo Scandolo | a229eca | 2017-08-08 13:05:28 -0700 | [diff] [blame] | 1 | |
| 2 | # Copyright 2017-present Open Networking Foundation |
| 3 | # |
| 4 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | # you may not use this file except in compliance with the License. |
| 6 | # You may obtain a copy of the License at |
| 7 | # |
| 8 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | # |
| 10 | # Unless required by applicable law or agreed to in writing, software |
| 11 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | # See the License for the specific language governing permissions and |
| 14 | # limitations under the License. |
| 15 | |
| 16 | |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 17 | """ |
| 18 | Pcap file writer |
| 19 | """ |
| 20 | |
| 21 | import struct |
| 22 | |
| 23 | PcapHeader = struct.Struct("<LHHLLLL") |
| 24 | PcapPktHeader = struct.Struct("<LLLL") |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 25 | PPIPktHeader = struct.Struct("<BBHL") |
| 26 | PPIAggregateField = struct.Struct("<HHL") |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 27 | |
| 28 | class PcapWriter(object): |
| 29 | def __init__(self, filename): |
| 30 | """ |
| 31 | Open a pcap file |
| 32 | """ |
| 33 | self.stream = file(filename, 'w') |
| 34 | |
| 35 | self.stream.write(PcapHeader.pack( |
| 36 | 0xa1b2c3d4, # magic |
| 37 | 2, # major |
| 38 | 4, # minor |
| 39 | 0, # timezone offset |
| 40 | 0, # timezone accuracy |
| 41 | 65535, # snapshot length |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 42 | 192 # PPI linktype |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 43 | )) |
| 44 | |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 45 | def write(self, data, timestamp, port): |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 46 | """ |
| 47 | Write a packet to a pcap file |
| 48 | |
| 49 | 'data' should be a string containing the packet data. |
| 50 | 'timestamp' should be a float. |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 51 | 'port' should be an integer port number. |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 52 | """ |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 53 | ppi_len = PPIPktHeader.size + PPIAggregateField.size |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 54 | self.stream.write(PcapPktHeader.pack( |
| 55 | int(timestamp), # timestamp seconds |
| 56 | int((timestamp - int(timestamp)) * 10**6), # timestamp microseconds |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 57 | len(data) + ppi_len, # truncated length |
| 58 | len(data) + ppi_len # un-truncated length |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 59 | )) |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 60 | self.stream.write(PPIPktHeader.pack( |
| 61 | 0, # version |
| 62 | 0, # flags |
| 63 | ppi_len, # length |
| 64 | 1, # ethernet dlt |
| 65 | )) |
| 66 | self.stream.write(PPIAggregateField.pack(8, PPIAggregateField.size - 4, port)) |
Rich Lane | 360bcca | 2013-08-23 17:10:14 -0700 | [diff] [blame] | 67 | self.stream.write(data) |
| 68 | |
| 69 | def close(self): |
| 70 | self.stream.close() |
Rich Lane | a9e6442 | 2013-08-26 13:56:24 -0700 | [diff] [blame] | 71 | |
| 72 | if __name__ == "__main__": |
| 73 | import time |
| 74 | print("Writing test pcap to test.pcap") |
| 75 | pcap_writer = PcapWriter("test.pcap") |
| 76 | pcap_writer.write("\x00\x01\x02\x03\x04\x05\x00\x0a\x0b\x0c\x0d\x0e\x08\x00", time.time(), 42) |
| 77 | pcap_writer.close() |