/*
* 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;
import ejip.jtcpip.util.Debug;
/**
* Class to handle ICMP packets.
*
* @author Ulrich Feichter
* @author Tobias Kellner
* @author Christof Rath
* @version $Rev: 984 $ $Date: 2007/01/24 19:37:07 $
*/
class ICMP
{
/** 0 */
protected final static byte TYPE_ECHO_REPLY = 0;
/** 3: Destination unreachable */
protected final static byte TYPE_DEST_UNREACH = 3;
/** 4: Source quench */
protected final static byte TYPE_SRC_QUENCH = 4;
/** 8 */
protected final static byte TYPE_ECHO = 8;
/** 11: Time exceeded */
protected final static byte TYPE_TIME_EXCEEDED = 11;
/**
* Answers to an incoming ICMP ECHO.
*
* @param pay
*/
private static void answerToEcho(Payload pay)
{
// if (Debug.enabled)
// Debug.println("ECHO REPLY to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP);
if (Debug.enabled)
Debug.println("ECHO REPLY", Debug.DBG_ICMP);
ICMPPacket.setType(pay, TYPE_ECHO_REPLY);
IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP);
}
/**
* Answers ICMP DESTINATION UNREACHABLE.
*
* @param pay
* @param code
*/
protected static void sendDestUnreach(Payload pay, int code)
{
// if (Debug.enabled)
// Debug.println("DEST UNREACHABLE to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP);
if (Debug.enabled)
Debug.println("DEST UNREACHABLE", Debug.DBG_ICMP);
ICMPPacket.ipToICMPPacket(pay);
ICMPPacket.setType(pay, ICMP.TYPE_DEST_UNREACH);
ICMPPacket.setCode(pay, code);
IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP);
}
/**
* Answers ICMP SOURCE QUENCHE.
*
* TODO: call this function if we have to close the TCP window
*
* @param pay
*/
protected static void sendSrcQuenche(Payload pay)
{
// if (Debug.enabled)
// Debug.println("SOURCHE QUENCHE to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP);
if (Debug.enabled)
Debug.println("SOURCHE QUENCHE ", Debug.DBG_ICMP);
ICMPPacket.ipToICMPPacket(pay);
ICMPPacket.setType(pay, ICMP.TYPE_SRC_QUENCH);
IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP);
}
/**
* Answers ICMP TIME EXCEEDED.
*
* @param pay
*/
protected static void sendTimeExceeded(Payload pay)
{
// if (Debug.enabled)
// Debug.println("TIME EXCEEDED to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP);
if (Debug.enabled)
Debug.println("TIME EXCEEDED ", Debug.DBG_ICMP);
ICMPPacket.ipToICMPPacket(pay);
ICMPPacket.setType(pay, ICMP.TYPE_TIME_EXCEEDED);
ICMPPacket.setCode(pay, 1); // 1: fragment reassembly time exceeded.
IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP);
}
/**
* By now we just print (if Debug.enabled == true) the information, that an IP packet
* hasn't reached its destination.
*
* TODO: do something if one of our IP packets has not reached its destination
*
* @param pay
*/
private static void handleDestUnreach(Payload pay)
{
byte code = ICMPPacket.getCode(pay);
ICMPPacket.icmpToIPPacket(pay);
if (Debug.enabled)
switch (code)
{
case 0: // net unreachable;
Debug.println("The network of the IP address ",Debug.DBG_ICMP);
// + IP.ipIntToString(IPPacket.getDestAddr(pay)) + " is unreachable",
// Debug.DBG_ICMP);
break;
case 1: // host unreachable;
Debug.println("The host with the IP address ",Debug.DBG_ICMP);
// + IP.ipIntToString(IPPacket.getDestAddr(pay)) + " is unreachable",
// Debug.DBG_ICMP);
break;
case 2: // protocol unreachable;
Debug.println("The protocol " ,Debug.DBG_ICMP);
// + IPPacket.getProtocol(pay) + "is unreachable",
// Debug.DBG_ICMP);
break;
case 3: // port unreachable;
Debug.println("The port IP address ",Debug.DBG_ICMP);
// + IP.ipIntToString(IPPacket.getDestAddr(pay))
// + ":" + UDPPacket.getDestPort(pay) + " is unreachable", Debug.DBG_ICMP);
break;
case 4: // fragmentation needed and DF set;
Debug.println("Fragmentation is needed but the Don't Fragment flag is set",
Debug.DBG_ICMP);
break;
case 5: // source route failed.
Debug.println("Source route failed", Debug.DBG_ICMP);
break;
}
}
/**
* Handles an incoming ICMP packet.
*
* @param pay
*/
protected static void receivePayload(Payload pay)
{
if (Debug.enabled)
Debug.println("ICMP received",Debug.DBG_ICMP);
// Debug.println("Type: " + ICMPPacket.getType(pay) + " Code: " + ICMPPacket.getCode(pay), Debug.DBG_ICMP);
switch (ICMPPacket.getType(pay))
{
case TYPE_ECHO:
answerToEcho(pay);
break;
case TYPE_DEST_UNREACH:
handleDestUnreach(pay);
Payload.freePayload(pay);
break;
default:
if (Debug.enabled)
Debug.println("Datagram unhandled...", Debug.DBG_ICMP);
Payload.freePayload(pay);
}
}
}