Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Jpcap


SysAdminMag.com

Jpcap

Jon Hoffman

Have you ever tried to write a systems administration or network security application in Java? If so, you know that Java lacks the necessarily low-level network functionality needed for these types of applications. You cannot handcraft a TCP/IP packet, set the flags, or even ping a computer with the standard Java network classes. That is where jpcap comes in.

Jpcap is a Java class that allows a Java application to read/write packets to the network, and it is available from:

http://netresearch.ics.uci.edu/kfujii/jpcap/doc/index.html 
            
Jpcap is based on winpcap/libpcap (winpcap.org and tcpdump.org), so it should work on any operating system that they support. In this article, I will use jpcap to develop a Java class for use in your own applications, which will contain some of the low-level network functionality needed to develop a "heartbeat" function to let you know if a remote computer is on. This heartbeat function will send a TCP packet to a remote computer with the "ACK" (acknowledge) flag set and then listen for a TCP packet back with the "RST" flag set. If the remote computer does not respond with the RST packet, it is either off the network or the port to which you sent the ACK packet is being blocked by a firewall. The Three-Way Handshake When a computer wants to communicate with a remote computer using TCP/IP, a three-way handshake must occur. The first machine begins by sending a packet with the "SYN" flag set. This is like saying, "Hi, Joe. Can we talk?" The remote computer is supposed to respond with a packet that has the SYN/ACK (synchronize/acknowledge) flags set, which is like Joe saying, "Sure, we can talk. What's up?" The three-way handshake is completed when the first machine responds with a packet that has the ACK flag set. This is like responding to Joe by saying "Good, because I have something to tell you." It's actually a bit more complicated than that, but to fully explain how TCP/IP works is well beyond the scope of this article. If you are interested in learning more about TCP/IP and how computers communicate, there are many good Web sites and books dedicated to that subject. Figure 1 shows the three-way handshake between two computers. For the rest of this article, if I refer to a TCP packet as an ACK packet or RST packet or any other TCP flag before the word packet, that means it is a TCP packet with that flag(s) set to true. If the first computer begins the handshaking with the ACK packet, the second computer will think it has missed the first part of the handshake and send a RST (reset) packet to the first computer so they can begin again. This also lets the first computer know that the second computer is "alive" on the network and that the port to which the packet was sent is not blocked. Figure 2 shows how our heartbeat method will work. The key to this type of heartbeat application is that the remote computer does not need to have any client application listening on the port to which the "ACK" packet is sent. The operating system will detect that the handshake did not occur properly and send a reset. The only requirement is the port cannot be blocked by a firewall. Before you can install jpcap, you will need to install libpcap for Unix/Linux or winpcap for Windows. If you are running Unix/Linux, you probably already have libpcap installed; just make sure you have version 0.9.4 or later. For most Linux distributions, you should go to the /usr/lib directory and then do a ls libpcap*. If libpcap is installed, you will see something like "libpcap.so.X.X.X" with the X.X.X as the version installed. If you do not have libpcap installed, or you have an older version, please see http://www.tcpdump.org for instructions on how to install it. If you are running Windows, download the installer from http://www.winpcap.org and just install it. If you already have winpcap installed, the installer will let you know. After you have libpcap/winpcap installed, download jpcap from:
http://netresearch.ics.uci.edu/kfujii/jpcap/doc/index.html 
    
and follow the installation instructions on the Web site. The Networking Class Once everything is installed, we can start writing our networking class. We'll begin the networking class with a simple constructor method that will obtain a list of network devices on the system and put the information into an array of NetworkInterfaces called devices (this is the jpcap.NetworkInterface not the java.net.NetworkInterface). The devices array will be used throughout our networking class, so it is defined as a global array. Listing 1 shows the start of our networking class. You can refer to the JavaDoc API documentation for the jpcap classes at:
http://netresearch.ics.uci.edu/kfujii/jpcap/doc/javadoc/index.html 
for more details about the jpcap classes. The getNetworkInterfaces() method returns the devices array so that a list of devices can be printed out. This is very useful in determining which network interface device to use in the other methods. If you are working on a Windows machine, you will want to print the list of network devices with the following code:
       NetworkInterface[] devices = net.getNetowrkInterfaces(); 
        for (int i=0; i<devices.length; i++) 
            System.out.println(i + ": " + devices[i].description);
The corresponding output should look something like this:
0: Generic dialup adapter 
1: Broadcom 440x 10/100 Integrated Controller (Microsoft's Packet Scheduler) 
2: Instant Wireless Network PC Card V2.5 (Microsoft's Packet Scheduler) 
If you are working with Linux, the output would be a lot more cryptic, so you would want to use the following code (note that you change the devices[i].description to devices[i].name):
        NetworkInterface[] devices = net.getNetowrkInterfaces(); 
        for (int i=0; i<devices.length; i++)         
            System.out.println(i + ": " + devices[i].description); 
The corresponding output should look something like this:
0:  eth0 
1:  any 
2:  lo 
The number before each device name/description is the location of the device in the array. I will call this number the NetwordInterfaceID for the remainder of this article, and it will be utilized to select which interface to use in the upcoming methods. Obtaining MAC and IP Addresses To handcraft a TCP packet to send to remote computers, you must first know your IP and MAC addresses. These will be used for the source (sender) information of the TCP/IP packets so that the remote computer will know who sent the packet and where to send the response. An IP address is the network identifier of a computer or device on a TCP/IP network (e.g., the Internet is a TCP/IP network). An IP address is a 32-bit numeric address written as four numbers separated by periods. Each number can range from 0 to 255 and is usually in decimal format (e.g., 69.l87.32.220 is an IP address). A MAC (Media Access Control) address is a unique identifier attached to most networking equipment. The Mac address is a 48-bit numeric address written as six numbers separated by colons. Each number can range from 0 to 255 and is usually in hexadecimal format (e.g., 00:03:25:dc:2a:53 is a MAC address). To find your IP and MAC addresses manually, you can run ifconfig on a Unix/Linux machine or ipconfig /all on a Windows machine. Listings 2 and 3 return the MAC and IP addresses of the current computer given a NetworkInterfaceID number. Keep in mind that the NetworkInterfaceID is the number of the network interface you wish to use to send the packet. The myMacAddress and myIPAddress methods both accept one argument, which is the networkInterfaceID of the network device from which you want to obtain the information. Both methods will then verify that a valid networkInterfaceID has been received, and, if not, will return a null to the method that called it. The next steps are to set the device (which is a NetworkInterface object) to the NetworkInterface specified by the networkInterfaceID, retrieve the address information required from the device, and return the information in an array of bytes. Once you've obtained your MAC and IP addresses, you need the MAC and IP addresses of the remote computer you wish to check. If you only know the FQN (fully qualified name (e.g., www.yahoo.com is a FQN) of the remote computer, you can get the IP address by running nslookup FQN (where FQN is the fully qualified name of the remote computer) at the terminal/command prompt. It's a bit more difficult to obtain the MAC address of the remote computer than to obtain the IP address. It is possible to obtain the MAC address from the terminal/command prompt if you have communicated with it recently, but we will write a function to obtain it given the IP address, so that you only need to know the IP address to do the heartbeat function. Listing 4 contains the method to get the MAC address of the remote machine. If you are familiar with TCP/IP networking, you will know that ARP stands for "Address Request Protocol". ARP is an actual protocol that is designed to get the MAC address of remote machine. I called the method arp (lowercase) because it's purpose is the same as the ARP protocol. For the remainder of the article, ARP in caps will stand for the protocol, and arp in lower case will stand for our method. The ARP protocol is a very basic protocol. It sends out a broadcast that asks for the MAC address of the computer with the specified IP address. The remote computer, if it is listening, should respond with the MAC address. You might be thinking that if the computer responds with its MAC address, it should be alive and listening and that is all we need for a heartbeat application. This would be correct except for the fact that ARP requests can be cached, so we cannot rely on this for the heartbeat. The arp method accepts three arguments: the Ipaddress of the remote computer (ip), the Ipaddress of the local computer (srcip), and the networkInterfaceID of the network card to use (networkInterfaceID). The first part of the arp method should look familiar. We begin by verifying that the NetworkInterfaceID is valid, then we set the device (which is a NetworkInterface object) to the NetworkInterface specified by the networkInterfaceID, and obtain the MAC address using the myMacAddress method. Then it starts to get a little more complicated. The JpcapCaptor.openDevice method initializes the network interface (defined by the NetworkInterface object device), returns an instance of the JpcapCaptor class, and assigns it to captor. The openDevice method accepts four arguments: the NetworkInterface object to use, Max number of BYTES to capture at once, set the interface to promiscuous mode, and the time out. We then assign a filter to the captor object with the setFilter method. The setFilter method accepts filters in the TCPDump format. For information on this format, refer to:
http://www.tcpdump.org/tcpdump_man.html 
The second argument in the setFilter method is a Boolean one, if you want the filter optimized. The ARP and Ethernet packets have a number of fields to set, and the code is commented to tell you what each field is. Once the packet is crafted, you can send it out with the sender.sendPacket method. It accepts a packet object as its one argument. The method finishes by capturing any packets that fit the filter defined in the setFilter method. If the capture times out, it will throw an IllegalArgumentException saying the remote computer did not respond. If the remote computer does respond to the ARP request, it returns the MAC address of the remote computer. You now have all the information needed to communicate with a remote computer over a TCP/IP network. In the next method, you will craft the TCP packet and send it to the remote machine. The ACKheartbeat Method Listing 5 contains the ACKheartBeat method. It will return a true, if the remote machine responded with the RST packet, or false, if it did not get a response. The ACKheartBeat method accepts four arguments: the NetworkInterfaceID of the network device to use, the IP address of the remote machine, the tcp port from which to send the packet, and the tcp port to which to send the packet. Most of the ACKheartBeat method should look familiar to you from the arp method. The main difference is that you are crafting a TCP packet rather than an ARP packet. The following lines define the settings for the TCP packet and the IP parameters:
TCPPacket p=new TCPPacket(srcPort,dstPort,60,60,false,true, \ 
  false,false,false,false,false,false,65535,0); 
                    p.setIPv4Parameter(0,false,false,false,0, \   
                      false,false,false,0,0,200,IPPacket. \         
                      IPPROTO_TCP,InetAddress. \                     
                      getByAddress(myIPAdd),InetAddress. \     
                      getByAddress(recAddr)); 
The constructor for the TCPPacket accepts 14 parameters. From left to right they are:
srcPort - The port number to send the packet from on the local computer
dstPort - The port number to send the packet to on the remote computer 
60 - sequence number 
60 - ACK number 
false - boolean URG flag 
true -  boolean ACK flag 
false - boolean PSH flag 
false - boolean RST flag 
false - boolean SYN flag 
false - boolean FIN flag 
false - boolean RSV1 
false - boolean RSV2 
65535- window size 
0 - urgent pointer
You can try setting different flags to see which type of response you receive from the remote machine. You only want the ACK flag set for the heartbeat method, so you can get a reset (packet with the RST flag set) response from the remote machine. Keep in mind that if you want to establish a communication link with another machine, you must start by sending a packet with the SYN flag set, then wait for the remote machine to return a packet with the SYN and ACK flags set, and finally you must send a packet with the ACK flag set. There is more involved to this, but, as I mentioned earlier, those details are well beyond the scope of this article. After the TCP/IP and Ethernet packets are crafted, you can send the packet out just like you did in the arp method and begin listening for a response. In the arp method, you set the filter of the captor method to "arp", which meant that you only wanted to captor arp responses. In the ACKheartBeat method, the filter is set to "tcp dst port " + srcPort, which states that you only want to capture tcp packets destined to the port from which you sent the TCP packet. The filter is set this way because the remote computer will respond to the port that originally sent the packet from. Using the Heartbeat Function You would use the ACKheartBeat like this:
networking net = new networking(); 
boolean alive = net.ACKheartBeat(1, "192.168.10.55",4421,2110); 
This would send a packet with the ACK flag set from the 4421 TCP port of the local machine to the 2110 TCP port of the computer located at the IP address of 192.168.10.55. If the computer responds, "alive" is set to true; if it does not respond, "alive" is set to false. You can use the results of the heartbeat application to trigger other processes. For example, if the heartbeat comes back false, you can send an email alert to the systems administrator. You could also put the results into a database and have another application display the results for a network monitor. You could even have the ACKheartbeat go out to the Internet and, if the results are false, you know that your connection to the Internet is down and have the computer switch to a backup connection. You can now use the jpcap to expand the networking class that we created in this article. Rather then sending an ACK packet, try sending a packet with only the SYN flag set. If the remote computer responds with a packet with both the SYN and ACK flags set, there is an application listening on that port. If the remote computer responds with the RST flag set, there is no application listening on that port but it is not blocked by a firewall. If there is no response, then the remote computer is either off the network or that port is being filtered by a firewall. This procedure can be used as a port scanner. Conclusion Jpcap can be used to write many different systems administrations utilities or network security tools that used to be off limits to Java developers because of the lack of low-level network support in Java. The Windows and Linux/Unix versions of jpcap can both be used to write Networking tools, but I have noticed that that the jpcap.NetworkInterface class for Windows does not always return the right information. In the networking class that I wrote for this article, I put in the following code:
     if (macString.equalsIgnoreCase("0:0:0:0:0:0:")) 
            returnByte = myMacAddress(0); 
    
0:0:0:0:0:0 is not a valid MAC address, but it does show up in the Windows version of jpcap. When it does, the correct MAC address is in the networkInterface with a networkInterfaceID of 0.

The jpcap Web site states that the latest version of jpcap requires libpcap 0.9.4 (which is also the latest release) or later, but it does not specify which version of winpcap is required. I believe the problem involves the latest version of winpcap not being 100% compatible with latest version of libpcap. My recommendation is to use the Windows version of jpcap only for development and the Linux/Unix version for production.

As a Systems Operation Manager, Jon works in the Network/Systems Administration, Network Security, and Development fields. Jon enjoys projects that combine all these areas, and that is where he got the idea to start writing administration and security tools in Java. Jon can be reached at: [email protected].


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.