/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.tools.ldapdecoder.snoop;
/**
* This class defines a data structure for storing information about an Internet
* Protocol header as defined in RFC 791.
*
*
* @author Neil A. Wilson
*/
public class IPv4Header
{
/**
* The ethertype used in the Ethernet header to indicate that the packet
* contains IPv4 data.
*/
public static final int ETHERTYPE_IPV4 = 0x0800;
// Indicates whether fragmented communication will be accepted.
private boolean mayFragment;
// Indicates whether this is the last fragment.
private boolean lastFragment;
// The specific IP protocol for this datagram.
private byte protocol;
// The time to live (TTL) for this packet.
private byte timeToLive;
// The byte defining the type of service bitmask.
private byte typeOfService;
// The option data associated with this IP datagram.
private byte[] optionBytes;
// The destination IP address for this IP packet.
private int destinationIP;
// The checksum for the IP header.
private int headerChecksum;
// The IP version for this header.
private byte ipVersion;
// The number of 32-bit words contained in the IP header.
private int ipHeaderWords;
// The source IP address for this IP packet.
private int sourceIP;
// The total length in bytes of this IP datagram, including the IP header and
// data.
private int totalLength;
// The identification value for this IP datagram.
private int ipID;
// The fragment offset for this IP datagram.
private int fragmentOffset;
/**
* Creates a new IPv4 header data structure with the provided information.
*
* @param ipVersion The IP version for this IP datagram.
* @param ipHeaderWords The number of 32-bit words contained in this IP
* header.
* @param typeOfService The type of service for this IP datagram.
* @param totalLength The total length in bytes of this IP packet,
* including the header and data.
* @param ipID The identifier for this IP datagram.
* @param mayFragment Indicates whether packets may be fragmented.
* @param lastFragment Indicates whether this is the last fragment in a
* set.
* @param fragmentOffset The offset in 64-bit words of this fragment in the
* overall data stream.
* @param timeToLive The time to live for this IP datagram.
* @param protocol The specific IP protocol represented by this
* packet.
* @param headerChecksum The checksum for the IP header.
* @param sourceIP The source IP address for this IP datagram.
* @param destinationIP The destination IP address for this IP datagram.
* @param optionBytes The set of data associated with any options that
* may be contained in this IP header.
*/
public IPv4Header(byte ipVersion, int ipHeaderWords, byte typeOfService,
int totalLength, int ipID, boolean mayFragment,
boolean lastFragment, int fragmentOffset, byte timeToLive,
byte protocol, int headerChecksum, int sourceIP,
int destinationIP, byte[] optionBytes)
{
this.ipVersion = ipVersion;
this.ipHeaderWords = ipHeaderWords;
this.typeOfService = typeOfService;
this.totalLength = totalLength;
this.ipID = ipID;
this.mayFragment = mayFragment;
this.lastFragment = lastFragment;
this.fragmentOffset = fragmentOffset;
this.timeToLive = timeToLive;
this.protocol = protocol;
this.headerChecksum = headerChecksum;
this.sourceIP = sourceIP;
this.destinationIP = destinationIP;
this.optionBytes = optionBytes;
}
/**
* Decodes data in the provided byte array as an IPv4 header.
*
* @param headerBytes The byte array containing the data to decode.
* @param offset The position in the byte array at which the IPv4
* header starts.
*
* @return The decoded IPv4 header.
*
* @throws SnoopException If there is a problem decoding the IPv4 header.
*/
public static IPv4Header decodeIPv4Header(byte[] headerBytes, int offset)
throws SnoopException
{
// First, make sure that the provided array is long enough to hold the
// minimum IPv4 header of 20 bytes.
if ((offset+20) > headerBytes.length)
{
throw new SnoopException("There are not enough bytes in the provided " +
"array to hold the minimum IPv4 header length " +
"of 20 bytes");
}
byte ipVersion = (byte) ((headerBytes[offset] >>> 4) & 0xFF);
if (ipVersion != 0x04)
{
throw new SnoopException("IP version is not 4");
}
int ipHeaderWords = (headerBytes[offset] & 0x0F);
if ((offset + (ipHeaderWords*4)) > headerBytes.length)
{
throw new SnoopException("There are not enough bytes in the provided " +
"array to hold the indicated IPv4 header " +
"header length of " + (ipHeaderWords*4) +
" bytes");
}
byte typeOfService = headerBytes[offset+1];
int totalLength = SnoopDecoder.byteArrayToInt(headerBytes, offset+2, 2);
int ipID = SnoopDecoder.byteArrayToInt(headerBytes, offset+4, 2);
int fragmentBits = SnoopDecoder.byteArrayToInt(headerBytes, offset+6, 2);
boolean mayFragment = ((fragmentBits & 0x4000) == 0x0000);
boolean lastFragment = ((fragmentBits & 0x2000) == 0x0000);
int fragmentOffset = (fragmentBits & 0x1FFF);
byte timeToLive = headerBytes[offset+8];
byte protocol = headerBytes[offset+9];
int headerChecksum = SnoopDecoder.byteArrayToInt(headerBytes, offset+10, 2);
int sourceIP = SnoopDecoder.byteArrayToInt(headerBytes, offset+12, 4);
int destinationIP = SnoopDecoder.byteArrayToInt(headerBytes, offset+16, 4);
byte[] optionBytes;
if (ipHeaderWords == 5)
{
optionBytes = new byte[0];
}
else
{
optionBytes = new byte[(ipHeaderWords-5) * 4];
System.arraycopy(headerBytes, offset+20, optionBytes, 0,
optionBytes.length);
}
return new IPv4Header(ipVersion, ipHeaderWords, typeOfService, totalLength,
ipID, mayFragment, lastFragment, fragmentOffset,
timeToLive, protocol, headerChecksum, sourceIP,
destinationIP, optionBytes);
}
/**
* Retrieves the IP protocol version specified in this datagram. The version
* will be encoded in the lower 4 bits of the returned byte.
*
* @return The IP protocol version specified in this datagram.
*/
public byte getIPVersion()
{
return ipVersion;
}
/**
* Retrieves the length in bytes of the IPv4 header.
*
* @return The length in bytes of the IPv4 header.
*/
public int getIPHeaderLength()
{
return (ipHeaderWords * 4);
}
/**
* Retrieves the byte containing the type of service flags for this IP
* datagram.
*
* @return The byte containing the type of service flags for this IP
* datagram.
*/
public byte getTypeOfService()
{
return typeOfService;
}
/**
* Retrieves the total length of this IPv4 datagram, including the header and
* any data.
*
* @return The total length of this IPv4 datagram, including the header and
* any data.
*/
public int getIPDatagramLength()
{
return totalLength;
}
/**
* Retrieves the identifier for this IPv4 datagram. The identifier will be
* encoded in the lower 16 bits of the returned int value.
*
* @return The identifier for this IPv4 datagram.
*/
public int getIPID()
{
return ipID;
}
/**
* Indicates whether the originator will accept fragmented packets.
*
* @return <CODE>true</CODE> if the originator will accept fragmented
* packets, or <CODE>false</CODE> if not.
*/
public boolean mayFragment()
{
return mayFragment;
}
/**
* Indicates whether this packet contains the last fragment in a fragmented
* data stream.
*
* @return <CODE>true</CODE> if this packet contains the last fragment in a
* fragmented data stream, or <CODE>false</CODE> if there are more
* fragments.
*/
public boolean lastFragment()
{
return lastFragment;
}
/**
* Retrieves the offset of this fragment in the overall data stream. The
* value will be encoded in the lower 13 bits of the returned int value, and
* it specifies the number of 64-bit datagrams into the overall data stream
* this IPv4 packet lies.
*
* @return The offset of this fragment in the overall data stream.
*/
public int getFragmentOffset()
{
return fragmentOffset;
}
/**
* Retrieves the time to live (TTL) for this IP datagram.
*
* @return The time to live for this IP datagram.
*/
public byte getTimeToLive()
{
return timeToLive;
}
/**
* Retrieves the protocol for this IP datagram.
*
* @return The protocol for this IP datagram.
*/
public byte getProtocol()
{
return protocol;
}
/**
* Retrieves the checksum for this IP datagram. The checksum will be encoded
* in the lower 16 bits of the returned int value.
*
* @return The checksum for this IP datagram.
*/
public int getHeaderChecksum()
{
return headerChecksum;
}
/**
* Retrieves the source IP address for this datagram, as a 32-bit value.
*
* @return The source IP address for this datagram as a 32-bit value.
*/
public int getSourceIP()
{
return sourceIP;
}
/**
* Retrieves the destination IP address for this datagram, as a 32-bit value.
*
* @return The destination IP address for this datagram as a 32-bit value.
*/
public int getDestinationIP()
{
return destinationIP;
}
/**
* Converts the provided 32-bit integer value to an IP address in dotted quad
* format.
*
* @param addressInt The 32-bit integer value containing the encoded IP
* address.
*
* @return The String representation of the provided IP address.
*/
public static String intToIPAddress(int addressInt)
{
StringBuilder buffer = new StringBuilder(16);
buffer.append((addressInt >>> 24) & 0x000000FF).append('.').
append((addressInt >>> 16) & 0x000000FF).append('.').
append((addressInt >>> 8) & 0x000000FF).append('.').
append(addressInt & 0x000000FF);
return buffer.toString();
}
/**
* Retrieves the encoded IP option data for this header.
*
* @return The encoded IP option data for this header.
*/
public byte[] getOptionBytes()
{
return optionBytes;
}
}