hold list of devices int statusCode = Pcap.findAllDevs(ifs, errbuf); if (statusCode != Pcap.OK) { System.out.println("Error occured: " + errbuf.toString()); return; } // We have a list of PcapIf devices to work with now.
Note: the return value from {@link #findAllDevs} is an integer resultcode, just like in the C counter part. The ifs
list is filled in with all the network devices as found from the corresponding C structure pcap_if
linked list returned from the C function call findAllDevs.
Now that we have a list of devices, we we print out the list of them and ask the user to pick one to open for capture:
for (int i = 0; i < ifs.size(); i++) { System.out.println("#" + i + ": " + ifs.get(i).getName()); } String l = System.in.readline().trim(); Integer i = Integer.valueOf(l); PcapIf netInterface = ifs.get(i);
Opening a network interface for live capture
Next we open up a live capture from the network interface using {@link #openLive(String,int,int,int,StringBuilder)}:
int snalen = 2048; // Truncate packet at this size int promiscous = Pcap.MODE_PROMISCUOUS; int timeout = 60 * 1000; // In milliseconds Pcap pcap = Pcap.openLive(netInterface.getName(), snaplen, promiscous, timeout, errbuf);
Last argument is a buffer that will hold an error string, if error occures. On error
openLive
will return null.
Compiling and applying a filter to network interface
Once we have an open interface for capture we can apply a filter to reduce amount of packets captured to something that is interesting to us:
PcapBpfProgram filter = new PcapBpfProgram(); String expression = "port 23" int optimize = 0; // 1 means true, 0 means false int netmask = 0; int r = pcap.compile(filter, expression, optimize, netmask); if (r != Pcap.OK) { System.out.println("Filter error: " + pcap.getErr()); } pcap.setFilter(filter);
If filter expression contained a syntax error, the return code will be -1 and exact error message can be retrieved using {@link #getErr} method.
Note of caution: the PcapBpfProgram
at the top of the previous code section, can not be accessed until successfully filled in with values in the pcap.compile
code. If you try and access any of its methods an IllegalStateException
will be thrown. Only after a successful call to compile
does the object become usable. The object is peered with C structure and until properly intialized, can not be accessed from java.
Dispatcher to receive packets as they arrive
And lastly lets do something with the data.
PcapHandler<PrintStream> handler = new PcapHandler<PrintStream>() { public void newPacket(PrintStream out, int caplen, int len, int seconds, int usecs, ByteBuffer buffer) { out.println("Packet captured on: " + new Date(seconds * 1000).toString()); } }; int cnt = 10; // Capture packet count PrintStream out = System.out; // Our custom object to send into the handler pcap.loop(cnt, handler, out); // Each packet will be dispatched to the handler pcap.close();
This sets up PCAP to capture 10 packets and notify our handler of each packet as each one is captured. Then after 10 packets the loop exits and we call pcap.close() to free up all the resources and we can safely throw away our pcap object. Also you may be curious why we pass System.out as userData to the loop handler. This is simply to demonstrate the typical usage for this kind of parameter. In our case we could easily pass a different PrintStream bound to lets say a network socket and our handler would produce output to it.
Alternative way of capturing packets from any of the open pcap sessions is to use {@link #dispatch(int,PcapPacketHandler,Object)} method, which worksvery similarly to {@link #loop(int,PcapPacketHandler,Object)}. You can also use {@link #next(PcapHeader,JBuffer)} and{@link #nextEx(PcapHeader,JBuffer)} methods which will deliver 1 packet at atime.
No packet data copies!
The packet data is delivered in a java.nio.ByteBuffer
. The data is not copied into the buffer, but a direct byte buffer is allocated and wrapped around the packet data as returned from libpcap. No in memory copies are performed, so if the native operating system supports no-copy packet captures, the packet are delived to Java without copies. Only a single ByteBuffer object allocation is incured.
Omitted methods from standard lipcap API
Certain deprecated methods from libpcap API have been omitted such as
lookupDev
,
lookupNet
. Also any methods that return
FILE *
since that is not appropriate for java environment.
Multithreading issues
Pcap
class does not provide any multithreading capabilities. As a pure wrapper for native libpcap library, Pcap
does not provide any additional locking or multithreaded paradigms. The most suggesting method is the {@link #breakloop()}, which can only be used from another thread. This is the extent of Pcap
's multithreading capabilities and threads have to be synchronized externally. Extrememe care must be taken, to ensure that no two methods are in use at the same time, with the exception of breakloop()
. For example, calling on {@link #close()} while a loop is still in progress will causelibpcap libpcap to crash or coredump which will also crash the entire Java VM.
@author Mark Bednarczyk
@author Sly Technologies, Inc.