tcpiputils/networkaddressandporttranslation/src/icmp.cpp
changeset 0 af10295192d8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/networkaddressandporttranslation/src/icmp.cpp	Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,611 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// napt.cpp
+// implementation of ICMP tranlation
+// 
+//
+
+/**
+ @file
+ @internalTechnology 
+*/
+
+#include "hookdefs.h"
+#include <e32std.h>
+#include <in6_opt.h>
+#include <udp_hdr.h>
+#include <icmp6_hdr.h>
+#include <udp_hdr.h>
+#include <in_pkt.h>
+#include <ext_hdr.h>
+#include <in_chk.h>
+#include <tcp_hdr.h>
+#include <icmp6_hdr.h>
+#include "naptlog.h"
+#include "panic.h"
+#include "napt_ini.h"
+#include <posthook.h>
+
+
+/*
+*----------------------------------------------------------------------------------------
+*						ICMP FILE
+*  Every ICMP message is supported except ICMP Redirect message. NAPT will not temper
+*  Other messages are taken care.
+*------------------------------------------------------------------------------------------
+*/
+
+
+TInt CProtocolNaptIn::IcmpHandler(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
+/* This Function will manipulate ICMP packets. It will handle two ICMP cases.
+ * First ping request.
+ * Second is Destination unreachable
+ * @param aPacket
+ * @param aInfo
+*/
+	{
+	TUint lSrcPort;
+    // This flag states that packets have been translated and that KIp6Hook_DONE should be used as return value
+	TBool translatedFlag = EFalse;
+
+	TInet6Checksum<TInet6HeaderIP4> lIp(aPacket);
+	TInt lengthIP	= lIp.iHdr->HeaderLength();
+    
+	//Obtain ICMP packet for checking error type 
+    TInet6Checksum<TInet6HeaderICMP_Echo> lIcmpIn(aPacket,lengthIP);
+    TUint type = lIcmpIn.iHdr->Type();
+	
+	//query identifier for particular ICMP echo reply
+    TUint16 queryId = lIcmpIn.iHdr->Identifier();
+	
+	const CNaptIPPortMap* table= NULL;
+	TNaptConfigInfo* info = NULL;
+ 
+	switch(type)
+		{
+			case KInet4ICMP_TimeStampReply:
+				LOG(Log::Printf(_L("ICMP type is time stamp reply ")));
+			case KInet4ICMP_EchoReply:
+						
+				LOG(Log::Printf(_L("ICMP type is PING response ")));
+
+				//check whether translation is required or not.Result should be KErrNone
+				table =iNapt->iNaptMapMgr.GetIPTranslationNode(queryId);
+
+		    	if (table)
+		    		{
+		    		lIcmpIn.iHdr->SetIdentifier(table->iSrcPort); //Store Original Query Id from node
+		    		info = table->iConfigInfo; //Store Config info in the local pointer
+		    	
+		    		//recompute checksum as we have changed query id
+		    		lIcmpIn.ComputeChecksum(aPacket,NULL);
+		    	    		
+		    	  	//Take original IP which is translated by NAPT.
+		 			TUint32 originalIP;
+			  		originalIP=table->iSrcIpAddr;
+			            
+		            //Set destination IP to the Original IP which was translated
+		            lIp.iHdr->SetDstAddr(originalIP);
+		            TInetAddr::Cast(aInfo.iDstAddr).SetV4MappedAddress(originalIP);
+
+					//This will set source scope i,e networkID as zero this will allow incoming hook to set scope 
+					//by itself.
+
+		            lIp.ComputeChecksum();
+		            translatedFlag = ETrue;
+		            
+		    		}
+		    	break;
+				
+			case KInet4ICMP_SourceQuench:
+
+		 	case KInet4ICMP_TimeExceeded:
+				//IcmpHandlerTracert return type is TBool, which is same as TInt, hence it the return value is 
+				//directly assigned to translatedFlag. Any change in return value (other than 0 and 1), 
+				//this assginment have to be revisited.
+		 	   translatedFlag =	IcmpHandlerTracert(aPacket, aInfo, &info);
+		 		break;
+
+				
+			case KInet4ICMP_ParameterProblem:
+			
+			case KInet4ICMP_Unreachable:
+				LOG(Log::Printf(_L("my type id is %d"),type));
+
+/*------------------------------------------------------------------------------------				
+*			 	ICMP destination Unreachable packet format.
+*				
+*					-------------------------------------------------
+*			        |	OUTER	|ICMP	|INNER	|UDP		|PAYLOAD|
+*				    |	IP		|HEADER	|IP     |           |       |
+*				    |	HEADER	|		|header |HEADER		|		|
+*					-------------------------------------------------
+*
+*  Rare case TYPE 3 CODE 4..NAPT not required 
+*
+*From RFC 1191 for use when the code is set to 4: 
+*when a router is unable to forward a datagram because it exceeds the MTU of the 
+*next-hop network and its Don't Fragment bit is set, the router is required to 
+*return an ICMP Destination Unreachable message to the source of the datagram,
+*with the Code indicating "fragmentation needed and DF set". 
+*To support the Path MTU Discovery technique specified in this memo, 
+*the router MUST include the MTU of that next-hop network in the low-order 16 bits of
+*the ICMP header field that is labelled "unused" in the ICMP specification.
+*The high-order 16 bits remain unused, and MUST be set to zero....
+*The size in bytes of the largest datagram that could be forwarded, 
+*along the path of the original datagram, without being fragmented at this
+*router. The size includes the IP header and IP data, and does not include 
+*any lower-level headers. This field will never contain a value less than 
+*68 since every router must be able to forward a 68 byte datagram without 
+*fragmentation.
+---------------------------------------------------------------------------------------
+*/
+	
+				//Split ICMP destnation Unreachable packet.
+				RMBufChain payload;
+				aPacket.SplitL(lengthIP, payload); 
+				
+				TInet6Checksum<TInet6HeaderICMP> lIcmpIn(payload);
+
+				TInt code = lIcmpIn.iHdr->Code();
+				TInt lenHeader=0;
+     		    if(code==KInet4ICMP_CODE_DF)
+     		    	{
+     		    	//rare case TYPE 3, CODE 4 dont need NAPT.Since there is not Transport header
+			 		LOG(
+						TBuf<70> tmpSrc;
+						TBuf<70> tmpDst;
+						TInetAddr::Cast(aInfo.iSrcAddr).OutputWithScope(tmpSrc);
+						TInetAddr::Cast(aInfo.iDstAddr).OutputWithScope(tmpDst);
+						LOG(Log::Printf(_L("\t I am ICMP packet dont reqquire NAPT \n src=[%S] dst=[%S] ICMP code =%d"), &tmpSrc, &tmpDst,code,type));
+						);
+
+     		    	aPacket.Append(payload);
+     		    	return KIp6Hook_PASS;
+     		    	}
+     		    
+     		    
+     		    //Length of ICMP header + 4 is size of Empty + next Hop MTU
+				lenHeader= lIcmpIn.iHdr->HeaderLength() + 4 ;
+				
+				//Inner IP header
+				TInet6Checksum<TInet6HeaderIP4> lIpIn(payload, lenHeader);
+				lenHeader += lIpIn.iHdr->HeaderLength();
+			
+				//Find transport protocol it is using.According to this Translation will be made.
+				TInt transport;
+				transport=lIpIn.iHdr->Protocol();
+
+				LOG(Log::Printf(_L("I am using protocol=%d for communication and my destination is unreachable"),transport));
+				if(transport==KProtocolInetUdp)
+					{
+				
+					//Inner UDP header.
+					TInet6Packet<TInet6HeaderUDP> lUdpIn(payload,lenHeader);
+				
+					//check if header length is appropriate
+					if(lUdpIn.iHdr==NULL)
+						{
+						LOG(Log::Printf(_L("Insuffient header length")));
+						aPacket.Append(payload);
+						return KIp6Hook_PASS;
+						}
+					lenHeader += lUdpIn.iHdr->HeaderLength();
+					lSrcPort = lUdpIn.iHdr->SrcPort();
+		 
+		 			//Check if there is an entry in the translation table.
+					table = iNapt->iNaptMapMgr.GetIPTranslationNode(lSrcPort);
+					
+					
+					if(table)
+						{
+			    	  	TUint32 originalIP;
+			    	  	originalIP = table->iSrcIpAddr;
+			    	  	TUint originalPort = table->iSrcPort;
+			    	  	info = table->iConfigInfo;
+
+						lIp.iHdr->SetDstAddr(originalIP);
+		            
+		                //Translate inner IP information
+						lIpIn.iHdr->SetSrcAddr(originalIP);
+						lIpIn.ComputeChecksum();
+					
+						//Translate inner Port			
+						lUdpIn.iHdr->SetSrcPort(originalPort);
+					
+					
+						lUdpIn.iHdr->SetChecksum(0);
+			           
+			   			
+			            TInetAddr::Cast(aInfo.iDstAddr).SetV4MappedAddress(originalIP);
+						
+						//This will set source scope i,e networkID of private Interface this will allow incoming hook to set scope 
+						//by itself.
+						lIp.ComputeChecksum();
+		 	            translatedFlag = ETrue;
+
+						}
+				
+					aPacket.Append(payload);
+					//NULL argument id for ICMP v4 packets	
+					lIcmpIn.ComputeChecksum(aPacket,NULL,NULL);
+
+				    }//Protocol UDP if
+			
+				else if(transport==KProtocolInetTcp)
+					{
+					//Tcp Header
+					TInet6Checksum<TInet6HeaderTCP> lTcpIn(payload, lenHeader);
+					//check if header length is appropriate
+					if(lTcpIn.iHdr==NULL)
+						{
+						LOG(Log::Printf(_L("Insuffient header length rare case type 3 code 4")));
+						aPacket.Append(payload);
+						return KIp6Hook_PASS;
+						}
+
+					lenHeader += lTcpIn.iHdr->HeaderLength();
+					lSrcPort = lTcpIn.iHdr->SrcPort();
+
+					//check whether packet need translation...
+					table =iNapt->iNaptMapMgr.GetIPTranslationNode(lSrcPort);
+					
+					if(table)
+						{
+			    	  	TUint32 originalIP;
+			    	  	originalIP =table->iSrcIpAddr;
+			    	  	TUint originalPort = table->iSrcPort;
+			    	  	info = table->iConfigInfo;
+						
+						//outer IP header...
+						lIp.iHdr->SetDstAddr(originalIP);
+						
+						//Translate Inner IP header...
+						lIpIn.iHdr->SetSrcAddr(originalIP);
+						lIpIn.ComputeChecksum();
+										
+						//Translate Port....
+						lTcpIn.iHdr->SetSrcPort(originalPort);
+			   	
+			   	
+			   			//this one is to avoid armv5 errors and calculate checksum right
+						RMBufChain& payload = static_cast<RMBufChain&>(aPacket);	   	
+			   			lTcpIn.ComputeChecksum(payload,&aInfo,aInfo.iOffset);
+			
+			            TInetAddr::Cast(aInfo.iDstAddr).SetV4MappedAddress(originalIP);
+			
+
+						lIp.ComputeChecksum();
+			            translatedFlag = ETrue;
+
+		 				}
+					aPacket.Append(payload);
+					//NULL argument id for ICMP v4 packets
+				 	lIcmpIn.ComputeChecksum(aPacket,NULL,NULL);
+					}//Protocol TCP if
+				break;	
+	 		}//Switch end
+	if(translatedFlag)
+		{
+		aInfo.iFlags &= ~KIpAddressVerified;
+		LOG(
+			TBuf<70> tmpSrc;
+			TBuf<70> tmpDst;
+			TInetAddr::Cast(aInfo.iSrcAddr).OutputWithScope(tmpSrc);
+			TInetAddr::Cast(aInfo.iDstAddr).OutputWithScope(tmpDst);
+			LOG(Log::Printf(_L("\t I am translated ICMP packet \n src=[%S] dst=[%S] proto=%d"), &tmpSrc, &tmpDst, aInfo.iProtocol));
+			);
+
+	    // Setting the scope to 0 will cause the stack to automatically fill in the correct scope itself
+		TInetAddr::Cast(aInfo.iSrcAddr).SetScope(0);
+
+		//Setting Network ID of private Interfae as a scope. Route will be searched according 
+		//to the Destination Id which is set as the scope of private interface.
+		TInetAddr::Cast(aInfo.iDstAddr).SetScope(info->iScopeSrc);
+		
+		return KIp6Hook_DONE;	
+		}
+	
+	return KIp6Hook_PASS;
+
+	}
+	
+	
+void CProtocolNapt::IcmpHandlerForward(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
+/* This Function will manipulate ICMP packets. It will handle two ICMP cases.
+ * First ping request.
+ * @param aPacket
+ * @param aInfo
+*/
+	{
+		
+    LOG(Log::Printf(_L(" CProtocolNapt::IcmpHandlerForwardL called for out going packets to global interface")));
+
+	//retrieve information from aInfo. This information will be maintained in the transation 
+	//table.
+ 	TUint32 sourceIP = (TInetAddr::Cast(aInfo.iSrcAddr)).Address();
+    TUint32 destinationIP =(TInetAddr::Cast(aInfo.iDstAddr)).Address();
+    const TUint32 targetIP= iCurConfigInfo->iPublicGatewayIP.Address();
+	
+	//IP packet.lengthIP is the length of IP header.
+	TInet6Checksum<TInet6HeaderIP4> lIp(aPacket);
+	TInt lengthIP	= lIp.iHdr->HeaderLength();
+    
+	//Obtain ICMP packet. 
+    TInet6Checksum<TInet6HeaderICMP_Echo> lIcmpIn(aPacket,lengthIP);
+    TUint type = lIcmpIn.iHdr->Type();
+    
+	//check if the type is ECHO i.e. 8. Then only translate else just pass packets.
+    switch(type)
+	    {
+		
+    case KInet4ICMP_TimeStamp:
+    
+	case KInetICMP_Information_Request:
+	
+	case KInet4ICMP_AddressMask_Request:
+
+	case KInet4ICMP_DNS_Request:
+	    
+    case KInet4ICMP_Echo :
+		LOG(Log::Printf(_L("my type id is %d"),type));
+
+	    TUint16 orgQueryId = lIcmpIn.iHdr->Identifier();
+
+		const CNaptIPPortMap* table=NULL;
+
+		//Finds  Translation Node,if already existing or creates  a new node filled with unique translated port number for 
+		//translated IP for TCP/UDP/ICMP connections.  
+		TRAPD(ret,table=iNaptMapMgr.FindOrCreateNaptEntryL(KProtocolInetIcmp ,sourceIP, destinationIP,orgQueryId ,0, iCurConfigInfo));
+	
+		if(table==NULL || (ret== KErrNoMemory))
+			{
+			LOG(Log::Printf(_L("No entry for table ")));
+			return;
+			}
+			
+		//set new Query Id -extract which is set in table node
+		lIcmpIn.iHdr->SetIdentifier(table->iTrPort)	;
+		//recompute checksum as we have changed QueryId in IcmpEchoRequest packet.
+		lIcmpIn.ComputeChecksum(aPacket, NULL);
+						
+		lIp.iHdr->SetSrcAddr(targetIP);
+	    TInetAddr::Cast(aInfo.iSrcAddr).SetV4MappedAddress(targetIP);
+
+	    // Setting the scope to 0 will cause the stack to automatically fill in the correct scope itself
+		TInetAddr::Cast(aInfo.iSrcAddr).SetScope(0);
+
+		//Setting Network ID of desired interface as a scope. Route will be searched according 
+		//to the Destination Id which is set as the scope of desired interface.
+		TInetAddr::Cast(aInfo.iDstAddr).SetScope(iCurConfigInfo->iScopedest);
+		LOG(
+			TBuf<70> tmpSrc;
+			TBuf<70> tmpDst;
+			TInetAddr::Cast(aInfo.iSrcAddr).OutputWithScope(tmpSrc);
+			TInetAddr::Cast(aInfo.iDstAddr).OutputWithScope(tmpDst);
+			LOG(Log::Printf(_L("\t I am translated ICMP packet OutBound \n src=[%S] dst=[%S] proto=%d"), &tmpSrc, &tmpDst, aInfo.iProtocol));
+			);
+
+		//Compute checksum
+		lIp.ComputeChecksum();
+		aInfo.iFlags &= ~KIpAddressVerified;
+		break;
+        }
+	}
+
+
+TInt CProtocolNaptIn::IcmpHandlerTracert(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo, TNaptConfigInfo** aConfigInfo)
+/*
+------------------------------------------------------------------------------------------------
+*				Packet format for ICMP type 11(Time exceeded message)
+*				
+*				 -------------------------------------------------------
+*				|IP 	|ICMP	 	|IP			| ICMP					|
+*				|Header	|Header	 	|Header		| Header				|
+*				|		|Type =11	|			| Type = 8(ping request)|
+*				 -------------------------------------------------------
+*	The internet header plus the first 8 bytes of the original datagram's data is returned to the sender. 
+*	This data is used by the host to match the message to the appropriate process.
+*	If a higher level protocol uses port numbers, they are assumed to be in the first 64 data bits of the original datagram's data.
+*
+*	Tracert could be a application.Clients can send UDP packets for tracert.64 bits(8bytes)might contain transport header.
+*	
+*
+*				 -------------------------------------------------------
+*				|IP 	|ICMP	 	|IP			| 	64 bits of data 	|
+*				|Header	|Header	 	|Header		| 	which could contain	|
+*				|		|Type =11	|			| 	port)				|
+*				 -------------------------------------------------------
+*
+*
+-------------------------------------------------------------------------------------------------
+*/
+	{
+	//source port of the packet
+	TUint lSrcPort;
+	
+	const CNaptIPPortMap* table= NULL;
+	
+	//IP header,this header will be outer most header of the packet. Take header length 
+	//and split packet.
+	TInet6Checksum<TInet6HeaderIP4> lIp(aPacket);
+	TInt lengthIP	= lIp.iHdr->HeaderLength();
+	
+    // This flag states that packets have been translated and that KIp6Hook_DONE should be used as return value
+	TBool translatedFlag= EFalse;
+
+	//Split packet and seperate outer IP and ICMP
+	RMBufChain payload;
+	aPacket.SplitL(lengthIP, payload); 
+
+
+	TInet6Checksum<TInet6HeaderICMP> lIcmpTem(payload);
+
+	//Length of ICMP header + 4 is size of Empty + next Hop MTU
+	TInt headerLen = lIcmpTem.iHdr->HeaderLength() + 4 ;
+
+	//Inner IP header
+	TInet6Checksum<TInet6HeaderIP4> lIpInternal(payload, headerLen);
+	headerLen += lIpInternal.iHdr->HeaderLength();
+	
+	//Find whether after inner header there is transport header
+	TInt transport= lIpInternal.iHdr->Protocol();
+	
+	if(transport==KProtocolInetUdp)
+		{
+		//Inner UDP header.
+		TInet6Packet<TInet6HeaderUDP> lUdpIn(payload,headerLen);
+
+		//check if header length is appropriate
+		if(lUdpIn.iHdr==NULL)
+			{
+			LOG(Log::Printf(_L("Insuffient header length")));
+			aPacket.Append(payload);
+			return KIp6Hook_PASS;
+			}
+		headerLen += lUdpIn.iHdr->HeaderLength();
+		lSrcPort = lUdpIn.iHdr->SrcPort();
+
+		//Check if there is an entry in the translation table.
+		table = iNapt->iNaptMapMgr.GetIPTranslationNode(lSrcPort);
+
+		if(table)
+			{
+			TUint32 originalIP;
+			originalIP = table->iSrcIpAddr;
+			TUint originalPort = table->iSrcPort;
+			*aConfigInfo = table->iConfigInfo;
+
+			lIp.iHdr->SetDstAddr(originalIP);
+
+			//Translate inner IP information
+			lIpInternal.iHdr->SetSrcAddr(originalIP);
+			lIpInternal.ComputeChecksum();
+
+			//Translate inner Port			
+			lUdpIn.iHdr->SetSrcPort(originalPort);
+
+
+			lUdpIn.iHdr->SetChecksum(0);
+
+			TInetAddr::Cast(aInfo.iDstAddr).SetV4MappedAddress(originalIP);
+
+			//This will set source scope i,e networkID of private Interface this will allow incoming hook to set scope 
+			//by itself.
+			lIp.ComputeChecksum();
+			translatedFlag = ETrue;
+			}
+		//Append splitted packet.Means join outer IP and ICMP.
+		aPacket.Append(payload);
+	
+		//NULL argument id for ICMP v4 packets	
+		lIcmpTem.ComputeChecksum(aPacket,NULL,NULL);
+
+		}//Protocol UDP if
+
+	else if(transport==KProtocolInetTcp)
+		{
+		//Tcp Header
+		TInet6Checksum<TInet6HeaderTCP> lTcpIn(payload, headerLen);
+		//check if header length is appropriate
+		if(lTcpIn.iHdr==NULL)
+			{
+			LOG(Log::Printf(_L("Insuffient header length")));
+			aPacket.Append(payload);
+			return KIp6Hook_PASS;
+			}
+
+		headerLen += lTcpIn.iHdr->HeaderLength();
+		lSrcPort = lTcpIn.iHdr->SrcPort();
+
+		//check whether packet need translation...
+		table =iNapt->iNaptMapMgr.GetIPTranslationNode(lSrcPort);
+
+		if(table)
+			{
+			TUint32 originalIP;
+			originalIP =table->iSrcIpAddr;
+			TUint originalPort = table->iSrcPort;
+            *aConfigInfo = table->iConfigInfo;
+			//outer IP header...
+			lIp.iHdr->SetDstAddr(originalIP);
+
+			//Translate Inner IP header...
+			lIpInternal.iHdr->SetSrcAddr(originalIP);
+			lIpInternal.ComputeChecksum();
+						
+			//Translate Port....
+			lTcpIn.iHdr->SetSrcPort(originalPort);
+
+
+			//this one is to avoid armv5 errors and calculate checksum right
+			RMBufChain& payload = static_cast<RMBufChain&>(aPacket);	   	
+			lTcpIn.ComputeChecksum(payload,&aInfo,aInfo.iOffset);
+
+			TInetAddr::Cast(aInfo.iDstAddr).SetV4MappedAddress(originalIP);
+
+
+			lIp.ComputeChecksum();
+			translatedFlag = ETrue;
+
+			}
+		aPacket.Append(payload);//Append splitted packet.Means join outer IP and ICMP.
+		//NULL argument id for ICMP v4 packets
+		lIcmpTem.ComputeChecksum(aPacket,NULL,NULL);
+		}//Protocol TCP if
+	else
+		{
+		TInet6Checksum<TInet6HeaderICMP_Echo> lIcmpPingHeader(payload, headerLen);
+
+		TUint16 queryId = lIcmpPingHeader.iHdr->Identifier();
+
+		table =iNapt->iNaptMapMgr.GetIPTranslationNode(queryId);
+
+		if(table)
+			{
+			TUint32 originalIP;
+			originalIP =table->iSrcIpAddr;
+            *aConfigInfo = table->iConfigInfo;
+			//outer IP header...
+			lIp.iHdr->SetDstAddr(originalIP);
+
+			//Translate Inner IP header...
+			lIpInternal.iHdr->SetSrcAddr(originalIP);
+			lIpInternal.ComputeChecksum();
+
+			lIp.ComputeChecksum();
+			translatedFlag = ETrue;
+
+			lIcmpPingHeader.ComputeChecksum(aPacket,NULL,NULL);
+			}
+		//Append splitted packet.Means join outer IP and ICMP.
+		aPacket.Append(payload);
+		lIcmpTem.ComputeChecksum(aPacket,NULL,NULL);
+
+	}//ICMP else
+	return translatedFlag;	
+
+}
+
+
+
+
+
+
+
+
+
+
+
+