This document describes how to develop applications using Jpcap. It
explains the functions and classes defined in Jpcap, and also
provides comprehensive descriptions on how to program using
Jpcap by showing some example codes.
Jpcap is an open source library for capturing and sending network
packets from Java applications. It provides facilities to:
Jpcap
has been tested on
Microsoft Windows (98/2000/XP/Vista), Linux (Fedora, Ubuntu), Mac OS
X (Darwin), FreeBSD, and Solaris.
Jpcap can be used to develop many kinds of network
applications, including (but not limited to):
from the host protocols (e.g., TCP/IP). This means that Jpcap
does not (cannot) block, filter or manipulate the traffic generated by
other programs on the same machine: it simply "sniffs" the packets that
transit on the wire. Therefore, it does not provide the appropriate
support for applications like traffic shapers, QoS schedulers and
personal firewalls.
When you want to capture packets from a network, the first thing you
have to do is to obtain the list of network interfases on your machine.
To do so, Jpcap provides
method. It returns an array of
object contains some information about the corresponding network
interface, such as its name, description, IP and MAC addresses, and
datatlink name and description.
The following sample code obtains the list of network
interfaces and
prints out their information.
//Obtain the list of network interfaces
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
//for each network interface
for (int i = 0; i < devices.length; i++) {
//print out its name and description
System.out.println(i+": "+devices[i].name + "(" + devices[i].description+")");
//print out its datalink name and description
System.out.println(" datalink: "+devices[i].datalink_name + "(" + devices[i].datalink_description+")");
//print out its MAC address
System.out.print(" MAC address:");
for (byte b : devices[i].mac_address)
System.out.print(Integer.toHexString(b&0xff) + ":");
System.out.println();
//print out its IP address, subnet mask and broadcast address
for (NetworkInterfaceAddress a : devices[i].addresses)
System.out.println(" address:"+a.address + " " + a.subnet + " "+ a.broadcast);
}
This
sample code may show a result like the following (on
windows):
0: \Device\NPF_{C3F5996D-FB82-4311-A205-25B7761897B9}(VMware Virtual Ethernet Adapter)
data link:EN10MB(Ethernet)
MAC address:0:50:56:c0:0:1:
address:/fe80:0:0:0:3451:e274:322a:fd9f null null
address:/172.16.160.1 /255.255.255.0 /255.255.255.255
or
the following (on Linux/UNIX):
0 : eth0(null)
datalink: EN10MB(Ethernet)
MAC address:0:c:29:fb:6c:df:
address:/172.16.32.129 /255.255.255.0 / 172.16.32.255
Open a network interface
Once
you obtain the list of network interfaces and choose which network
interface to captuer packets from, you can open the interface by
using
JpcapCaptor.openDevice()
method. The following piece of code illustrates how to open an network
interface.
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
int index=...; // set index of the interface that you want to open.
//Open an interface with openDevice(NetworkInterface intrface, int snaplen, boolean promics, int to_ms)
JpcapCaptor captor=JpcapCaptor.openDevice(device[index], 65535, false, 20);
When
calling the
JpcapCaptor.openDevice()
method, you can specify the following parameters:
Name: | Purpose |
NetworkInterface intrface | Network
interface that you want to open. |
int snaplen | Max
number of bytes to capture at once. |
boolean promics | True
if you want to open the interface in promiscuous mode, and
otherwise false.
In
promiscuous mode, you can capture packets every packet from the
wire, i.e., even if its source or destination MAC address is not same
as the MAC address of the interface you are opening. In
non-promiscuous mode, you can only capture packets send and received by
your host. |
int to_ms | Set
a capture timeout value in milliseconds. |
JpcapCaptor.openDevice() returns an instance of
JpcapCaptor.
You can then call several methods of the
JpcapCaptor
class to actually capture packets from the network interface.
Capture packets from
the network interface
Once you obtain an instance of of
JpcapCaptor,
you can capture packets from the interface.
There
are two major approaches to capture packets using a
JpcapCaptor
instance: using a callback method, and capturing packets one-by-one.
Using
a callback methodIn this approach,
you implement a callback method to process captured packets, and then
pass the callback method to Jpcap so that Jpcap calls it back every
time it captures a packet. Let's see how you can do this approach in
detail.
First, you implement a callback method
by defining a new class which implements the
PacketReceiver
interface. The
PacketReceiver
interface defines a
receivePacket()
method, so you need to implement a
receivePacket()
method in your class.
The following class
implement a
receivePacket()
method which simply prints out a captured packet.
class PacketPrinter implements PacketReceiver {
//this method is called every time Jpcap captures a packet
public void receivePacket(Packet packet) {
//just print out a captured packet
System.out.println(packet);
}
}
Then, you can call either
JpcapCaptor.processPacket() or
JpcapCaptor.loopPacket() methods to start capturing using the callback method. When calling
processPacket() or
loopPacket()
method, you can also specify the number of packets to capture before
the method returns. You can specify -1 to continue capturing packets
infinitely.
JpcapCaptor captor=JpcapCaptor.openDevice(device[index], 65535, false, 20);
//call processPacket() to let Jpcap call PacketPrinter.receivePacket() for every packet capture.
captor.processPacket(10,new PacketPrinter());
captor.close();
The two methods for callback,
processPacket() and
loopPacket(), are very similar. Usually you might want to use
processPacket() because it supports timeout and non_blocking mode, while
loopPacket() doesn't.
Capturing
packets one-by-one
Using
a callback method is a little bit tricky because you don't know when
the callback method is called by Jpcap. If you don't want to use a
callback method, you can also capture packets using the
JpcapCaptor.getPacket() method.
getPacket() method simply returns a captured packet. You can (or have to) call
getPacket() method multiple times to capture consecutive packets.
The following sample code also prints out captured packets.
JpcapCaptor captor=JpcapCaptor.openDevice(device[index], 65535, false, 20);
for(int i=0;i<10;i++){
//capture a single packet and print it out
System.out.println(captor.getPacket());
}
captor.close();
Set capturing filter
In Jpcap, you can set a
filter so that Jpcap doesn't capture unwanted packets. For example, if
you only want to capture TCP/IPv4 packets, you can set a filter as
following:
JpcapCaptor captor=JpcapCaptor.openDevice(device[index], 65535, false, 20);
//set a filter to only capture TCP/IPv4 packets
captor.setFilter("ip and tcp", true);
The
filter expression "ip and tcp" means to to "keep only the packets that
are both IPv4 and TCP and deliver them to the application".
By
properly setting a filter, you can reduce the number of packets to
examine, and thus can improve the performance of your application.
You can check the following homepage for more details about filter expression.
Designing
Capture Filters for Ethereal/WiresharkSave captured packets
into a file
You
can save captured packets into a binary file so that you can later
retrieve them using Jpcap or other applications which supports reading
a tcpdump format file.
To save captured packets, you first need to open a file by calling
JpcapWriter.openDumpFile() method with an instance of
JpcapCaptor which was used to capture packets, and a String filename.
JpcapCaptor captor=JpcapCaptor.openDevice(device[index], 65535, false, 20);
//open a file to save captured packets
JpcapWriter writer=JpcapWriter.openDumpFile(captor,"yourfilename");
Once you obtained an instance of
JpcapWriter through
openDumpFile() method, you can save captured packets using
JpcapWriter.writePacket() method. After you saved all the packets you want to save, you need to call
JpcapWriter.close() method to close the opened file.
The following sample code, combined with the above code, captures and saves first 100 packets captured.
for(int i=0;i<10;i++){
//capture a single packet
Packet packet=captor.getPacket();
//save it into the opened file
writer.writePacket(packet);
}
writer.close();
Read saved packets from
a file
In Jpcap, you can read the packets you saved using
JpcapWriter by opening the file using
JpcapCaptor.openFile() method. Similar to
JpcapCaptor.openDevice() method,
JpcapCaptor.openFile() method also returns an instance of
JpcapCaptor class. So you can use the same ways described in
Capture packets from the
network interface section to read packets from the file. For example, you can read and print out saved packets from a file as follows:
//open a file to read saved packets
JpcapCaptor captor=JpcapCaptor.openFile("yourfilename");
while(true){
//read a packet from the opened file
Packet packet=captor.getPacket();
//if some error occurred or EOF has reached, break the loop
if(packet==null || packet==Packet.EOF) break;
//otherwise, print out the packet
System.out.println(packet);
}
captor.close();
Send packets through a
network interface
You can also send packets to the network using Jpcap. To send a packet, you need to obtain an instance of
JpcapSender by calling either
JpcapSender.openDevice() or
JpcapCaptor.getJpcapSenderInstance() methods.
Once you obtain an instance of
JpcapSender, you can pass an instance of
Packet class to
JpcapSender.sendPacket() method.
The following sample code sends a TCP/IPv4/Ethernet packet onto a network interface.
//open a network interface to send a packet to
JpcapSender sender=JpcapSender.openDevice(devices[index]);
//create a TCP packet with specified port numbers, flags, and other parameters
TCPPacket p=new TCPPacket(12,34,56,78,false,false,false,false,true,true,true,true,10,10);
//specify IPv4 header parameters
p.setIPv4Parameter(0,false,false,false,0,false,false,false,0,1010101,100,IPPacket.IPPROTO_TCP,
InetAddress.getByName("www.microsoft.com"),InetAddress.getByName("www.google.com"));
//set the data field of the packet
p.data=("data").getBytes();
//create an Ethernet packet (frame)
EthernetPacket ether=new EthernetPacket();
//set frame type as IP
ether.frametype=EthernetPacket.ETHERTYPE_IP;
//set source and destination MAC addresses
ether.src_mac=new byte[]{(byte)0,(byte)1,(byte)2,(byte)3,(byte)4,(byte)5};
ether.dst_mac=new byte[]{(byte)0,(byte)6,(byte)7,(byte)8,(byte)9,(byte)10};
//set the datalink frame of the packet p as ether
p.datalink=ether;
//send the packet p
sender.sendPacket(p);
sender.close();
Jpcap documentation.
Copyright (c) 2007 Keita Fujii. All rights reserved.