tcpiputils/networkaddressandporttranslation/src/translationtable.cpp
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <e32base.h>
       
    17 #include <es_sock.h> // for BigEndian
       
    18 #include <e32hal.h>
       
    19 #include <icmp6_hdr.h>
       
    20 #include <ip4_hdr.h>
       
    21 #include "translationtable.h"
       
    22 #include "hookdefs.h"
       
    23 #include "naptconfigtable.h"
       
    24 
       
    25 
       
    26 
       
    27 //NAPT Translation Table class Constructor
       
    28 CNaptIPPortMap *CNaptIPPortMap:: NewL()
       
    29 	{
       
    30 	CNaptIPPortMap *self = new(ELeave)  CNaptIPPortMap;
       
    31 	return self;
       
    32 	}
       
    33 
       
    34 //NAPT Translation Table class Destructor
       
    35 CNaptIPPortMap::~CNaptIPPortMap()
       
    36 	{}
       
    37 	
       
    38 	
       
    39 //NAPT Translation Table Manager Constructor..
       
    40 TNaptTableMapMgr::TNaptTableMapMgr()
       
    41 	{
       
    42 	iIcmpQueryId = KNaptIcmpQuery_HIGH;
       
    43 	iLastPort 	 = KNaptPort_HIGH;
       
    44 	iBucketsInUse= 0;
       
    45 	iPublicGatewayIP=0;
       
    46 	}
       
    47 
       
    48 //NAPT Translation Table Manager Destructor..
       
    49 TNaptTableMapMgr::~TNaptTableMapMgr()
       
    50 	{ }
       
    51 
       
    52 CNaptIPPortMap* TNaptTableMapMgr::GetIPTranslationNode(TUint16 aDstPortNo)
       
    53 	/**
       
    54 	* Gets the translated ip & port number information 
       
    55 	* Mainly used in incoming packet conversion
       
    56 	@internalTechnology
       
    57 	@param aTrDstPort  	- Unique Translated Port Information
       
    58 	*
       
    59 	**/ 
       
    60 	{
       
    61 	TInt bucket = FindBucket(aDstPortNo);
       
    62 	CNaptIPPortMap* table = NULL;
       
    63 	
       
    64 	TNaptTableIter naptTableIter(iIPPortMap[bucket]);
       
    65 	naptTableIter.SetToFirst();
       
    66 
       
    67  	 while ((table = naptTableIter++) != NULL)
       
    68  		{
       
    69  		if (table->iTrPort == aDstPortNo)
       
    70  			{
       
    71  			return table;
       
    72  			}
       
    73  		}//while
       
    74     
       
    75 	return NULL;
       
    76 	}
       
    77 
       
    78 
       
    79 CNaptIPPortMap* TNaptTableMapMgr::AllocateTranslationNodeL(TUint  aProtocolType,const TUint32& aSrcAddr,const TUint32& aDstAddr,const TUint16 aSrcPort ,const TUint16 aDstPort, const TNaptConfigInfo* aConfigInfo, TUint16 aQueryId)
       
    80 	/**
       
    81 	*Allocates Translation Node with a new unique translated port number for 
       
    82 	*translated IP for TCP/UDP connections.  
       
    83 	@param 	aProtocolType
       
    84 	@param  aSrcAddr
       
    85 	@param 	aDstAddr
       
    86 	@param 	aSrcPort
       
    87 	@param  aDstPort
       
    88       @param  aConfigInfo
       
    89 	@param	aQueryId
       
    90 	*
       
    91 	* The function is called only once when the first packet in the session passes 
       
    92 	* through NAPT hook.   
       
    93 	* The function is called only when the corresponding arguments are not present 
       
    94 	* anywhere in the indexed translation table list.  
       
    95 	* For TCP/UDP protocols the function generates new unique port number in the 
       
    96 	* predefined range.  The generated port is used as a key to index in the 
       
    97 	* translation table.  
       
    98 	* For ICMP packets like ICMP echo/reply(used in ping application), the function
       
    99 	* doesnot generates a port number, instead it uses the QueryId of the ICMP 
       
   100 	* message, ie the QueryId is used as the key to index the translation table.
       
   101 	*
       
   102 	* The index is generated based on the key  using the FindBucket Hash Function, 
       
   103 	* a new node is  linked to the indexed node.
       
   104 	*
       
   105 	* returns the filled CNaptIPPortMap Translated Node information.
       
   106 	**/
       
   107 	{
       
   108 	
       
   109 	TInt index =0;
       
   110 	CNaptIPPortMap *tableNode=NULL;
       
   111 	
       
   112 	if (iLastPort == KNaptPort_LOW) //lower range of the port
       
   113 		{
       
   114 		iLastPort = KNaptPort_HIGH;
       
   115 		}
       
   116 
       
   117 	
       
   118 	// we have to allocate memory..so we will allocate in the begining itself 
       
   119 	// fill all values except translated port number  
       
   120 	tableNode = CNaptIPPortMap::NewL();
       
   121 
       
   122 	tableNode->iCurTime= User::NTickCount();
       
   123 	tableNode->iProtocolType = aProtocolType;
       
   124 	tableNode->iSrcPort = aSrcPort;	//incase of ICMP echo request it stores original query id
       
   125 	tableNode->iDstPort = aDstPort;
       
   126 
       
   127 	//we should be knowing what tranlsated destination address to be filled
       
   128 	tableNode->iTrIpAddr  = iPublicGatewayIP; 
       
   129 	tableNode->iSrcIpAddr = aSrcAddr;
       
   130 	tableNode->iDstIpAddr = aDstAddr;
       
   131 	tableNode->iConfigInfo = const_cast<TNaptConfigInfo* >(aConfigInfo);	
       
   132 		
       
   133 	//for ICMP messages or If full indexed TranslationTable is Full
       
   134 	if (iBucketsInUse == KTranslationHashTableSize || aProtocolType == KProtocolInetIcmp) // table is full, 
       
   135 		{
       
   136 		TInt key;
       
   137 		if (aProtocolType == KProtocolInetIcmp)
       
   138 			{
       
   139 			key = aQueryId; 
       
   140 			}
       
   141 		else
       
   142 			{
       
   143 			key = iLastPort--;
       
   144 			}
       
   145 			
       
   146 	
       
   147 		tableNode->iTrPort = key;	
       
   148 		
       
   149 		index = FindBucket(key);
       
   150 		if (iIPPortMap[index].IsEmpty())
       
   151 			{
       
   152 			iBucketsInUse++;	
       
   153 			}
       
   154 		iIPPortMap[index].AddFirst(*tableNode);
       
   155 
       
   156 		}
       
   157 	else
       
   158 		{
       
   159 		
       
   160 		//following algorithm is the Open Addressing Algorithm for finding out the empty slot.
       
   161 		TInt tempCnt=0;
       
   162 
       
   163 		index = FindBucket(iLastPort);
       
   164 		while (! iIPPortMap[index].IsEmpty()  && (tempCnt <= iBucketsInUse) )
       
   165 			{
       
   166 			--iLastPort;   // decrementthe iLastPort, hope that next index generated will be empty in translation table.
       
   167 
       
   168 			if (iLastPort <= KNaptPort_LOW) //lower range of the port
       
   169 				{
       
   170 				iLastPort = KNaptPort_HIGH;
       
   171 				}
       
   172 		
       
   173 			++tempCnt;
       
   174 			index = FindBucket(iLastPort);
       
   175 		
       
   176 			}//while
       
   177 		
       
   178 			
       
   179 			//found an empty slot... from above loop
       
   180 			if (iIPPortMap[index].IsEmpty())
       
   181 				{
       
   182 				iBucketsInUse++;
       
   183 				}
       
   184 			iIPPortMap[index].AddFirst( *tableNode);
       
   185 			tableNode->iTrPort  = iLastPort--;
       
   186 		}//else	
       
   187 		
       
   188 	//time.. to start timer		
       
   189 	if (iBucketsInUse == 1 ) //time.. to start timer	
       
   190 		{
       
   191 		iTimerPtr->StartTimer();
       
   192 		}
       
   193 	return tableNode;
       
   194 
       
   195 	}
       
   196 	
       
   197 	
       
   198 CNaptIPPortMap* TNaptTableMapMgr::FindOrCreateNaptEntryL( TUint aProtocolType,const TUint32& aSrcAddr,const TUint32&  aDstAddr,const TUint16 aSrcPort,const TUint16 aDstPort, const TNaptConfigInfo *aConfigInfo)
       
   199 	/**
       
   200 	*Finds  Translation Node  if already existing or creates  a new node filled with unique translated port number for 
       
   201 	*translated IP for TCP/UDP/ICMP connections.  
       
   202 	@param 	aProtocolType- TCP/UDP/ICMP
       
   203 	@param  aSrcAddr - Source Address from which packet is originated
       
   204 	@param 	aDstAddr - Destination Address to which packet is destined
       
   205 	@param 	aSrcPort - Source Port from which packet is originated
       
   206 	@param  aDstPort - Destination Port to which packet is destined
       
   207       @param aConfigInfo - Configuration to be used for packet translation
       
   208 	*
       
   209 	* The function is called each time the packet needs translation passes through NAPT hook 
       
   210 	* Function First checks any NAPT table node exists with the matched arguments.
       
   211 	* If the node does not exist, creates a new node.
       
   212 	* returns the filled CNaptIPPortMap Translated Node information.
       
   213 	**/
       
   214 	{
       
   215 		CNaptIPPortMap *table=NULL;
       
   216 		for (TInt index=0;index<KTranslationHashTableSize;index++)
       
   217 			{
       
   218 
       
   219 			TNaptTableIter naptTableIter(iIPPortMap[index]);
       
   220 			naptTableIter.SetToFirst();
       
   221    		 	while ((table = naptTableIter++) != NULL)
       
   222         		{
       
   223         		if (table->iSrcPort == aSrcPort && table->iDstPort== aDstPort 
       
   224 				&& table->iProtocolType == aProtocolType 
       
   225 				&& table->iSrcIpAddr==aSrcAddr && table->iDstIpAddr==aDstAddr)
       
   226 					{
       
   227 					table->iCurTime = User::NTickCount();
       
   228 					return table;
       
   229 					}
       
   230 				}
       
   231 			}
       
   232 		//there is no entry in the translation table..make an entry..
       
   233 		if (aProtocolType == KProtocolInetIcmp)
       
   234 			{
       
   235 			if (iIcmpQueryId == KNaptIcmpQuery_LOW)
       
   236 				{
       
   237 				iIcmpQueryId=KNaptIcmpQuery_LOW;	
       
   238 				}
       
   239 			}
       
   240 		
       
   241 		table = AllocateTranslationNodeL(aProtocolType, aSrcAddr,aDstAddr,aSrcPort,aDstPort,aConfigInfo,iIcmpQueryId--);
       
   242 		
       
   243 		return table;
       
   244 	
       
   245 	}
       
   246 	
       
   247 void TNaptTableMapMgr::TimerComplete()
       
   248 	/**
       
   249 	*
       
   250 	*  Deletes the timed out transactions
       
   251 	*  Function is called after  timer expiry interval.  
       
   252 	*  If there are no entries present, Stop the Timer.
       
   253 	*  The functions scans through all translation table entries and deletes the 
       
   254 	*  node entries which are old ones based on the configured protocol time out entries.
       
   255 	*
       
   256 	**/
       
   257 	{
       
   258 
       
   259 	CNaptIPPortMap* table=NULL;
       
   260 	TBool deleteFlag= EFalse;
       
   261 	TUint32 curTime;
       
   262 	TInt seconds=0;
       
   263 	
       
   264 	for (TInt index=0; index< KTranslationHashTableSize; index++)
       
   265 		{
       
   266 		TNaptTableIter naptTableIter(iIPPortMap[index]);
       
   267 		naptTableIter.SetToFirst();
       
   268 
       
   269 		while ((table = naptTableIter++) != NULL)
       
   270     		{
       
   271     		deleteFlag = EFalse;
       
   272 			curTime = User::NTickCount();
       
   273 			if (curTime <= table->iCurTime)//checking clock wrap around
       
   274    				{
       
   275     			seconds = ((KMaxTUint32 - table->iCurTime) + curTime)/1000; 
       
   276     			}
       
   277 			else
       
   278     			{
       
   279     			seconds = (curTime - table->iCurTime)/1000;
       
   280     			}
       
   281 
       
   282 			//Depending on the protocol type delete transactions
       
   283 			switch (table->iProtocolType)
       
   284 				{
       
   285 				case KProtocolInetTcp:
       
   286 					if (seconds >= iTimerPtr->iNaptTcpIdleTimeout)//this is for TCP Inactive Connections..
       
   287 						{
       
   288 						deleteFlag=ETrue;
       
   289 						}
       
   290 					if (seconds >= iTimerPtr->iNaptTcpCloseTimeout && table->iProtocolFlag==KTcpCloseDeletePacket )
       
   291 						{
       
   292 						deleteFlag=ETrue;
       
   293 						}
       
   294 					if (seconds >= iTimerPtr->iNaptTcpOpenTimeout && table->iProtocolFlag==KTcpCtlSYN)
       
   295 						{
       
   296 						deleteFlag=ETrue;
       
   297 						}
       
   298 				
       
   299 				break;
       
   300 		
       
   301 				case KProtocolInetUdp:
       
   302 					if (seconds >= iTimerPtr->iNaptUdpIdleTimeout)
       
   303 						{
       
   304 						deleteFlag=ETrue;
       
   305 						}
       
   306 				break;
       
   307 	
       
   308 				case KProtocolInetIcmp:
       
   309 					if (seconds >= iTimerPtr->iNaptIcmpIdleTimeout )
       
   310 						{
       
   311 						deleteFlag=ETrue;
       
   312 						}
       
   313 				break;
       
   314 				}//end of switch
       
   315 			if (deleteFlag)
       
   316 				{
       
   317 				DeleteNodeInIndexedList(index,table);
       
   318 				}
       
   319 			}//end of while loop inside linked list
       
   320 		}//end of for loop entire index 
       
   321 	}
       
   322 	
       
   323 
       
   324 
       
   325 void TNaptTableMapMgr::DeleteNaptTableNode( CNaptIPPortMap *aTableNode)
       
   326 	/**
       
   327 	*
       
   328 	* Deletes the specified NAPT Translation Node in the Indexed list.
       
   329 	@param aTableNode - Table Node to be Deleted.
       
   330 	*
       
   331 	*/
       
   332 	{
       
   333 	TInt index= FindBucket(aTableNode->iTrPort);
       
   334 	DeleteNodeInIndexedList(index,aTableNode);
       
   335 
       
   336 	}
       
   337 
       
   338 void TNaptTableMapMgr::DeleteNodeInIndexedList(TInt aIndex, CNaptIPPortMap *aTableNode)
       
   339 	/*
       
   340 	*
       
   341 	* Deletes the specified NAPT table node in the indexed linked list.
       
   342 	@param----aIndex - index at which aTableNode exist.
       
   343 	@param----aTableNode - napt table node  to be deleted
       
   344 	* After deleting the specified node, decrement the iBucketsInUse if the indexed list is empty.
       
   345 	* Stop the timer, if there are no napt table nodes exists for translation.
       
   346 	*
       
   347 	*/
       
   348 	{
       
   349 	
       
   350 	iIPPortMap[aIndex].Remove(*aTableNode);	
       
   351 	delete aTableNode;
       
   352 	if (iIPPortMap[aIndex].IsEmpty())//check list is empty.
       
   353 		{
       
   354 		iBucketsInUse--;
       
   355 		}
       
   356 					
       
   357 	if (iBucketsInUse == 0) //Stop the Timer as there are no connections to translate
       
   358 		{
       
   359 		iTimerPtr->Cancel();
       
   360 		}
       
   361 	}
       
   362 	
       
   363 TBool TNaptTableMapMgr::VerifySender(const CNaptIPPortMap *aTableNode, const TUint32 &aSrcIp,TUint16 aSrcPort)
       
   364 	/*
       
   365 	*
       
   366 	* Function Matches the Sender IP and Port Number with the Stored NAPT translated node
       
   367 	@param---aTableNode - Napt Table Node to which the Sender IP & Port Number to be matched.
       
   368 	@param---aSrcIp -	Sender's source IP Address 
       
   369 	@param----aSrcPort - Sender's source port number
       
   370 	*
       
   371 	*/
       
   372 	{
       
   373 	if ( aTableNode->iDstPort == aSrcPort  && aTableNode->iDstIpAddr==aSrcIp)
       
   374 		{
       
   375 		return ETrue;
       
   376 		}
       
   377 	return EFalse;
       
   378 	}
       
   379 	
       
   380 	
       
   381 	
       
   382 void TNaptTableMapMgr::HandleTcpConnectionPhases(TInet6Checksum<TInet6HeaderTCP>& aTcpPacket, CNaptIPPortMap* aTableNode,const TInt aPacketDirection)
       
   383 	/*
       
   384 	*
       
   385 	* Function Handles Tcp Close Connection Phase mainly.. and open sequence,
       
   386 	* and open sequence,if it is originated during close sequence.
       
   387 	@param---aTcpPacket - Tcp Packet to be checked for FIN,ACK,RST & SYN Bits
       
   388 	@param----TableNode - Napt Table Node at which the TCP packet's above information to be stored. 
       
   389 	@param-----aPacketDirection - Direction which packet is travelling IN/OUT
       
   390 	* The NAPT table node will be marked for deletion if corresponding FIN+ACK messages are exchanged.
       
   391 	* But NAPT table node will be deleted immediately after the RST Flag is received from the private
       
   392 	*
       
   393 	*/
       
   394 	{
       
   395 
       
   396 	TUint8 synBit = aTcpPacket.iHdr->SYN();
       
   397 	if (synBit)
       
   398 	   	{
       
   399 	   	//Reset the protocol Flag to have only to have Syn Bit..so that if pending fin is cancelled.
       
   400 	   	//The reset enables SYN to be received, ie new connection initiation request to pass through
       
   401 	   	// and to cancel the NAPT table node entry node for deletion
       
   402 		aTableNode->iProtocolFlag = KTcpCtlSYN;
       
   403 		//its good to return now here as we dont need to check, as other bits like RST/FIN wont 
       
   404 		//be transmitted along with SYN bit message.
       
   405 		return;
       
   406 	   	}	
       
   407 	else
       
   408 		{
       
   409 		//Reset Syn Bit...to come out of TCP SYN open timer..
       
   410 		aTableNode->iProtocolFlag &= ~KTcpCtlSYN;
       
   411 		}
       
   412 	
       
   413 	TUint8 ackBit = aTcpPacket.iHdr->ACK();
       
   414 	TUint8 finBit = aTcpPacket.iHdr->FIN();
       
   415 	TUint8 rstBit = aTcpPacket.iHdr->RST();
       
   416 	
       
   417 	//Putting this below condition before the actual FIN bit,  ensures that FIN+ACK in the same packet
       
   418 	//would not mark the packet for deletion. The node is marked for delete after the receive of FIN 
       
   419 	//exchanges from both ends. 
       
   420 	//The NAPT table node is deleted only after close time out period after receiving last ACK which initiated FIN.
       
   421 	if ((aTableNode->iProtocolFlag == (KTcpClosePacketOUT|KTcpClosePacketIN)) && ackBit )
       
   422 		{
       
   423 		//The above condition ensures that ACK is received for the corresponding FIN which has been sent earlier.
       
   424 		//However it is not checking ACK received  is the one  corresponding ACK for the FIN(can be done by sequence number matching)
       
   425 		//As we are not deleting NAPT table node immediately, the execption of receiving ACK for the not
       
   426 		//correct FIN can be ignored and we rely on TCP clien ends resolve the correct sequence number if they are not the same.
       
   427 		
       
   428 		
       
   429 		//Also when FIN is sent by the end client(its in HALF close FIN_WAIT state), it wont send any 
       
   430 		//further data but it is able to recive data. The next message sent by the closing client,
       
   431 		//is either FIN(retransmission) or ACK.
       
   432 	
       
   433 		//It handles many Close Scenarios like below(list.. is not complete)
       
   434 		// 1.FIN ->, <- ACK, <- FIN, ACK -> (rare, but possible)[Simulteneous close]
       
   435 		// 2.FIN+ACK ->, <- FIN+ACK, ACK ->
       
   436 		// 3.FIN ->, <- FIN+ACK, ACK ->
       
   437 		// 4.FIN+ACK ->, <- FIN, <- ACK, ACK ->(rare, but possible)[very Simulteneous close]..etc
       
   438 		// However in last case..the table node is marked before the last ACk is originated. This seems ok, as we are not 
       
   439 		// deleting any packet 
       
   440 		aTableNode->iProtocolFlag |= ackBit ; //now it is KTcpCloseDeletePacket	
       
   441 		
       
   442 		}
       
   443 	if (finBit)
       
   444 		{
       
   445 		aTableNode->iProtocolFlag |= aPacketDirection;
       
   446 		return;
       
   447 		}
       
   448 		
       
   449 
       
   450 	//Delete NAPT table node entry only if RST is originated from private subnet
       
   451 	//RST coming from global interface have to wait for  Close timeout period 
       
   452 	//for the entry to be deleted.  	
       
   453 	if (rstBit && (aPacketDirection == KTcpClosePacketOUT))
       
   454 		{
       
   455 		DeleteNaptTableNode(aTableNode);
       
   456 		}  		
       
   457 	
       
   458 	}
       
   459