Overview
For one, jNetStream SDK is made up of several components which are reffered to as "frameworks". Capture Framework is very important as this is the part of the overal jNetStream API that allows you to capture packets. You can open capture files which store packet data in files. You can grab packets directly from live network by snooping on a network interface. You can also just create packets yourself right in memory and make it look like they came from a file or some place.
In this section you will find several topics related to Capture Framework and lots of related examples.
The basics
The framework is made up of a number of java packages which all begin with jnetstream.capture top level package. The main way you access the package is through a set of static factory methods found in the class jnetstream.capture.Captures. You will use these static methods a lot.
Here is what the Capture Framework can do for you:
- capture live packets from a network interface - see
Captures.openLive - open capture files read them and modify them - see
Captures.openFile, Captures.newFile, FileCapture, PacketIterator, RecordIterator, RawIteratoralso contains a set of indexers which present the file as index based set of packets, records or even raw buffers.PacketIndexer, RecordIndexer and RawIndexer - open standard IO streams and uni-directional java.nio.channels. With input streams you can open compressed or encrypted files. See
Captures.newInput, Captures.newOutput, InputIterator
There are 2 basic steps to working with the capture framework.
Step #1 - aquire a capture
The first thing to do is to aquire a capture. A capture is a source of packets. All types of captures described below, all implement a common interface jnetstream.capture.Capture . This interface provides basic access to some of the common properties between the different types of captures possible.
The capture can be a LiveCapture which taps a network interface and grabs live packets from it. You work with LivePacket object which are a subclass of CapturePacket
Another type of capture is FileCapture which opens up a file with stored packets in it and makes the contents available to you. You work with mutable FilePacket objects which are a subclass of CapturePacket, Record objects which are the records that make up the capture files or with raw ByteBuffer objects.
There is also the InputCapture which is a specialized and limited version of the FileCapture. InputCapture allows you to work with sigle direction input sources such as standard java InputStream or ReadableByteChannel. There are no mutable methods, ones that modify the content, since streams and the ReadableByteChannel are readonly and can not be modified. Therefore you can only read the packets. You also can't rewind with seek operations as you will see below. You work with readonly FilePacket objects which are a subclass of CapturePacket, Record objects which are the records that make up the capture files or with raw ByteBuffer objects.
There is the OutputCapture which only allows 1 method which is add. Another words you can only add packets which are formatted into proper records and serialized. Output from this type capture is suitable to be stored in a file and then re-opened with normal Captures.openFile call. You work with Packet, Record or ByteBuffer objects to send tot he output.
Lastly there is the PacketInputStream and PacketOutputStream. These are not technically a captures, as they don't implement the main Capture interface which all other types of captures do, but they are included in the Capture Framework. They work exactly how you'd expect an InputStream and OutputStream objects to work. You setup a PacketOutputStream you write packets to it using PacketOutputStream.writePacket(Packet) call and then somewhere on the other end you attach a PacketInputStream and use its PacketInputStream.readPacket(): Packet to read the packat back into reality. The objects you work with here are DeserializedPacket objects.
Step #2 - use iterators or indexers to work with the capture
Once you aquire a capture, through the use of one of the Captures factory methods, you will notice that there isn't much that you can do directly with the Capture or one of its sub-interfaces returned to you. All the work is done by iterators and indexers.
You aquire an interator or indexer from your active capture through the use of Capture.getPacketIterator or one of the sub-interfaces of Capture. The Capture interface only allows you to get a PacketIterator or a Iterator<CapturePacket>. This is because at this level of the API you can only reliably assume to iterate over a sequence of packets from a generic capture source. All capture sessions are designed to return packets. So this is the common demoninator accross all types of capture sessions. If you want more, you have to work with something more specific such as FileCapture instead of the basic Capture interface.
Here is how this works. All factory methods return the some kind of subclassed interface of Capture. For example Captures.openFile(File): FileCapture returns a FileCapture object which is a sub-interface of Capture. You could choose to do this:
FileCapture capture = Captures.openFile(new File("file.pcap"));
// instead of
Capture capture = Captures.openFile(new File("file.pcap"));
Both these forms are valid captures, you will find that working with FileCapture provides many more ways of working with a capture file.
You can even go a step further if you know the type of file you are opening, by going all the way with:
PcapFile capture = Captures.openFile(PcapFile.class, new File("file.pcap"));
Now when you work with PcapFile which subclasses FileCapture which is a subclass of Capture you have now access to all the possible features, record types and properties of a LibPCAP based file. You now work with PcapPacket and PcapRecord objects instead of more generic FilePacket and Record ones. These give you access to everything that Pcap file format has to offer.
Anyway, iterators keep track of the position, of where they are in a capture, may that be a file, live network captures or reading a stream, allow you to do things like add new packets at the current position of the iterator, search for records at certain starting positions if the capture allows this type of operation, removing things, replacing, resizing, swaping and of course chaning its content such as poking in a new value into a record's header that you just read from a file.
Indexers are currently only allowed by FileCapture objects, that is for file based captures, as indexing requires random access to the capture data and only files currently allow that. Indexers allow you to do everything that an interator does such as add, remove, retain, swap, repalce, resize any record within the file, but they don't keep track of a current position. Actually they keep track of the position of every record within the capture file. You access records and packets through use of a simple index. You say give me packet at index 100 and the indexer figures out exactly where it resides in the file and gets the data for you. So if you want to add or remove a packet form a capture file you simply say PacketIndexer.remove(100) or PacketIndexer.add(50, anotherPacket), which will remove the packet at index 100 in the first case and add a new packet at index 50.
Don't forget to close
Now this isn't a step that really deserves a section to itself, but make sure you CLOSE the capture session in order to free up possibly significant amount of resources. All Capture sessions should be closed with Capture.close when no longer needed. If you don't have a direct reference to a capture because you put it in a tight java foreach loop for exmple, for(LivePacket: Captures.openLive()){...}, you can use the static method out of the good old Captures.close which closes the last capture session returned.
There is a whole section dedicates to iterators and indexers. You should read that next.