/*
* Copyright (c) 2006-2007 Graz University of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The names "Graz University of Technology" and "IAIK of Graz University of
* Technology" must not be used to endorse or promote products derived from
* this software without prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package ejip.jtcpip;
/**
* The IP Packet Class encapsulating methods to handle a Payload as an IP
* Packet. All methods are static and get a {@link Payload} as a parameter.
* There are get and set methods for all fields of the IP header.
*
* @author Tobias Kellner
* @author Ulrich Feichter
* @author Christof Rath
* @version $Rev: 849 $ $Date: 2007/01/24 19:37:07 $
*/
public class IPPacket
{
/** Position of the Reserved Flag in the 2nd word of the IP header */
private static final int RESERVED_MASK = 0x8000;
/** Position of the Don't Fragment Flag in the 2nd word of the IP header */
private static final int DF_MASK = 0x4000;
/** Position of the More Fragments Flag in the 2nd word of the IP header */
private static final int MF_MASK = 0x2000;
/**
* Get the IP Version. Should be 4 for IPv4
*
* @param pay
* The Payload
* @return The IP Version
*/
public static byte getVersion(Payload pay)
{
return (byte) (pay.ipHeader[0] >>> 28);
}
/**
* Set the IP Version Should be 4 for IPv4
*
* @param pay
* The Payload
* @param ver
* The IP Version to set
*/
public static void setVersion(Payload pay, byte ver)
{
int i = pay.ipHeader[0] & 0x0FFFFFFF;
pay.ipHeader[0] = i | ((ver & 0xF) << 28);
}
/**
* Get the Internet Header Length. This is the size of the IP header in
* 32-bit words. (min. 5, max. 15)
*
* @param pay
* The Payload
* @return The Internet Header Length
*/
public static byte getIHL(Payload pay)
{
return (byte) ((pay.ipHeader[0] >>> 24) & 0x0F);
}
/**
* Set the Internet Header Length. This is the size of the IP header in
* 32-bit words. (min. 5, max. 15)
*
* @param pay
* The Payload
* @param len
* The Internet Header Length
*/
public static void setIHL(Payload pay, byte len)
{
int i = pay.ipHeader[0] & 0xF0FFFFFF;
pay.ipHeader[0] = i | ((len & 0xF) << 24);
}
/**
* Get the Type of Service.
* <ul>
* <li> bits 0-2: precedence
* <li> bit 3: 0 = Normal Delay, 1 = Low Delay
* <li> bit 4: 0 = Normal Throughput, 1 = High Throughput
* <li> bit 5: 0 = Normal Reliability, 1 = High Reliability
* <li> bits 6-7: Reserved for future use
* </ul>
*
* @param pay
* The Payload
* @return The Type of Service
*/
public static byte getToS(Payload pay)
{
return (byte) ((pay.ipHeader[0] >>> 16) & 0xFF);
}
/**
* Set the Type of Service.
* <ul>
* <li> bits 0-2: precedence
* <li> bit 3: 0 = Normal Delay, 1 = Low Delay
* <li> bit 4: 0 = Normal Throughput, 1 = High Throughput
* <li> bit 5: 0 = Normal Reliability, 1 = High Reliability
* <li> bits 6-7: Reserved for future use
* </ul>
*
* @param pay
* The Payload
* @param tos
* The Type of Service
*/
public static void setToS(Payload pay, byte tos)
{
int i = pay.ipHeader[0] & 0xFF00FFFF;
pay.ipHeader[0] = i | ((tos & 0xFF) << 16);
}
/**
* Get the Total Length of the Packet. Entire size of the datagram,
* including header and data, in bytes. (min. 20, max. 65535)
*
* @param pay
* The Payload
* @return The Total Length
*/
public static short getLength(Payload pay)
{
return (short) (pay.ipHeader[0] & 0xFFFF);
}
/**
* Set the Total Length of the Packet. Entire size of the datagram,
* including header and data, in bytes. (min. 20, max. 65535)
*
* @param pay
* The Payload
* @param len
* The Total Length
*/
public static void setLength(Payload pay, short len)
{
int i = pay.ipHeader[0] & 0xFFFF0000;
pay.ipHeader[0] = i | (len & 0xFFFF);
}
/**
* Get the Identification. Used for uniquely identifying individual
* fragments of a fragmented IP Packet.
*
* @param pay
* The Payload
* @return The Identification
*/
public static short getID(Payload pay)
{
return (short) (pay.ipHeader[1] >>> 16);
}
/**
* Set the Identification. Used for uniquely identifying individual
* fragments of a fragmented IP Packet.
*
* @param pay
* The Payload
* @param id
* The Identification
*/
public static void setID(Payload pay, short id)
{
int i = pay.ipHeader[1] & 0x0000FFFF;
pay.ipHeader[1] = i | ((id & 0xFFFF) << 16);
}
/**
* Check whether the Reserved Flag is set. This Flag must be zero. <b>Note:</b>
* because this is a benign IP Stack, setting this flag is not possible.
*
* @param pay
* The Payload
* @return Whether the Reserved Flag is set
*/
public static boolean isReservedSet(Payload pay)
{
return (pay.ipHeader[1] & RESERVED_MASK) != 0;
}
/**
* Clear the Reserved Flag. This Flag must be zero. <b>Note:</b> because
* this is a benign IP Stack, setting this flag is not possible.
*
* @param pay
* The Payload
*/
public static void clearReserved(Payload pay)
{
pay.ipHeader[1] = pay.ipHeader[1] & ~RESERVED_MASK;
}
/**
* Check whether the Don't Fragment Flag is set. A Packet with DF set must
* not be fragmented. If it would have to be, it is dropped instead.
*
* @param pay
* The Payload
* @return Whether the Don't Fragment Flag is set
*/
public static boolean isDFSet(Payload pay)
{
return (pay.ipHeader[1] & DF_MASK) != 0;
}
/**
* Set the Don't Fragment Flag. A Packet with DF set must not be fragmented.
* If it would have to be, it is dropped instead.
*
* @param pay
* The Payload
*/
public static void setDF(Payload pay)
{
pay.ipHeader[1] = pay.ipHeader[1] | DF_MASK;
}
/**
* Clear the Don't Fragment Flag. A Packet with DF set must not be
* fragmented. If it would have to be, it is dropped instead.
*
* @param pay
* The Payload
*/
public static void clearDF(Payload pay)
{
pay.ipHeader[1] = pay.ipHeader[1] & ~DF_MASK;
}
/**
* Check whether the More Fragments Flag is set. In a fragmented IP Packet,
* all split Packets except the last one have this flag set.
*
* @param pay
* The Payload
* @return Whether the More Fragments Flag is set
*/
public static boolean isMFSet(Payload pay)
{
return (pay.ipHeader[1] & MF_MASK) != 0;
}
/**
* Set the More Fragments Flag. In a fragmented IP Packet, all split Packets
* except the last one have this flag set.
*
* @param pay
* The Payload
*/
public static void setMF(Payload pay)
{
pay.ipHeader[1] = pay.ipHeader[1] | MF_MASK;
}
/**
* Clear the More Fragments Flag. In a fragmented IP Packet, all split
* Packets except the last one have this flag set.
*
* @param pay
* The Payload
*/
public static void clearMF(Payload pay)
{
pay.ipHeader[1] = pay.ipHeader[1] & ~MF_MASK;
}
/**
* Get the Fragment Offset. The place of a particular fragment in the
* original IP datagram, measured in units of 8-byte blocks.
*
* @param pay
* The Payload
* @return The Fragment Offset
*/
public static short getFragOfs(Payload pay)
{
return (short) (pay.ipHeader[1] & 0x1FFF);
}
/**
* Set the Fragment Offset. The place of a particular fragment in the
* original IP datagram, measured in units of 8-byte blocks.
*
* @param pay
* The Payload
* @param ofs
* The Fragment Offset
*/
public static void setFragOfs(Payload pay, short ofs)
{
int i = pay.ipHeader[1] & 0xFFFFE000;
pay.ipHeader[1] = i | (ofs & 0x1FFF);
}
/**
* Get the Time To Live. Each packet switch (or router) that a datagram
* crosses decrements the TTL field by one. When the TTL field hits zero,
* the Packet is no longer forwarded by a packet switch and is discarded.
*
* @param pay
* The Payload
* @return The Time To Live
*/
public static byte getTTL(Payload pay)
{
return (byte) (pay.ipHeader[2] >>> 24);
}
/**
* Set the Time To Live. Each packet switch (or router) that a datagram
* crosses decrements the TTL field by one. When the TTL field hits zero,
* the Packet is no longer forwarded by a packet switch and is discarded.
*
* @param pay
* The Payload
* @param ttl
* The Time To Live
*/
public static void setTTL(Payload pay, byte ttl)
{
int i = pay.ipHeader[2] & 0x00FFFFFF;
pay.ipHeader[2] = i | ((ttl & 0xFF) << 24);
}
/**
* Get the Protocol. The protocol used in the data part of the datagram.
*
* @see IP#PROT_ICMP
* @see IP#PROT_TCP
* @see IP#PROT_UDP
*
* @param pay
* The Payload
* @return The Protocol
*/
public static byte getProtocol(Payload pay)
{
return (byte) ((pay.ipHeader[2] >>> 16) & 0xFF);
}
/**
* Set the Protocol. The protocol used in the data part of the datagram.
*
* @see IP#PROT_ICMP
* @see IP#PROT_TCP
* @see IP#PROT_UDP
*
* @param pay
* The Payload
* @param proto
* The Protocol
*/
public static void setProtocol(Payload pay, byte proto)
{
int i = pay.ipHeader[2] & 0xFF00FFFF;
pay.ipHeader[2] = i | ((proto & 0xFF) << 16);
}
/**
* Get the Header Checksum. The checksum is calculated over the IP Header.
*
* @param pay
* The Payload
* @return The Header Checksum
*/
public static short getChecksum(Payload pay)
{
return (short) (pay.ipHeader[2] & 0xFFFF);
}
/**
* Set the Header Checksum to the correct value. The checksum is calculated
* over the IP Header (with the checksum field assumed to be zero). The
* calculation is done in {@link IPPacket#calculateChecksum}.
*
* @param pay
* The Payload
*/
public static void setChecksum(Payload pay)
{
pay.ipHeader[2] = pay.ipHeader[2] & 0xFFFF0000;
pay.ipHeader[2] = pay.ipHeader[2] | (calculateChecksum(pay) & 0xFFFF);
}
/**
* Get the Source address. The IP address the Packet originated from.
*
* @param pay
* The Payload
* @return The Source address as 32-bit value
*/
public static int getSrcAddr(Payload pay)
{
return pay.ipHeader[3];
}
/**
* Set the Source address. The IP address the Packet originated from.
*
* @param pay
* The Payload
* @param addr
* The Source address as 32-bit value
*/
public static void setSrcAddr(Payload pay, int addr)
{
pay.ipHeader[3] = addr;
}
/**
* Get the Destination address. The IP address the Packet is headed to.
*
* @param pay
* The Payload
* @return The Destination address as 32-bit value
*/
public static int getDestAddr(Payload pay)
{
return pay.ipHeader[4];
}
/**
* Set the Destination address. The IP address the Packet is headed to.
*
* @param pay
* The Payload
* @param addr
* The Destination address as 32-bit value
*/
public static void setDestAddr(Payload pay, int addr)
{
pay.ipHeader[4] = addr;
}
/**
* Calculate the correct Checksum. The checksum is calculated over the IP
* Header (with the checksum field assumed to be zero).
*
* @param pay
* The Payload
* @return The Checksum
*/
public static short calculateChecksum(Payload pay)
{
int i;
int ofs = 0;
int sum = 0;
byte cnt = getIHL(pay);
while (cnt != 0)
{
i = pay.ipHeader[ofs];
sum += i & 0xffff;
sum += i >>> 16;
++ofs;
--cnt;
}
while ((sum >> 16) != 0)
sum = (sum & 0xffff) + (sum >> 16);
sum = (~sum) & 0xffff;
return (short) sum;
}
/**
* Check whether the checksum is valid.
*
* @param pay
* The Payload
* @return Whether the checksum is valid.
*/
public static boolean isChecksumValid(Payload pay)
{
return calculateChecksum(pay) == 0; // Checksum with checksum field
// correctly set should equal 0
}
/**
* Check whether the Packet is valid. Checks the checksum and whether the
* Reserved Flag is cleared.
*
* @param pay
* The Payload
* @return Whether the Packet is valid.
*/
public static boolean isValidPacket(Payload pay)
{
return (!isReservedSet(pay) && isChecksumValid(pay));
}
}