Jpcap Tutorial

1.0 (for Jpcap 0.7)

Author:
    Keita Fujii (kfujii@uci.edu)
Home page:
    http://netresearch.ics.uci.edu/kfujii/jpcap/doc/index.html

Table of Contents

Introduction

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.

The latest version of this document can be found at: http://netresearch.ics.uci.edu/kfujii/jpcap/doc/tutorial/index.html

What is Jpcap

Jpcap is an open source library for capturing and sending network packets from Java applications. It provides facilities to:
  • capture raw packets live from the wire. 
  • save captured packets to an offline file, and read captured packets from an offline file.
  • automatically identify packet types and generate corresponding Java objects (for Ethernet, IPv4, IPv6, ARP/RARP, TCP, UDP, and ICMPv4 packets).
  • filter the packets according to user-specified rules before dispatching them to the application.
  • send raw packets to the network
Jpcap is based on libpcap/winpcap, and is implemented in C and Java.

Jpcap has been tested on Microsoft Windows (98/2000/XP/Vista), Linux (Fedora, Ubuntu), Mac OS X (Darwin), FreeBSD, and Solaris.

What kind of applications can be developed using Jpcap

Jpcap can be used to develop many kinds of network applications, including (but not limited to):
  • network and protocol analyzers
  • network monitors
  • traffic loggers
  • traffic generators
  • user-level bridges and routers
  • network intrusion detection systems (NIDS)
  • network scanners
  • security tools

What Jpcap cannot do

Jpcap captures and sends packets independently 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.


Jpcap tutorial: a step by step guide for using Jpcap

Obtain the list of network interfaces

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 providesJpcapCaptor.getDeviceList() method. It returns an array of NetworkInterface objects.

NetworkInterface 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 intrfaceNetwork interface that you want to open.
int snaplenMax number of bytes to capture at once.
boolean promicsTrue 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_msSet 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 method

In 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/Wireshark

Save 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 interfacesection 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() orJpcapCaptor.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();