Changeset 872:fa66f778ed74
- Timestamp:
- 08/16/08 14:37:28
(5 months ago)
- Author:
- Phil <phil@secdev.org>
- Message:
Extracted raw pcap file reader/writer from PcapReader/PcapWriter?
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r866 |
r872 |
|
| 11 | 11 | from arch import * |
|---|
| 12 | 12 | from error import log_runtime |
|---|
| | 13 | from base_classes import BasePacketList |
|---|
| 13 | 14 | |
|---|
| 14 | 15 | |
|---|
| … | … | |
| 454 | 455 | return PcapReader(filename).read_all(count=count) |
|---|
| 455 | 456 | |
|---|
| 456 | | class PcapReader: |
|---|
| 457 | | """A stateful pcap reader |
|---|
| 458 | | |
|---|
| 459 | | Based entirely on scapy.rdpcap(), this class allows for packets |
|---|
| 460 | | to be dispatched without having to be loaded into memory all at |
|---|
| 461 | | once |
|---|
| 462 | | """ |
|---|
| | 457 | |
|---|
| | 458 | |
|---|
| | 459 | class RawPcapReader: |
|---|
| | 460 | """A stateful pcap reader. Each packet is returned as a string""" |
|---|
| 463 | 461 | |
|---|
| 464 | 462 | def __init__(self, filename): |
|---|
| … | … | |
| 480 | 478 | raise RuntimeWarning, "Invalid pcap file (too short)" |
|---|
| 481 | 479 | vermaj,vermin,tz,sig,snaplen,linktype = struct.unpack(self.endian+"HHIIII",hdr) |
|---|
| 482 | | self.LLcls = conf.l2types.get(linktype, Raw) |
|---|
| 483 | | if self.LLcls == Raw: |
|---|
| 484 | | warning("PcapReader: unkonwon LL type [%i]/[%#x]. Using Raw packets" % (linktype,linktype)) |
|---|
| | 480 | |
|---|
| | 481 | self.linktype = linktype |
|---|
| | 482 | |
|---|
| | 483 | |
|---|
| 485 | 484 | |
|---|
| 486 | 485 | def __iter__(self): |
|---|
| … | … | |
| 488 | 487 | |
|---|
| 489 | 488 | def next(self): |
|---|
| 490 | | """impliment the iterator protocol on a set of packets in a |
|---|
| 491 | | pcap file |
|---|
| 492 | | """ |
|---|
| | 489 | """impliment the iterator protocol on a set of packets in a pcap file""" |
|---|
| 493 | 490 | pkt = self.read_packet() |
|---|
| 494 | 491 | if pkt == None: |
|---|
| … | … | |
| 505 | 502 | if len(hdr) < 16: |
|---|
| 506 | 503 | return None |
|---|
| 507 | | sec,usec,caplen,olen = struct.unpack(self.endian+"IIII", hdr) |
|---|
| | 504 | sec,usec,caplen,wirelen = struct.unpack(self.endian+"IIII", hdr) |
|---|
| 508 | 505 | s = self.f.read(caplen) |
|---|
| | 506 | return s,(sec,usec,wirelen) # caplen = len(s) |
|---|
| | 507 | |
|---|
| | 508 | |
|---|
| | 509 | def dispatch(self, callback): |
|---|
| | 510 | """call the specified callback routine for each packet read |
|---|
| | 511 | |
|---|
| | 512 | This is just a convienience function for the main loop |
|---|
| | 513 | that allows for easy launching of packet processing in a |
|---|
| | 514 | thread. |
|---|
| | 515 | """ |
|---|
| | 516 | for p in self: |
|---|
| | 517 | callback(p) |
|---|
| | 518 | |
|---|
| | 519 | def read_all(self,count=-1): |
|---|
| | 520 | """return a list of all packets in the pcap file |
|---|
| | 521 | """ |
|---|
| | 522 | res=[] |
|---|
| | 523 | while count != 0: |
|---|
| | 524 | count -= 1 |
|---|
| | 525 | p = self.read_packet() |
|---|
| | 526 | if p is None: |
|---|
| | 527 | break |
|---|
| | 528 | res.append(p) |
|---|
| | 529 | return res |
|---|
| | 530 | |
|---|
| | 531 | def recv(self, size): |
|---|
| | 532 | """ Emulate a socket |
|---|
| | 533 | """ |
|---|
| | 534 | return self.read_packet()[0] |
|---|
| | 535 | |
|---|
| | 536 | def fileno(self): |
|---|
| | 537 | return self.f.fileno() |
|---|
| | 538 | |
|---|
| | 539 | def close(self): |
|---|
| | 540 | return self.f.close() |
|---|
| | 541 | |
|---|
| | 542 | |
|---|
| | 543 | |
|---|
| | 544 | class PcapReader(RawPcapReader): |
|---|
| | 545 | def __init__(self, filename): |
|---|
| | 546 | RawPcapReader.__init__(self, filename) |
|---|
| | 547 | try: |
|---|
| | 548 | self.LLcls = conf.l2types[self.linktype] |
|---|
| | 549 | except KeyError: |
|---|
| | 550 | warning("PcapReader: unknown LL type [%i]/[%#x]. Using Raw packets" % (self.linktype,self.linktype)) |
|---|
| | 551 | self.LLcls = Raw |
|---|
| | 552 | def read_packet(self): |
|---|
| | 553 | rp = RawPcapReader.read_packet(self) |
|---|
| | 554 | if rp is None: |
|---|
| | 555 | return None |
|---|
| | 556 | s,(sec,usec,wirelen) = rp |
|---|
| | 557 | |
|---|
| 509 | 558 | try: |
|---|
| 510 | 559 | p = self.LLcls(s) |
|---|
| … | … | |
| 517 | 566 | p.time = sec+0.000001*usec |
|---|
| 518 | 567 | return p |
|---|
| 519 | | |
|---|
| 520 | | def dispatch(self, callback): |
|---|
| 521 | | """call the specified callback routine for each packet read |
|---|
| 522 | | |
|---|
| 523 | | This is just a convienience function for the main loop |
|---|
| 524 | | that allows for easy launching of packet processing in a |
|---|
| 525 | | thread. |
|---|
| 526 | | """ |
|---|
| 527 | | p = self.read_packet() |
|---|
| 528 | | while p != None: |
|---|
| 529 | | callback(p) |
|---|
| 530 | | p = self.read_packet() |
|---|
| 531 | | |
|---|
| 532 | 568 | def read_all(self,count=-1): |
|---|
| 533 | | """return a list of all packets in the pcap file |
|---|
| 534 | | """ |
|---|
| 535 | | res=[] |
|---|
| 536 | | while count != 0: |
|---|
| 537 | | count -= 1 |
|---|
| 538 | | p = self.read_packet() |
|---|
| 539 | | if p is None: |
|---|
| 540 | | break |
|---|
| 541 | | res.append(p) |
|---|
| | 569 | res = RawPcapReader.read_all(self, count) |
|---|
| 542 | 570 | return PacketList(res,name = os.path.basename(self.filename)) |
|---|
| 543 | | |
|---|
| 544 | 571 | def recv(self, size): |
|---|
| 545 | | """ Emulate a socket |
|---|
| 546 | | """ |
|---|
| 547 | 572 | return self.read_packet() |
|---|
| 548 | | |
|---|
| 549 | | def fileno(self): |
|---|
| 550 | | return self.f.fileno() |
|---|
| 551 | | |
|---|
| 552 | | def close(self): |
|---|
| 553 | | return self.f.close() |
|---|
| 554 | | |
|---|
| 555 | | |
|---|
| 556 | | |
|---|
| 557 | | class PcapWriter: |
|---|
| | 573 | |
|---|
| | 574 | |
|---|
| | 575 | |
|---|
| | 576 | class RawPcapWriter: |
|---|
| 558 | 577 | """A stream PCAP writer with more control than wrpcap()""" |
|---|
| 559 | 578 | def __init__(self, filename, linktype=None, gz=False, endianness="", append=False, sync=False): |
|---|
| … | … | |
| 580 | 599 | self.f = [open,gzip.open][gz](filename,append and "ab" or "wb", gz and 9 or bufsz) |
|---|
| 581 | 600 | |
|---|
| 582 | | |
|---|
| 583 | | |
|---|
| 584 | 601 | def fileno(self): |
|---|
| 585 | 602 | return self.f.fileno() |
|---|
| … | … | |
| 587 | 604 | def _write_header(self, pkt): |
|---|
| 588 | 605 | self.header_present=1 |
|---|
| 589 | | |
|---|
| 590 | | if self.linktype == None: |
|---|
| 591 | | if type(pkt) is list or type(pkt) is tuple: |
|---|
| 592 | | pkt = pkt[0] |
|---|
| 593 | | self.linktype = conf.l2types.get(pkt.__class__,1) |
|---|
| 594 | 606 | |
|---|
| 595 | 607 | if self.append: |
|---|
| … | … | |
| 613 | 625 | if not self.header_present: |
|---|
| 614 | 626 | self._write_header(pkt) |
|---|
| 615 | | for p in pkt: |
|---|
| 616 | | self._write_packet(p) |
|---|
| 617 | | |
|---|
| 618 | | def _write_packet(self, packet): |
|---|
| | 627 | if type(pkt) is str: |
|---|
| | 628 | self._write_packet(pkt) |
|---|
| | 629 | else: |
|---|
| | 630 | for p in pkt: |
|---|
| | 631 | self._write_packet(p) |
|---|
| | 632 | |
|---|
| | 633 | def _write_packet(self, packet, sec=None, usec=None, caplen=None, wirelen=None): |
|---|
| 619 | 634 | """writes a single packet to the pcap file |
|---|
| 620 | 635 | """ |
|---|
| 621 | | s = str(packet) |
|---|
| 622 | | l = len(s) |
|---|
| 623 | | sec = int(packet.time) |
|---|
| 624 | | usec = int((packet.time-sec)*1000000) |
|---|
| 625 | | self.f.write(struct.pack(self.endian+"IIII", sec, usec, l, l)) |
|---|
| 626 | | self.f.write(s) |
|---|
| | 636 | if caplen is None: |
|---|
| | 637 | caplen = len(packet) |
|---|
| | 638 | if wirelen is None: |
|---|
| | 639 | wirelen = caplen |
|---|
| | 640 | if sec is None or usec is None: |
|---|
| | 641 | t=time.time() |
|---|
| | 642 | it = int(t) |
|---|
| | 643 | if sec is None: |
|---|
| | 644 | sec = it |
|---|
| | 645 | if usec is None: |
|---|
| | 646 | usec = int((t-it)*1000000) |
|---|
| | 647 | self.f.write(struct.pack(self.endian+"IIII", sec, usec, caplen, wirelen)) |
|---|
| | 648 | self.f.write(packet) |
|---|
| 627 | 649 | if self.gz and self.sync: |
|---|
| 628 | 650 | self.f.flush() |
|---|
| … | … | |
| 633 | 655 | return self.f.close() |
|---|
| 634 | 656 | |
|---|
| | 657 | class PcapWriter(RawPcapWriter): |
|---|
| | 658 | def _write_header(self, pkt): |
|---|
| | 659 | if self.linktype == None: |
|---|
| | 660 | if type(pkt) is list or type(pkt) is tuple or isinstance(pkt,BasePacketList): |
|---|
| | 661 | pkt = pkt[0] |
|---|
| | 662 | try: |
|---|
| | 663 | self.linktype = conf.l2types[pkt.__class__] |
|---|
| | 664 | except KeyError: |
|---|
| | 665 | warning("PcapWriter: unknown LL type for %s. Using type 1 (Ethernet)" % pkt.__class__.__name__) |
|---|
| | 666 | self.linktype = 1 |
|---|
| | 667 | RawPcapWriter._write_header(self, pkt) |
|---|
| | 668 | |
|---|
| | 669 | def _write_packet(self, packet): |
|---|
| | 670 | sec = int(packet.time) |
|---|
| | 671 | usec = int((packet.time-sec)*1000000) |
|---|
| | 672 | s = str(packet) |
|---|
| | 673 | caplen = len(s) |
|---|
| | 674 | RawPcapWriter._write_packet(self, s, sec, usec, caplen, caplen) |
|---|
| | 675 | |
|---|
| 635 | 676 | |
|---|
| 636 | 677 | re_extract_hexcap = re.compile("^(0x[0-9a-fA-F]{2,}[ :\t]|(0x)?[0-9a-fA-F]{2,}:|(0x)?[0-9a-fA-F]{3,}[: \t]|) *(([0-9a-fA-F]{2} {,2}){,16})") |
|---|