pcapng.py 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. """
  2. Primaly refer:
  3. http://www.winpcap.org/ntar/draft/PCAP-DumpFileFormat.html
  4. TODO:
  5. * Writer class implementation.
  6. * Options getter/setter implementation.
  7. * Support nanosecond.
  8. Investigate the implementation to support multi interface.
  9. Limitation:
  10. Because the generally considered to only use wireshark, support header
  11. referenced to http://wiki.wireshark.org/Development/PcapNg
  12. Mostly the following limitations
  13. * Only a single section
  14. Support:
  15. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  16. | SHB v1.0 | Data |
  17. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  18. Not support:
  19. |<- 1st Section ->|<- 2nd Section ->| ... |
  20. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  21. | SHB v1.0 | Data | SHB v1.1 | Data | ... |
  22. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  23. Wireshark wiki written as "Capture file will have the following
  24. pcap-ng blocks: SHB, IDB, IDB, IDB, EPB, EPB, ..., ISB, ISB, ISB.".
  25. * SHB(Section Header Block)
  26. * IDB(Interface Description Block)
  27. * EPB(Enhanced Packet Block) <-- this is DUMP PACKET
  28. * ISB(Interface Statistics Block)
  29. Thus, created by assuming the following figure of block format:
  30. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  31. | SHB | IDB | IDB | EPB | EPB | ... | EPB | ISB | ISB |
  32. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  33. ( 'A`)< Only file reading...
  34. TODO: generic interface for different reader/writer
  35. """
  36. from pypacker import pypacker
  37. from pypacker import ppcap
  38. import struct
  39. PCAPNG_IDB = 0x00000001 # Interface Description Block
  40. # PCAPNG_PB = 0x00000002 # (obsolated) Packet Block
  41. PCAPNG_SPB = 0x00000003 # Simple Packet Block
  42. # PCAPNG_NRB = 0x00000004 # Name Resolution Block
  43. PCAPNG_ISB = 0x00000005 # Interface Statistics Block
  44. PCAPNG_EPB = 0x00000006 # Enhanced Packet Block
  45. PCAPNG_SHB = 0x0A0D0D0A # Section Header Block
  46. PCAPNG_VERSION_MAJOR = 1
  47. PCAPNG_VERSION_MINOR = 0
  48. BE_MAGIC = 0x1a2b3c4d
  49. LE_MAGIC = 0x4d3c2b1a
  50. OPT_ENDOFOPT = 0
  51. OPT_COMMENT = 1
  52. OPT_IDB_IF_NAME = 2
  53. OPT_IDB_IF_DESC = 3
  54. OPT_IDB_IF_V4ADDR = 4
  55. OPT_IDB_IF_V6ADDR = 5
  56. OPT_IDB_IF_MAC = 6
  57. OPT_IDB_IF_EUI = 7
  58. OPT_IDB_IF_SPEED = 8
  59. OPT_IDB_IF_TSRESOL = 9
  60. OPT_IDB_IF_TZONE = 10
  61. OPT_IDB_IF_FILTER = 11
  62. OPT_IDB_IF_OS = 12
  63. OPT_IDB_IF_FCSLEN = 13
  64. OPT_IDB_IF_TSOFFSET = 14
  65. OPT_ISB_STARTTIME = 2
  66. OPT_ISB_ENDTIME = 3
  67. OPT_ISB_IFRECV = 4
  68. OPT_ISB_IFDROP = 5
  69. OPT_ISB_FILTERACCEPT = 6
  70. OPT_ISB_OSDROP = 7
  71. OPT_ISB_USRDELIV = 8
  72. OPT_SHB_HARDWARE = 2
  73. OPT_SHB_OS = 3
  74. OPT_SHB_USERAPPL = 4
  75. IDB_OPTIONS = {
  76. 1: "opt_comment",
  77. 2: "if_name",
  78. 3: "if_description",
  79. 4: "if_IPv4addr",
  80. 5: "if_IPv6addr",
  81. 6: "if_MACaddr",
  82. 7: "if_EUIaddr",
  83. 8: "if_speed",
  84. 9: "if_tsresol",
  85. 10: "if_tzone",
  86. 11: "if_filter",
  87. 12: "if_os",
  88. 13: "if_fcslen",
  89. 14: "if_tsoffset",
  90. }
  91. ISB_OPTIONS = {
  92. 1: "opt_comment",
  93. 2: "isb_starttime",
  94. 3: "isb_endtime",
  95. 4: "isb_ifrecv",
  96. 5: "isb_ifdrop",
  97. 6: "isb_filteraccept",
  98. 7: "isb_osdrop",
  99. 8: "isb_usrdeliv",
  100. }
  101. SHB_OPTIONS = {
  102. 1: "opt_comment",
  103. 2: "shb_hardware",
  104. 3: "shb_os",
  105. 4: "shb_userappl",
  106. }
  107. def _32bit_alignment(offset, length):
  108. return (offset + length + 3) & 0xFFFC
  109. class OPT(pypacker.Packet):
  110. """General option format"""
  111. __hdr__ = (
  112. ("code", "H", 0),
  113. ("length", "H", 0),
  114. )
  115. class SHB(pypacker.Packet):
  116. """Section Header Block (mandatory)"""
  117. __hdr__ = (
  118. ("type", "I", PCAPNG_SHB),
  119. ("block_length", "I", 0),
  120. ("magic", "I", BE_MAGIC),
  121. ("v_major", "H", PCAPNG_VERSION_MAJOR),
  122. ("v_minor", "H", PCAPNG_VERSION_MINOR),
  123. ("section_length", "Q", 0),
  124. )
  125. class OPT(OPT):
  126. # TODO: getter and setter
  127. pass
  128. class SHB_LE(SHB):
  129. __byte_order__ = "<"
  130. class OPT(SHB.OPT):
  131. __byte_order__ = "<"
  132. class IDB(pypacker.Packet):
  133. """Interface Description Block (mandatory)"""
  134. __hdr__ = (
  135. ("type", "I", PCAPNG_IDB),
  136. ("block_length", "I", 0),
  137. ("linktype", "H", 0),
  138. ("reserved", "H", 0),
  139. ("snaplen", "I", 0),
  140. )
  141. class OPT(OPT):
  142. # TODO: getter and setter
  143. pass
  144. class IDB_LE(IDB):
  145. __byte_order__ = "<"
  146. class OPT(IDB.OPT):
  147. __byte_order__ = "<"
  148. class EPB(pypacker.Packet):
  149. """Enhanced Packet Block (optional)"""
  150. __hdr__ = (
  151. ("type", "I", PCAPNG_EPB),
  152. ("block_length", "I", 32),
  153. ("interface_id", "I", 0),
  154. ("ts_high", "I", 0),
  155. ("ts_low", "I", 0),
  156. ("cap_len", "I", 0),
  157. ("len", "I", 0),
  158. )
  159. class OPT(OPT):
  160. # TODO: getter and setter
  161. pass
  162. class EPB_LE(EPB):
  163. __byte_order__ = "<"
  164. class OPT(EPB.OPT):
  165. __byte_order__ = "<"
  166. class SPB(pypacker.Packet):
  167. """Simple Packet Block (optional)"""
  168. __hdr__ = (
  169. ("type", "I", PCAPNG_SPB),
  170. ("block_length", "I", 16),
  171. ("len", "I", 0),
  172. )
  173. class SPB_LE(SPB):
  174. __byte_order__ = "<"
  175. class ISB(pypacker.Packet):
  176. """Interface Statistics Block (optional)"""
  177. __hdr__ = (
  178. ("type", "I", PCAPNG_ISB),
  179. ("block_length", "I", 0),
  180. ("interface_id", "I", 1),
  181. ("ts_high", "I", 0),
  182. ("ts_low", "I", 0),
  183. )
  184. class OPT(OPT):
  185. # TODO: getter and setter
  186. pass
  187. class ISB_LE(ISB):
  188. __byte_order__ = "<"
  189. class OPT(ISB.OPT):
  190. __byte_order__ = "<"
  191. # TODO: Writer
  192. class Writer(object):
  193. def __init__(self):
  194. pass
  195. class Reader(object):
  196. def __init__(self, fileobj=None, filename=None, lowest_layer=None, filter=None, ts_conversion=True):
  197. self.idbs = []
  198. self.isbs = []
  199. self.__block_order__ = ""
  200. self._IDB = IDB
  201. self._EPB = EPB
  202. self._ISB = ISB
  203. self._SHB = SHB
  204. # handle source modes
  205. if fileobj is not None:
  206. self.__fh = fileobj
  207. elif filename is not None:
  208. self.__fh = open(filename, "rb")
  209. else:
  210. raise Exception("No fileobject and no filename given..nothing to read!!!")
  211. """
  212. How to parse:
  213. |--> Parse1 |--> iter | Parse2 <--|
  214. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  215. | SHB | IDB | IDB | EPB | EPB | ... | EPB | ISB | ISB |
  216. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  217. 1. Parse from head and stop at the EPB pointer.
  218. 2. Parse from tail and stop at the EPB pointer
  219. or not supported header.
  220. """
  221. # Parse1
  222. while 1:
  223. buf = self.__fh.read(8)
  224. block_type, block_length = struct.unpack(self.__block_order__ + "2I", buf)
  225. if block_type == PCAPNG_SHB:
  226. buf = buf + self.__fh.read(block_length - len(buf))
  227. self.shb = self._SHB(buf)
  228. # Endian is decided magic in SHB.
  229. if self.shb.magic == LE_MAGIC:
  230. self.__to_le()
  231. self.shb = self._SHB(buf)
  232. self.shb.opts = self.__unpack_opt(buf, self._SHB)
  233. elif block_type == PCAPNG_IDB:
  234. buf = buf + self.__fh.read(block_length - len(buf))
  235. _idb = self._IDB(buf)
  236. _idb.opts = self.__unpack_opt(buf, self._IDB)
  237. self.idbs.append(_idb)
  238. elif block_type == PCAPNG_EPB:
  239. self.__iter_pos = self.__fh.tell() - 8
  240. self.__next__ = self._next_bytes_conversion
  241. # TODO: Support nanosecond
  242. self.__resolution_factor = 1000000.0
  243. break
  244. else:
  245. break
  246. # Parse2
  247. """
  248. 1. Read Block Total Length from tail.
  249. 2. Seek reverse the Block Total Length.
  250. 3. Same Parse1.
  251. 0 1 2 3
  252. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  253. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <---2
  254. | Block Type | 3
  255. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
  256. | Block Total Length | V
  257. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  258. / Block Body /
  259. / /* variable length, aligned to 32 bits */ /
  260. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  261. | Block Total Length |
  262. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ <---1
  263. """
  264. tail_offset = 0
  265. while 1:
  266. self.__fh.seek(-1 * (4 + tail_offset), 2)
  267. block_length = struct.unpack(self.__block_order__ + "I", self.__fh.read(4))[0]
  268. self.__fh.seek(-1 * block_length, 1)
  269. buf = self.__fh.read(8)
  270. block_type, block_length = struct.unpack(self.__block_order__ + "2I", buf)
  271. tail_offset += block_length
  272. if block_type == PCAPNG_ISB:
  273. buf = buf + self.__fh.read(block_length - len(buf))
  274. _isb = self._ISB(buf)
  275. _isb.opts = self.__unpack_opt(buf, self._ISB)
  276. self.isbs.append(_isb)
  277. else:
  278. break
  279. def __to_le(self):
  280. self.__block_order__ = "<"
  281. self._IDB = IDB_LE
  282. self._EPB = EPB_LE
  283. self._ISB = ISB_LE
  284. self._SHB = SHB_LE
  285. def __unpack_opt(self, buf, BLOCK):
  286. offset = BLOCK._hdr_fmt.size
  287. opts = []
  288. while 1:
  289. opt_hdr = buf[offset:offset + OPT._hdr_fmt.size]
  290. if not opt_hdr:
  291. break
  292. code, length = struct.unpack(self.__block_order__ + "2H", opt_hdr)
  293. opt = BLOCK.OPT(buf[offset:offset + OPT._hdr_fmt.size + length])
  294. if opt.code == OPT_ENDOFOPT:
  295. break
  296. opts.append(opt)
  297. offset = _32bit_alignment(offset + OPT._hdr_fmt.size, length)
  298. return opts
  299. def _next_bytes_conversion(self):
  300. """
  301. Standard __next__ implementation. Needs to be a sepearte method to be called by producer.
  302. return -- (timestamp_microseconds, Enhanced_Packet_Block) for pcap-reader.
  303. Access DUMP DATA: Enhanced_Packet_Block.data
  304. """
  305. buf = self.__fh.read(8)
  306. if not buf:
  307. raise StopIteration
  308. block_type, block_length = struct.unpack(self.__block_order__ + "2I", buf)
  309. if not block_type == PCAPNG_EPB:
  310. raise StopIteration
  311. buf = buf + self.__fh.read(block_length - len(buf))
  312. _epb = self._EPB(buf)
  313. _epb.opts = self.__unpack_opt(buf, self._EPB)
  314. return (((_epb.ts_high << 32) + _epb.ts_low) / self.__resolution_factor, _epb)
  315. def __iter__(self):
  316. """
  317. return -- (timestamp, Enhanced Packet Block) for pcap-reader depending on configuration.
  318. """
  319. self.__fh.seek(self.__iter_pos)
  320. while True:
  321. try:
  322. yield self.__next__()
  323. except StopIteration:
  324. break