package com.intrbiz.bergamot.net.raw.model.payload;
import java.nio.ByteBuffer;
import com.intrbiz.bergamot.net.raw.model.IPPayload;
/**
* Basic structure of an ICMP packet
*/
public class ICMPPacket implements IPPayload
{
/* Useful constants */
public static final byte ICMP_TYPE_ECHO = 8;
public static final byte ICMP_TYPE_REPLY = 0;
public static final byte[] DEFAULT_DATA = createDefaultData();
private static final byte[] createDefaultData()
{
byte[] data = new byte[56];
for (int i = 0; i < data.length; i ++)
{
data[i] = 0x1B;
}
return data;
}
/* ICMP packet header - 8 bytes*/
private byte type;
private byte code;
private short checksum;
private short id;
private short sequence;
/* ICMP packet data */
private byte[] data;
public ICMPPacket()
{
super();
}
public ICMPPacket(byte type, short id, short seq)
{
super();
this.type = type;
this.id = id;
this.sequence = seq;
this.data = DEFAULT_DATA;
}
public ICMPPacket(ByteBuffer from)
{
super();
// verify the checksum
this.checksum = this.verifyChecksum(from);
// decode
this.type = from.get();
this.code = from.get();
/* checksum */ from.getShort();
this.id = from.getShort();
this.sequence = from.getShort();
this.data = new byte[from.remaining()];
from.get(this.data);
}
public int computeLength()
{
return 8 + (this.data == null ? 0 : this.data.length);
}
public void pack(ByteBuffer to)
{
int start = to.position();
// pack
to.put(this.type);
to.put(this.code);
to.putShort((short) /* checksum */ 0);
to.putShort(this.id);
to.putShort(this.sequence);
// data
to.put(this.data);
// compute checksum
int end = to.position();
to.limit(end);
to.position(start);
short checksum = this.computeChecksum(to);
to.putShort(start + 2, checksum);
to.position(end);
}
private short computeChecksum(ByteBuffer buffer)
{
int start = buffer.position();
// ensure the checksum is zeroed
buffer.putShort(start + 2, (short) 0);
// compute
int sum = 0;
while (buffer.remaining() > 1)
{
sum += ((int) buffer.getShort()) & 0xFFFF;
}
// handle any remaining single byte value
if (buffer.hasRemaining())
{
// odd sized packet
sum += ((((int) buffer.get()) & 0xFF) << 8);
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum = (sum >> 16) + (sum & 0xFFFF);
// reset to start of the payload
buffer.position(start);
return (short) ((~sum) & 0xFFFF);
}
private short verifyChecksum(ByteBuffer buffer)
{
int start = buffer.position();
// get the checksum
short checksum = buffer.getShort(start + 2);
// compute the checksum
short computedChecksum = this.computeChecksum(buffer);
// verify
if (checksum != computedChecksum) throw new RuntimeException("Invalid ICMP Checksum");
return checksum;
}
public byte getType()
{
return type;
}
public void setType(byte type)
{
this.type = type;
}
public byte getCode()
{
return code;
}
public void setCode(byte code)
{
this.code = code;
}
public short getChecksum()
{
return checksum;
}
public void setChecksum(short checksum)
{
this.checksum = checksum;
}
public short getId()
{
return id;
}
public void setId(short id)
{
this.id = id;
}
public short getSequence()
{
return sequence;
}
public void setSequence(short sequence)
{
this.sequence = sequence;
}
public byte[] getData()
{
return data;
}
public void setData(byte[] data)
{
this.data = data;
}
public String toString()
{
return "icmp-packet {\n" +
"type: " + this.getType() + "\n" +
"code: " + this.getCode() + "\n" +
"cksm: " + this.getChecksum() + "\n" +
"id: " + this.getId() + "\n" +
"seq: " + this.getSequence() + "\n" +
"}";
}
}