vpnengine/ikev1lib/src/ikev1sa.cpp
changeset 0 33413c0669b9
equal deleted inserted replaced
-1:000000000000 0:33413c0669b9
       
     1 /*
       
     2 * Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  IKEv1 SA
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "ikedebug.h"
       
    20 #include "ikev1SA.h"
       
    21 #include "ikev1SAdata.h"
       
    22 #include "ikev1keepalive.h"
       
    23 #include "ikev1nokianattkeepalive.h" // CIkev1NokiaNattKeepAlive
       
    24 #include "ikepolparser.h"
       
    25 #include "ikesocketdefs.h"
       
    26 #include "ikev1pluginsession.h"
       
    27 
       
    28 CIkev1SA* CIkev1SA::NewL( CIkev1PluginSession& aPluginSession,
       
    29                           TIkev1SAData& aIkev1SAdata,
       
    30                           CSARekeyInfo* aSaRekey,
       
    31                           MIkeDebug& aDebug )
       
    32 {
       
    33 	CIkev1SA *sa = new (ELeave) CIkev1SA( aPluginSession, aDebug );
       
    34 	sa->ConstructL( aIkev1SAdata, aSaRekey );
       
    35 	return sa;
       
    36 }
       
    37 
       
    38 
       
    39 //Constructor
       
    40 CIkev1SA::CIkev1SA( CIkev1PluginSession& aPluginSession,
       
    41                     MIkeDebug& aDebug )
       
    42  : CTimer( EPriorityStandard ),
       
    43    iPluginSession( aPluginSession ),
       
    44    iDebug( aDebug )
       
    45 {
       
    46     CActiveScheduler::Add(this);
       
    47 }
       
    48 
       
    49 void CIkev1SA::ConstructL(TIkev1SAData& aIkev1SAdata, CSARekeyInfo* aSaRekey)
       
    50 {
       
    51 	CTimer::ConstructL();   			
       
    52 	iHdr.CopyL(aIkev1SAdata);
       
    53 	
       
    54 	if ( aSaRekey )
       
    55 	{
       
    56 	   //
       
    57 	   // Rekeyed IKE SA. Try to find "original" IKE SA and move IPSEC
       
    58 	   // SPI list from that SA to the new rekeyed one.
       
    59 	   // If "original" IKE SA is found, (re)start expiration timer
       
    60 	   // with rekey "left over" time.
       
    61 	   //
       
    62 	   iRekeyed = ETrue;
       
    63 	   CIkev1SA *OrigSA = iPluginSession.FindIkev1SA(aSaRekey->GetCookieI(), aSaRekey->GetCookieR());
       
    64 	   if ( OrigSA )
       
    65 	   {
       
    66 		  DEBUG_LOG(_L("ISAKMP SA Rekeyed, SPI list moved from original SA"));		   
       
    67 		  iSPIList = OrigSA->iSPIList;
       
    68 		  OrigSA->iSPIList = NULL;
       
    69 		  OrigSA->iSPIList = new (ELeave) CIpsecSPIList(1);  // Dummy
       
    70 		  if ( OrigSA->IsActive() )
       
    71 		  {
       
    72 			 OrigSA->Cancel();  		  
       
    73 			 OrigSA->iRemainingTime = 0;
       
    74 			 OrigSA->iLeftOverTime = 0;
       
    75 			 DEBUG_LOG1(_L("Rekeyed SA expiration time set to %u"),OrigSA->iRemainingTime);
       
    76 		     OrigSA->StartTimer();
       
    77 		  }	 
       
    78 	   }
       
    79 	}
       
    80 	
       
    81 	if ( !iSPIList ) 
       
    82        iSPIList = new (ELeave) CIpsecSPIList(4);
       
    83 
       
    84 	TInt DPDHeartbeat;
       
    85 
       
    86 	if ( iHdr.iDPDSupported && iHdr.iIkeData->iDPDHeartBeat )
       
    87 	     DPDHeartbeat = iHdr.iIkeData->iDPDHeartBeat;      
       
    88 	else DPDHeartbeat = 0;
       
    89 
       
    90 	TInt KeepAliveTimeout = 0;
       
    91 	TInt port = IkeSocket::KIkePort500;
       
    92 	TUint32 NATKeepAlive = (iHdr.iNAT_D_Flags & LOCAL_END_NAT);
       
    93 	if ( NATKeepAlive || iHdr.iNAT_T_Required )
       
    94 	{
       
    95 		KeepAliveTimeout = (TInt)iHdr.iIkeData->iNatKeepAlive; 
       
    96 		if ( NATKeepAlive )
       
    97 		{	   
       
    98 		    port = IkeSocket::KIkePort4500;
       
    99 			if ( KeepAliveTimeout == 0 )
       
   100 				KeepAliveTimeout = 120;  // If not configured use 2 minutes  
       
   101 		}	  
       
   102 	}
       
   103 
       
   104 	if ( DPDHeartbeat || KeepAliveTimeout )
       
   105 	{
       
   106 		iIkeKeepAlive = CIkeV1KeepAlive::NewL( iPluginSession,
       
   107 		                                       port,
       
   108 		                                       (TInetAddr&)iHdr.iDestinAddr,
       
   109 		                                       KeepAliveTimeout,
       
   110 		                                       DPDHeartbeat,
       
   111 										       (MDpdHeartBeatEventHandler*)this );
       
   112 	}
       
   113 	
       
   114 	// Nokia NAT-T needed
       
   115 	if (!NATKeepAlive &&
       
   116 	    iHdr.iNAT_T_Required &&
       
   117 	    (KeepAliveTimeout > 0) )
       
   118 		{
       
   119 		// Start Nokia IPsec over NAT keepalive handler
       
   120 		TInetAddr addr = (TInetAddr)iHdr.iDestinAddr;
       
   121 		
       
   122 		// NAT-T default ESP UDP port
       
   123 		TInt port(KNokiaNattDefaultPort);
       
   124 		if (iHdr.iIkeData->iEspUdpPort)
       
   125 			port = iHdr.iIkeData->iEspUdpPort;
       
   126 
       
   127 		iNokiaNatt = CIkev1NokiaNattKeepAlive::NewL( iPluginSession,
       
   128 		                                             addr,
       
   129 		                                             port,
       
   130 		                                             KeepAliveTimeout,
       
   131 		                                             iDebug );
       
   132 		}
       
   133 	
       
   134 	if ( !iHdr.iVirtualIp && aSaRekey )
       
   135 	{
       
   136 	   //
       
   137 	   // Rekeyed IKE SA. No virtual IP address received in IKE SA
       
   138 	   // negotiation. Get "old" virtual IP address saved into
       
   139 	   // CSARekeyInfo object (if any).
       
   140 	   //
       
   141 		iHdr.StoreVirtualIp(aSaRekey->GetInternalAddr());
       
   142 	}	
       
   143 
       
   144 	
       
   145     //Lifetime in seconds
       
   146     iRemainingTime = iHdr.iLifeTimeSecs;
       
   147     if ( iRemainingTime == 0 ) 
       
   148         iRemainingTime = DEFAULT_MAX_ISAKMP_LIFETIME;
       
   149 
       
   150 	//
       
   151 	//  Check if IKE SA rekeying threshold value (per cent) defined
       
   152 	//  If it is (value is between 70 - 95), use that per cent value
       
   153 	//  as IKE SA timeout (Rekey for a new IKE SA is started then)
       
   154 	//  "Left over" time is the expiration timeout for rekeyed IKE SA
       
   155 	//  value which is used when rekey negotiation is started.
       
   156 	//  The minimum value for that is set to 30 seconds
       
   157 	//
       
   158 	TInt RekeyThreshold = iHdr.iIkeData->iRekeyingThreshold;
       
   159 	if ( RekeyThreshold != 0 )	
       
   160 	{
       
   161 	   if ( RekeyThreshold < 70 )
       
   162 		    RekeyThreshold = 70;
       
   163 	   else if ( RekeyThreshold > 95 )
       
   164 		    RekeyThreshold = 95;
       
   165 	   DEBUG_LOG1(_L("Negotiated ISAKMP Lifetime set to %u"),iRemainingTime);
       
   166 	   iLeftOverTime   = iRemainingTime - ((iRemainingTime/100.0) * RekeyThreshold); 	
       
   167 	   iRemainingTime -= iLeftOverTime;
       
   168 	   if ( iLeftOverTime < 30 )
       
   169 		   iLeftOverTime = 30;  
       
   170 	} 		
       
   171 
       
   172     DEBUG_LOG1(_L("ISAKMP Lifetime set to %u"),iRemainingTime);
       
   173 			
       
   174     //Lifetime in Kb
       
   175     iRemainingKB = iHdr.iLifeTimeKB;
       
   176     DEBUG_LOG1(_L("ISAKMP KB Lifetime set to %u"),iRemainingKB);
       
   177 
       
   178 	StartTimer();			
       
   179 			
       
   180 }
       
   181 
       
   182 //Destructor
       
   183 CIkev1SA::~CIkev1SA()
       
   184 {
       
   185     Cancel();
       
   186     
       
   187     //Delete the IPSEC SAs as well if desired
       
   188     if ( iHdr.iIkeData && iSPIList)
       
   189         {
       
   190         for (TInt i = 0; i < iSPIList->Count(); i++)
       
   191             {
       
   192             TIpsecSPI* spi_node = iSPIList->At(i);
       
   193             iPluginSession.DeleteIpsecSA( spi_node->iSPI,
       
   194                                           spi_node->iSrcAddr, 
       
   195                                           spi_node->iDstAddr,
       
   196                                           spi_node->iProtocol );
       
   197             }
       
   198         }   
       
   199         
       
   200 	iHdr.CleanUp();	
       
   201     //Deletes the SPI List
       
   202     delete iSPIList;
       
   203 	delete iIkeKeepAlive;
       
   204 	delete iNokiaNatt;
       
   205 }
       
   206 
       
   207 
       
   208 void CIkev1SA::SetExpired()
       
   209 {
       
   210     DEBUG_LOG(_L("CIkev1SA::SetExpired"));
       
   211 
       
   212 	if ( !iExpired )  //If already expired do nothing to avoid renewing the expiration timer.
       
   213 	{
       
   214 	    DEBUG_LOG(_L("SA is still active. Expiring it..."));
       
   215 	
       
   216 		iExpired = ETrue;
       
   217 		//if ( iHdr.iIkeData->iIpsecExpires )
       
   218 		//{	
       
   219 	    //DEB(iEngine->PrintText(_L("iIpsecExpires is ETrue\n"));)
       
   220 		for (TInt i = 0; i < iSPIList->Count(); i++)
       
   221 		{
       
   222 		    DEBUG_LOG(_L("Deleting IPsec SA"));
       
   223 			TIpsecSPI* spi_node = iSPIList->At(i);
       
   224 			iPluginSession.DeleteIpsecSA( spi_node->iSPI,
       
   225 			                              spi_node->iSrcAddr,
       
   226 			                              spi_node->iDstAddr,
       
   227 			                              spi_node->iProtocol );
       
   228 		}
       
   229 		//}	
       
   230 		Cancel();   //Cancel the current timer
       
   231 		After(ISAKMP_DELETE_TIME);
       
   232 	}
       
   233 }
       
   234 
       
   235 void CIkev1SA::UpdateSAL(TBool aExpired, TIkev1SAData* aIkev1SAdata)
       
   236 {
       
   237     DEBUG_LOG(_L("CIkev1SA::UpdateSAL"));
       
   238 
       
   239     if ( aExpired )
       
   240     {	    
       
   241         ExpireSA();
       
   242     }
       
   243     else
       
   244     {
       
   245         DEBUG_LOG(_L("Not expiring SA"));
       
   246         if ( aIkev1SAdata ) 
       
   247         {            
       
   248             iHdr.CopyL(*aIkev1SAdata);
       
   249         }
       
   250     }	
       
   251 }
       
   252 
       
   253 void CIkev1SA::ExpireSA()
       
   254     {
       
   255     DEBUG_LOG(_L("Expiring SA"));
       
   256     SetExpired();
       
   257     }
       
   258 
       
   259 void CIkev1SA::DoCancel()
       
   260 {
       
   261     CTimer::DoCancel();
       
   262 }
       
   263 
       
   264 void CIkev1SA::RunL()
       
   265 {
       
   266 
       
   267     DEBUG_LOG(_L("CIkev1SA::RunL"));
       
   268     if (!iExpired)  //Still alive so that's a normal Lifetime Expiration
       
   269     {
       
   270         DEBUG_LOG(_L("Sa is not expired"));
       
   271     
       
   272 		if (iRemainingTime > 0) //Timer still no finished
       
   273 		{
       
   274 			StartTimer();
       
   275 			return;
       
   276 		}
       
   277 		
       
   278 		if ( iLeftOverTime )
       
   279 		{
       
   280 		    //
       
   281 			// Start IKE phase 1 rekey operation
       
   282 			//
       
   283 			iRemainingTime = iLeftOverTime;
       
   284 			iLeftOverTime  = 0;
       
   285 			CSARekeyInfo* SARekeyInfo = CSARekeyInfo::NewL(iHdr.iCookie_I, iHdr.iCookie_R, iHdr.iVirtualIp);
       
   286 				
       
   287 		    iHdr.iVirtualIp = NULL; //Exclusive ownership of the object moved to TSARekeyInfo
       
   288 		    DEBUG_LOG(_L("Starting ISAKMP SA rekeying "));
       
   289 		    CleanupStack::PushL(SARekeyInfo);					   
       
   290 		    iPluginSession.RekeyIkeSAL(&iHdr, SARekeyInfo);
       
   291 		    CleanupStack::Pop(SARekeyInfo);					   			   
       
   292 		    StartTimer();  
       
   293 		}
       
   294 		else
       
   295 		{	
       
   296             DEBUG_LOG(_L("**\n---ISAKMP SA Deleted---- Lifetime expired**"));
       
   297 			iPluginSession.DeleteIkeSA(&iHdr, EFalse);  // "Normal" close
       
   298 			SetExpired();
       
   299 		}   
       
   300     }
       
   301     else
       
   302 	{	//Expired must be erased Completely after the default waiting time
       
   303 	
       
   304 	    DEBUG_LOG(_L("Deleting IKE Sa"));
       
   305 	    iPluginSession.RemoveIkeSA( this, iStatus.Int() );
       
   306 	}	
       
   307 	
       
   308 }
       
   309 
       
   310 TInt CIkev1SA::RunError(TInt aError)
       
   311     {
       
   312     DEBUG_LOG1(_L("CIkev1SA::RunError, err=%d"), aError);
       
   313     iPluginSession.HandleError(aError);
       
   314     return KErrNone;
       
   315     }
       
   316 
       
   317 void CIkev1SA::StartTimer()
       
   318 {
       
   319 	if (iRemainingTime > KMaxTInt/SECOND)   //To avoid overflowing the Timer
       
   320 	{
       
   321 		iRemainingTime -= KMaxTInt/SECOND;
       
   322 		After(KMaxTInt);
       
   323 	}
       
   324 	else    //No overflow
       
   325 	{
       
   326 		After(iRemainingTime*SECOND);
       
   327 		iRemainingTime = 0;
       
   328 	}
       
   329 }
       
   330 
       
   331 //Adds a new node to the List of SPIs to know the direction if it has to be deleted.
       
   332 void CIkev1SA::AddIpsecSPIL(TIpsecSPI& aIpsecSpi)
       
   333 {
       
   334     TIpsecSPI* spi_node =  new (ELeave) TIpsecSPI;
       
   335     CleanupStack::PushL(spi_node);
       
   336     iSPIList->AppendL(spi_node);
       
   337     CleanupStack::Pop();
       
   338     spi_node->iSrcAddr  = aIpsecSpi.iSrcAddr;
       
   339     spi_node->iDstAddr  = aIpsecSpi.iDstAddr;
       
   340     spi_node->iSPI      = aIpsecSpi.iSPI;
       
   341     spi_node->iProtocol = aIpsecSpi.iProtocol;
       
   342 	spi_node->iInbound  = aIpsecSpi.iInbound;
       
   343 }
       
   344 
       
   345 TBool CIkev1SA::FindIpsecSPI(TUint32 aSPI, TBool aInbound)
       
   346 {
       
   347     TIpsecSPI *spi_node;
       
   348     for (TInt i = 0; i < iSPIList->Count(); i++)
       
   349     {
       
   350         spi_node = iSPIList->At(i);
       
   351         if ( (spi_node->iSPI == aSPI) && (spi_node->iInbound == aInbound) )
       
   352         {
       
   353             return ETrue;
       
   354         }
       
   355     }
       
   356 
       
   357     return EFalse;
       
   358 }
       
   359 
       
   360 //
       
   361 //Deletes a TIpsecSPI matching aSPI 
       
   362 // 
       
   363 TBool CIkev1SA::DeleteIpsecSPI(TUint32 aSPI, TBool aInbound)
       
   364 {
       
   365     TIpsecSPI *spi_node;
       
   366     for (TInt i = 0; i < iSPIList->Count(); i++)
       
   367     {
       
   368         spi_node = iSPIList->At(i);
       
   369         if ( (spi_node->iSPI == aSPI) && (spi_node->iInbound == aInbound) )
       
   370         {
       
   371             delete spi_node;
       
   372             iSPIList->Delete(i);
       
   373             return ETrue;
       
   374         }
       
   375     }
       
   376 
       
   377     return EFalse;
       
   378 }
       
   379 
       
   380 //
       
   381 // Flush all Ipsec SA:s bound to this IKE SA from SADB and send Delete
       
   382 // payload for all inbound SAs
       
   383 // 
       
   384 void CIkev1SA::DeleteIpsecSAs()
       
   385 {
       
   386     TIpsecSPI* spi_node;
       
   387 	TInt c = iSPIList->Count();
       
   388     for (TInt i = 0; i < c; i++)
       
   389     {
       
   390         spi_node = iSPIList->At(i);
       
   391         if ( spi_node->iInbound )
       
   392 		{	
       
   393             //Only the inbound ones notified to avoid receiving packets using an expired SA
       
   394             //The opposite if receiving a Delete
       
   395 			DEBUG_LOG1(_L("Sending ISAKMP Delete payload for IPSec SPI %x"),
       
   396 			        (int)ByteOrder::Swap32(spi_node->iSPI));
       
   397 
       
   398             // Call to delete may fail (delete sends DELETE payloads, and the data connection 
       
   399             // may not be open anymore). This is non-fatal, however.
       
   400             TRAPD(err, iPluginSession.DeleteIpsecSAL(&iHdr, spi_node));
       
   401             if (err == KErrNone) 
       
   402                 {
       
   403                 // DELETE sent successfully
       
   404     			DEBUG_LOG(_L("CIkev1SA::DeleteIpsecSAsL() IPsec SA delete OK"));
       
   405                 }
       
   406             else if (err == KErrNotFound) 
       
   407                 {
       
   408                 // Non-fatal leave occured (couldn't send DELETE due to invalid connection)
       
   409                 // We can still continue purging IPSEC SAs.
       
   410     			DEBUG_LOG(_L("CIkev1SA::DeleteIpsecSAsL() IPsec SA delete failed due non-existing connection. Non-fatal, continuing"));
       
   411                 }
       
   412             else
       
   413                 {
       
   414                 // Fatal leave (e.g. out of memory etc)
       
   415     			DEBUG_LOG(_L("CIkev1SA::DeleteIpsecSAsL() IPsec SA deletion error. Fatal."));
       
   416     			iPluginSession.HandleError(err);
       
   417                 return;
       
   418                 }
       
   419 		}
       
   420 	    iPluginSession.DeleteIpsecSA(spi_node->iSPI, spi_node->iSrcAddr, spi_node->iDstAddr, spi_node->iProtocol);		
       
   421 		delete spi_node;
       
   422     }
       
   423     iSPIList->Reset();  //Empties the full list at once
       
   424 }
       
   425 
       
   426 //
       
   427 // void CIkev1SA::DeleteIpsecSAsForced()
       
   428 // 
       
   429 void CIkev1SA::DeleteIpsecSAsForced()
       
   430 {
       
   431     TIpsecSPI* spi_node;
       
   432 	TInt c = iSPIList->Count();
       
   433     for (TInt i = 0; i < c; i++)
       
   434     {
       
   435         spi_node = iSPIList->At(i);
       
   436        	iPluginSession.DeleteIpsecSA( spi_node->iSPI,
       
   437        	                              spi_node->iSrcAddr,
       
   438        	                              spi_node->iDstAddr,
       
   439        	                              spi_node->iProtocol );		
       
   440 		delete spi_node;
       
   441     }
       
   442     iSPIList->Reset();
       
   443 }
       
   444 
       
   445 void CIkev1SA::EventHandlerL()
       
   446 {
       
   447 	//
       
   448 	// The implementation for class MDpdHeartBeatEventHandler virtual function
       
   449 	// This method is called by an CIkeKeepAlive object instance when
       
   450 	// DPD heartbeat timeout has elapsed.
       
   451 	//
       
   452 	if ( !iExpired && iSPIList->Count() )
       
   453 	   iPluginSession.KeepAliveIkeSAL(&iHdr);	
       
   454 }
       
   455 
       
   456 void CIkev1SA::CancelRekey()
       
   457     {
       
   458     if ( iLeftOverTime != 0 )
       
   459         {
       
   460         DEBUG_LOG1(_L("CIkev1SA::CancelRekey, remaining time=%d"), iLeftOverTime );
       
   461         iRemainingTime = iLeftOverTime;
       
   462         iLeftOverTime = 0;
       
   463         }        
       
   464     }
       
   465 
       
   466 //
       
   467 //class CIpsecSPIList : public CArrayPtr<TIpsecSPI>
       
   468 //
       
   469 CIpsecSPIList::CIpsecSPIList(TInt aGranularity) : CArrayPtrFlat<TIpsecSPI>(aGranularity){}
       
   470 CIpsecSPIList::~CIpsecSPIList() {ResetAndDestroy();}
       
   471