--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/networkaddressandporttranslation/src/napt.cpp Tue Jan 26 15:23:49 2010 +0200
@@ -0,0 +1,1186 @@
+// Copyright (c) 2008-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:
+// implementation of UDP and TCP 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 "naptconfigtable.h"
+#include <posthook.h>
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#include "naptutil.h"
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+#include <es_prot_internal.h>
+
+const TInt KIapUnDefined = 0;
+
+
+void Panic(TNAPTPanic aPanic)
+ {
+ User::Panic(_L("NAPTHook panic"), aPanic);
+ }
+
+_LIT(KProtocolNaptName, "napt");
+
+
+//Timer class Functions..
+CNaptTimer* CNaptTimer::NewL(CProtocolNapt* aNaptProtocol)
+ /**
+ *
+ * Create an instance of the timer
+ *
+ */
+ {
+ CNaptTimer* timer = new(ELeave)CNaptTimer();
+ CleanupStack::PushL(timer);
+ timer->ConstructL();
+ timer->iNaptProtocol = aNaptProtocol;
+ timer->iMapMgrPtr = &(aNaptProtocol->iNaptMapMgr);
+ CleanupStack::Pop(timer);
+ return timer;
+ }
+
+
+void CNaptTimer::StartTimer()
+ /**
+ *
+ * Start Timer & Add it Active Scheduler
+ *
+ **/
+ {
+ ASSERT(!IsAdded());
+ CActiveScheduler::Add(this);
+ //it should be in Micro Seconds..
+ CTimer::After(iNaptTableScanInterval*1000000);
+ }
+
+
+void CNaptTimer::RunL()
+ /**
+ * Timer is complete...
+ * Delete the TimedOut Entries from the TranslationTable.
+ * Check Any Packets are there in TranslationTable to be converted.
+ * Restart Timer if they are present by taking iIndexedCount
+ * Else Stop the timer
+ *
+ * @internalTechnology
+ **/
+ {
+
+ //delete timeout transactions..
+ iMapMgrPtr->TimerComplete();
+
+ //reset timer
+ if (iNaptProtocol->iNaptMapMgr.GetIndexedPortCount())
+ {
+ CTimer::After(iNaptTableScanInterval*1000000);
+ }
+ else
+ {
+ Cancel();
+ }
+ }
+
+
+void CNaptTimer::Cancel()
+ /**
+ *
+ * Remove Timer from Active Scheduler
+ *
+ **/
+ {
+ CTimer::DoCancel();
+ if (IsAdded())
+ {
+ Deque();
+ }
+ }
+
+CNaptTimer::~CNaptTimer()
+ /**
+ *
+ * Timer destructor
+ *
+ */
+ {
+ Cancel();
+ }
+
+
+/**
+---------------------------------------------------------------------------------------
+ CSapNapt
+---------------------------------------------------------------------------------------
+
+This class is derived from CServProviderBase.CSapNapt is the service class for sockets
+loading NAPT.But here only one socket will be able to load protocol.If protocol once
+loaded other socket cannot service protocol by opening socket.
+
+ */
+
+CSapNapt::CSapNapt()
+ {
+ iConfigInfo = NULL;
+ }
+
+
+TNaptConfigInfo* CSapNapt::GetConfigInfo()
+/**
+ * This method is used to get the NAPT related configuration for this Service provider
+ * access point.
+ * @param None
+ * return - TNaptConfigInfo*
+**/
+ {
+ return iConfigInfo;
+ }
+
+void CSapNapt::SetConfigInfo(TNaptConfigInfo *aConfigInfo)
+/**
+ * This method is used to set the NAPT related configuration for this Service provider
+ * access point.
+ * @param None
+ * return - TNaptConfigInfo*
+**/
+ {
+ iConfigInfo = aConfigInfo;
+ }
+
+TInt CSapNapt::SetOption(TUint aLevel ,TUint aName ,const TDesC8& anOption)
+/**
+ * This class is used to set interface index information to be used by NAPT.
+ * level will contain Downlink information and name will contain private interface
+ * index. This method will also bind the protocol to the TCP/IP stack if it has not been
+ * done yet.
+ * @param aDownlink-- Downlink Interface Index.
+ * @param aPrivateInterface - Private interface Index.
+ * return - KErrNone if no value is assigned else KErrPermissionDenied
+**/
+
+ {
+ TInt err = KErrNone;
+#ifndef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+
+ const TInterfaceLockInfo* info= reinterpret_cast<const TInterfaceLockInfo* >(anOption.Ptr());
+ if(aLevel==KSolNapt && aName == KSoNaptSetup)
+ {
+ if(anOption.Length()!=sizeof(TInterfaceLockInfo))
+ {
+ //this means that Block is not filled properly
+ return KErrArgument;
+ }
+ err = iConfigMgr->UpdateConfigL(info, this);
+ }//check if option and size
+ else
+ {
+ //options level or Name wrong
+ return KErrArgument;
+ }
+
+#else //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+ if(aLevel==KSolNapt)
+ {
+ switch(aName)
+ {
+ case KSoNaptSetup:
+ case KSoNaptProvision:
+ {
+ LOG(Log::Printf(_L("CSapNapt::SetOption(): KSoNaptSetup ")));
+ const TInterfaceLockInfo* info = reinterpret_cast<const TInterfaceLockInfo* >(anOption.Ptr());
+ if(anOption.Length()!= sizeof(TInterfaceLockInfo))
+ {
+ //this means that Block is not filled properly
+ return KErrArgument;
+ }
+ err = iConfigMgr->UpdateConfigL(info, this) ;
+ }
+ break;
+
+ default:
+ {
+ LOG(Log::Printf(_L("//options level or Name wrong")));
+ //options level or Name wrong
+ return KErrArgument;
+ }
+ }//switch ends here
+ }
+ else
+ {
+ //options level or Name wrong
+ return KErrArgument;
+ }
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+ // Bind the protocol to TCP/IP stack and this will result in actually attach of the hook
+ DoBindToL(err);
+
+ return err;
+ }//end main function
+
+
+void CSapNapt::DoBindToL(TInt aStatus)
+/* This method is used to bind the protocol to TCP/IP stack once the client
+ * configures NAPT hook. It checks if the protocol is not already bound in case it is
+ * already bound the method does nothing and simply returns. Until and unless Napt is
+ * configured it's not actually bound to TCP/IP stack.
+ * @param aStatus -- Status.
+ * return - None
+ *
+ */
+ {
+ if ((aStatus == KErrNone) && (iProtocol->iBoundFlag == EFalse))
+ {
+ iProtocol->iBoundFlag = ETrue;
+ iProtocol->BindToL(iProtocol->iProtBase);
+ }
+ }
+
+TInt CSapNapt::SecurityCheck(MProvdSecurityChecker* aChecker)
+ /**
+ * Capability check for the NAPT sockets.
+ *
+ * NAPT sockets require the NetworkControl capability.
+ *
+ * @param aChecker The policy checker.
+ * @return The result of the policy check.
+ */
+ {
+ // This method is called when a SAP is created and when a socket is transferred between sessions. The SAP is
+ //required to check whether the originating client process has enough privileges to request services from the SAP.
+ //The MProvdSecurityChecker class instance is used to perform security policy checks. The SAP may choose
+ //to perform a security policy check in its SecurityCheck(...) method, or it may choose to store the
+ //MProvdSecurityChecker class instance argument and perform checking later (i.e. when subsequent
+ //SAP methods are called).
+ _LIT_SECURITY_POLICY_C1(KPolicyNetworkControl, ECapabilityNetworkControl);
+ return aChecker->CheckPolicy(KPolicyNetworkControl, "NAPT policy failed.");
+ }
+
+
+
+
+/*
+-------------------------------------------------------------------------------------------------
+ CProtocolNapt
+
+-------------------------------------------------------------------------------------------------
+
+
+ Protocol loading
+ ----------------
+
+ ESOCK
+ \
+ \
+ load \
+ \ load
+ CProtocolNapt-------->CProtocolNaptIn
+
+
+
+CProtocolNapt will load CProtocolNaptIn in its constructor. CProtocolNapt will bind itself as forward hook and
+will bind CProtocolNaptIn as an InboundHook using NetworkServices.
+
+
+ */
+
+
+CProtocolNapt* CProtocolNapt::NewL()
+ {
+ CProtocolNapt* self = new(ELeave) CProtocolNapt();
+ CleanupStack::PushL(self);
+ self->CreateL();
+ CleanupStack::Pop();
+ return self;
+ }
+
+
+void CProtocolNapt::CreateL()
+/*
+ *ConstructL part of two phase construction. Allocating memory to Inbound class aand passing
+ * reference to this.
+*/
+ {
+ iNaptMapMgr.iLastPort = KNaptPort_HIGH;
+
+
+ iConfigMgr = CNaptClientConfigMgr::NewL(*this);
+
+ //Allocating memory for Inbound Hook. No need for cleanup stack here its
+ //a leaving function, so everything should be traped above.
+ iProtInbound = new(ELeave) CProtocolNaptIn(this);
+
+ //Create Timer Instance
+ if (!iTimer)
+ {
+ iTimer = CNaptTimer::NewL(this);
+ iNaptMapMgr.iTimerPtr = iTimer;
+ }
+ iBoundFlag = EFalse;
+ }
+
+CProtocolNapt::~CProtocolNapt()
+/**
+ * Destructor.This is called when NAPT is destroyed. Protocol should unbind it self
+ * from the Network Layer.
+**/
+
+ {
+ CNaptIPPortMap *table=NULL;
+ if (iTimer )
+ {
+ //running timer will be stopped in destructor
+ delete iTimer;
+ }
+ for (TInt index=0;index<KTranslationHashTableSize;index++)
+ {
+ TNaptTableIter naptTableIter(iNaptMapMgr.iIPPortMap[index]);
+ naptTableIter.SetToFirst();
+ while((table=naptTableIter++)!=NULL)
+ {
+ iNaptMapMgr.iIPPortMap[index].Remove(*table);
+ delete table;
+ }
+ }
+ // Protocol is being unloaded and hence clear all SAP references
+ // We are not really needed to delete the objects as esock will take care of
+ // deleting all the SAPs.
+ iSapList.Reset();
+ //Delete the client config manager.
+ //This in turn destroys all the configurations stored in the list
+ delete iConfigMgr;
+
+ if(iBoundFlag != EFalse)
+ {
+ //Unbind Hooks.iProtInbound is the inbound hook which should be unbind from
+ //stack before unbinding main protocol.Should unbind using network service
+ //which quite important.If unable to unbind then check for network Services.
+ NetworkService()->Protocol()->Unbind((CProtocolBase*)iProtInbound,0);
+
+ NetworkService()->Protocol()->Unbind(this,0);
+
+ }
+
+ if(iProtInbound!=NULL)
+ {
+ delete iProtInbound;
+ iProtInbound=NULL; //just safe step
+ }
+#ifdef __DEBUG
+//UnMarking heap which is marked when protocol is loaded in Family.cpp
+__UHEAP_MARKEND;
+#endif
+
+ }
+
+
+void CProtocolNapt::Identify(TServerProtocolDesc* aProtocolDesc)const
+ {
+ Describe(*aProtocolDesc);
+ }
+
+
+
+void CProtocolNapt::BindL(CProtocolBase* /*protocol*/, TUint /*id*/)
+ {
+ // We should not overwrite the existing esk files
+
+ }
+
+
+
+void CProtocolNapt::BindToL(CProtocolBase* aProtocol)
+ /**
+ * The protocol binds itself to TCP/IP stack. The bind has been delibrately deferred
+ * here to facilitate opening of multiple sockets without actually loading the hook.
+ * The hook will be actually loaded when someone configured the setup information in NAPT
+ *
+ **/
+ {
+ if(iBoundFlag != EFalse)
+ {
+ const TUint id = (TUint)DoBindToL(aProtocol);
+ }
+ else
+ iProtBase = aProtocol;
+ }
+
+
+void CProtocolNapt::NetworkAttachedL()
+ /**
+ * The TCP/IP stack has been attached to this plugin.
+ *
+ * The CProtocolPosthook impelements the basic BindL/BindToL and Unbind
+ * processing. The NetworkAttached is called when the TCP/IP
+ * is connected with this protocol module.
+ *
+ * This function installs a hook for forwarded packets. The function
+ * ApplyL will be called for each received packet that enters the
+ * forward path (before actual forwarding decision).
+ *
+ * Could also install any other hooks to pull packets.
+ */
+ {
+ //Read Timer Configuration Parameters
+ ReadConfigurationFile();
+
+ NetworkService()->BindL(this, BindForwardHook());
+
+ //Binding Inbound hook as hook all. This will take packets from all the interfaces
+ //and translate only thise which are required.This seperate class optimise RAM usage.
+ //and implemented to avoid usage of heavy calls like IsForMeAddress.
+ NetworkService()->BindL((CProtocolBase*)iProtInbound, BindHookAll());
+
+ iManager = NetworkService()->Interfacer();
+
+ }
+
+
+void CProtocolNapt::ReadConfigurationFile()
+ /*
+ * Timer values are stored in Timer Class.
+ * iNaptTableScanInterval value should be less than 2147 seconds, as it is an argument
+ * to CTimer::After(TTimeIntervalMicroSeconds32).
+ */
+ {
+ iTimer->iNaptTableScanInterval = GetIniValue(NAPT_INI_TIMER,NAPT_INI_TABLESCANINTERVAL,KTableScanIntervalDefault,1,KTimerMaxSeconds);
+ iTimer->iNaptTcpIdleTimeout = GetIniValue(NAPT_INI_TIMER,NAPT_INI_TCPIDLETIMEOUT,KTcpIdleTimeOutDefault,1,KMaxTInt);
+ iTimer->iNaptUdpIdleTimeout = GetIniValue(NAPT_INI_TIMER,NAPT_INI_UDPIDLETIMEOUT,KUdpIdleTimeoutDefault,1,KMaxTInt);
+ iTimer->iNaptIcmpIdleTimeout = GetIniValue(NAPT_INI_TIMER,NAPT_INI_ICMPIDLETIMEOUT,KIcmpIdleTimeoutDefault,1,KMaxTInt);
+ iTimer->iNaptTcpCloseTimeout = GetIniValue(NAPT_INI_TIMER,NAPT_INI_TCPCLOSETIMEOUT,KTcpCloseTimeoutDefault,1,KMaxTInt);
+ iTimer->iNaptTcpOpenTimeout = GetIniValue(NAPT_INI_TIMER,NAPT_INI_TCPOPENTIMEOUT,KTcpOpenTimeoutDefault,1,KMaxTInt);
+ }
+
+
+TInt CProtocolNapt::GetIniValue(const TDesC& aSection, const TDesC& aName, TInt aDefault, TInt aMin, TInt aMax)
+ /*
+ * Timer values are read from the configuration file-napt.ini
+ * If the configuration values are not present default values are stored
+ */
+ {
+ TInt value;
+ CESockIniData* config = NULL;
+
+ TRAP_IGNORE(config = CESockIniData::NewL(NAPT_INI_DATA));
+ if (config==NULL || !config->FindVar(aSection, aName, value))
+ {
+ value = aDefault;
+ }
+ else if (value < aMin || value > aMax)
+ {
+ value = aDefault;
+ }
+ delete config;
+ return value;
+ }
+
+
+TInt CProtocolNapt::ApplyL(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
+/*
+ * This function is called for all the packets coming from interfce. This instance of
+ * ApplyL will be called for forwarding hook as well as inbound hook. Packets are
+ * translated for both inbound and forwarding packets. Scope is being set for packet
+ * destined to private interface.
+ * @param aPacket
+ * @param aInfo
+*/
+ {
+ const TInetAddr& dest = aInfo.iDstAddr;
+ const TInetAddr& src= aInfo.iSrcAddr;
+ const TUint32 ifindex = aInfo.iInterfaceIndex;
+ TInetAddr addr(aInfo.iSrcAddr);
+ LOG(Log::Printf(_L("packet received from interface index=[%d] and source ip address is:%x"),ifindex,addr.Address()));
+
+ iCurConfigInfo = iConfigMgr->FindConfig(ifindex);
+ if(!iCurConfigInfo)
+ {
+
+ LOG(Log::Printf(_L("No configuration information for interface index=[%d]"),ifindex));
+ return KIp6Hook_PASS;
+ }
+
+ //This Flag will make code to traverse extra check.If this is true then code
+ //will see if scope of packet and private interface match or not.
+ TBool checkScopeFlag= EFalse;
+
+ //This bit will be used in checking the scope of packet
+ const TIp6Addr& packetScopeIp = dest.Ip6Address();
+ TUint packetScope=KIapUnDefined;
+
+
+ LOG(Log::Printf(_L("I belong to protocol family--version=[%d]"),aInfo.iVersion));
+
+ //check for IP version.
+ if(aInfo.iVersion==4)
+ {
+ LOG(Log::Printf(_L("\tInterface Index --Private IAP=[%d],Public IAP=[%d]"), iCurConfigInfo->iPrivateIap ,iCurConfigInfo->iPublicIap));
+
+ const TIp6Addr& source = iCurConfigInfo->iPrivateIp.Ip6Address();
+
+ //Find NET ID i.e. scope for Private Interface. explanation given below.
+ iCurConfigInfo->iScopeSrc = iManager->RemoteScope(source ,iCurConfigInfo->iPrivateIap ,EScopeType_IAP);
+
+
+
+ //giving iPublicGatewayIP information to tranlsation table manager
+ iNaptMapMgr.iPublicGatewayIP=iCurConfigInfo->iPublicGatewayIP.Address();
+
+ const TIp6Addr& downlink = iCurConfigInfo->iPublicGatewayIP.Ip6Address();
+
+ //Take public interface scope.This will be use in Routing.IAP and Interface IP will
+ //select scope i.e. NET ID.
+ /*
+ Each interface is assigned 16 scope identifiers, one for each scope level (1..16).
+ The set of scope identifiers in each of the interfaces defines a virtual forest of trees (of depth 16),
+ where the actual interfaces are the leaf nodes.
+ Each scope id at net level (16) defines it's own tree.
+
+ scope=16 net=1 net=1
+ | |
+ scope=14 Global=1 Global=1
+ | | / \
+ | | | |
+ | | | |
+ scope=2 IAP = 1 IAP=2 IAP=3
+ / \ | |
+ scope=1 if=1 if=2 if=3 if=4
+
+
+ */
+ iCurConfigInfo->iScopedest = iManager->RemoteScope(downlink ,iCurConfigInfo->iPublicIap ,EScopeType_IAP);
+
+
+
+ //Check if source IP of packet and destination IP is same. If yes then extra check
+ //to find if scope of packet and private Interface match or not
+ if((iCurConfigInfo->iPublicGatewayIP.Address())==(src.Address()))
+ {
+ checkScopeFlag=ETrue;
+ }
+ if(checkScopeFlag)
+ {
+ //Extract scope of the packet.This will help in deciding what type of packet neet translation
+ //This fundamental will be quite helpful when subnet for private and public IP will be same
+ packetScope =iManager->RemoteScope(packetScopeIp , aInfo.iInterfaceIndex ,EScopeType_IF);
+ }
+
+ //translate accoring to the private range and netmask specified.Extra check is added for the packets coming from
+ //private interface to be translated.This check is that packet coming from private scope with relevant
+ //subnet should be translated.the check is if(packetScope!=iSrcScope) then dont translate.This will resolve issue
+ //of private and public IP being same
+ if(iCurConfigInfo->iPrivateIp.Match(aInfo.iSrcAddr,iCurConfigInfo->iNetMaskLength)&& !(dest.Match(iCurConfigInfo->iPrivateIp,iCurConfigInfo->iNetMaskLength)))
+ {
+#ifdef SYMBIAN_NETWORKING_ADDRESS_PROVISION
+ if((src.Address() != iCurConfigInfo->iProvisionedIp) || ! iCurConfigInfo->iUplinkAccess)
+ {
+ LOG(Log::Printf(_L("No forward translation %d:"), KIp6Hook_PASS));
+ return KIp6Hook_PASS;
+ }
+#endif //SYMBIAN_NETWORKING_ADDRESS_PROVISION
+ LOG(
+ TBuf<70> tmpSrc;
+ TBuf<70> tmpDst;
+ TInetAddr::Cast(aInfo.iSrcAddr).OutputWithScope(tmpSrc);
+ TInetAddr::Cast(aInfo.iDstAddr).OutputWithScope(tmpDst);
+ LOG(Log::Printf(_L("\t Hi I am packet coming from private interface and need translation\n src=[%S] dst=[%S] proto=%d"), &tmpSrc, &tmpDst, aInfo.iProtocol));
+ LOG(Log::Printf(_L("I am in Forwarding hook of NAPT")));
+ );
+
+ //Intelligence maintained if public and private ip are same
+
+ if(aInfo.iProtocol==KProtocolInetUdp ||aInfo.iProtocol== KProtocolInetTcp)
+ {
+ if(checkScopeFlag)
+ {
+ //No translatation will happen if Pubilc and private IP are same. Stack panics if
+ //this happens. No need for translation just pass it.
+ LOG(Log::Printf(_L("public IP is same as client IP. Sorry no translation")));
+
+ //check if scope for packet matches scope of private interface ot not. If not then dont
+ //manipulate
+ if(packetScope!=iCurConfigInfo->iScopeSrc)
+ {
+ return KIp6Hook_PASS;
+ }
+ }
+ //Packet manipulation TCP/UDP
+ ForwardManipulation(aPacket,aInfo);
+ }//udp and tcp
+
+ else if(aInfo.iProtocol == KProtocolInetIcmp)
+ {
+ if(checkScopeFlag)
+ {
+ //No translatation will happen if Pubilc and private IP are same. Stack panics if
+ //this happens. No need for translation just pass it.
+ LOG(Log::Printf(_L("public IP is same as client IP. Sorry no translation")));
+
+ //check if scope for packet matches scope of private interface ot not. If not then dont
+ //manipulate
+ if(packetScope!=iCurConfigInfo->iScopeSrc)
+ {
+ return KIp6Hook_PASS;
+ }
+ }
+ else if(dest.Address()== iCurConfigInfo->iPublicGatewayIP.Address())
+ {
+ //This is quite special case PINGING Public Gateway wont require NAPT
+ return KIp6Hook_PASS;
+ }
+
+ //Packet manipulation ICMP
+ IcmpHandlerForward(aPacket,aInfo);
+ } //ICMP
+ } //end check for packets coming from private interface.
+ else if(iCurConfigInfo->iPrivateIp.Match(aInfo.iDstAddr,iCurConfigInfo->iNetMaskLength)&& !(iCurConfigInfo->iPrivateIp.Match(aInfo.iSrcAddr,iCurConfigInfo->iNetMaskLength)))
+ {
+ // 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(iCurConfigInfo->iScopeSrc);
+ }
+ //Pass all packets which dont need translation
+ else
+ {
+ return KIp6Hook_PASS;
+ }
+
+ } // Closing If of Version Check
+
+ return KIp6Hook_PASS;
+ } //Function close
+
+
+
+
+
+void CProtocolNapt::ForwardManipulation(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
+ {
+
+ LOG(Log::Printf(_L("CProtocolNapt::ForwardManipulation called for outgoing packets to global interface")));
+ //retrieve information from aInfo. This information will be maintained in the transation
+ //table.
+ TUint lSrcPort;
+ TUint lDstPort;
+
+ //Declarations of IP to be stored in table.
+ const TUint32 sourceIP =(TInetAddr::Cast(aInfo.iSrcAddr)).Address();
+ const TUint32 destinationIP=(TInetAddr::Cast(aInfo.iDstAddr)).Address();
+ const TUint32 targetIP= iCurConfigInfo->iPublicGatewayIP.Address();
+ TUint translatedPort;
+
+ TInet6Checksum<TInet6HeaderIP4> lIp(aPacket);
+
+ //IP header Length ....used to access UDP header
+ TInt lengthIP = lIp.iHdr->HeaderLength();
+
+ CNaptIPPortMap* table=NULL;
+
+ if(aInfo.iProtocol==KProtocolInetUdp)
+ {
+ //UDP header
+ TInet6Packet<TInet6HeaderUDP> lUdp(aPacket,lengthIP);
+ lSrcPort=lUdp.iHdr->SrcPort();
+ lDstPort =lUdp.iHdr->DstPort();
+
+
+ //Check if entry is needed or not.If result is KErrNone then record exsists in the table.
+ TRAPD(ret,table=iNaptMapMgr.FindOrCreateNaptEntryL(KProtocolInetUdp ,sourceIP, destinationIP,lSrcPort ,lDstPort, iCurConfigInfo));
+
+ if(table==NULL || (ret == KErrNoMemory))
+ {
+ LOG(Log::Printf(_L("I am UDP packet from private Interface and I need translation")));
+ return;
+ }
+
+ //Get translated port from the table.
+ TUint translatedPort = table->iTrPort;
+
+ //Set translated port in the UDP header
+ lUdp.iHdr->SetSrcPort(translatedPort);
+ aInfo.iSrcAddr.SetPort(translatedPort);
+
+
+ //Set source IP of packet as public IP (public refer to Gateway)
+ lIp.iHdr->SetSrcAddr(targetIP);
+ TInetAddr::Cast(aInfo.iSrcAddr).SetV4MappedAddress(targetIP);
+
+ //Setting source scope i,e networkID as zero this will allow stack to to set source scope
+ //for packet.
+ 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);
+
+ //Compute checksum zero for UDP
+ lUdp.iHdr->SetChecksum(0);
+
+ //Compute IP checksum
+ lIp.ComputeChecksum();
+ aInfo.iFlags &= ~KIpAddressVerified;
+
+ }//Protocol Check UDP
+
+ // Section for manipulating TCP packets.
+ else if(aInfo.iProtocol==KProtocolInetTcp)
+ {
+ TInet6Checksum<TInet6HeaderTCP> lTcp(aPacket,lengthIP);
+ lSrcPort = lTcp.iHdr->SrcPort();
+ lDstPort = lTcp.iHdr->DstPort();
+
+ //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(KProtocolInetTcp ,sourceIP, destinationIP,lSrcPort ,lDstPort, iCurConfigInfo));
+
+ if(table==NULL || (ret==KErrNoMemory))
+ {
+ LOG(Log::Printf(_L("I am TCP packet from private Interface and I need translation")));
+ return ;
+ }
+
+
+ //Get last translated port
+ translatedPort = table->iTrPort;
+
+ lTcp.iHdr->SetSrcPort(translatedPort);
+ aInfo.iSrcAddr.SetPort(translatedPort);
+
+ 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);
+
+ //this one is to avoid armv5 errors and calculate checksum right
+ RMBufChain& payload = static_cast<RMBufChain&>(aPacket);
+
+ //checksum calculations
+ lTcp.ComputeChecksum(payload,&aInfo,lengthIP);
+ lIp.ComputeChecksum();
+
+ aInfo.iFlags &= ~KIpAddressVerified;
+
+
+ iNaptMapMgr.HandleTcpConnectionPhases(lTcp,table,KTcpClosePacketOUT);
+ }//Protocol Check TCP
+
+ }
+
+
+
+void CProtocolNapt::Describe(TServerProtocolDesc& anEntry)
+/* Protocol Description
+ * @param anEntry
+*/
+ {
+ anEntry.iName=KProtocolNaptName;
+ anEntry.iAddrFamily=KAfInet;
+ anEntry.iSockType=KSockDatagram;
+ anEntry.iProtocol=KProtocolNAPT;
+ anEntry.iVersion=TVersion(1, 0, 0);
+ anEntry.iByteOrder=EBigEndian;
+ anEntry.iServiceInfo=KSIDatagram | KSIConnectionLess;
+ anEntry.iNamingServices=0;
+ anEntry.iSecurity=KSocketNoSecurity;
+ anEntry.iMessageSize=0xffff;
+ anEntry.iServiceTypeInfo=0;
+ anEntry.iNumSockets=KUnlimitedSockets;
+ anEntry.iServiceTypeInfo=ESocketSupport | EInterface;
+
+ }
+
+
+
+
+/*
+----------------------------------------------------------------------------------------------------
+ CProtocolNaptIn code
+----------------------------------------------------------------------------------------------------
+The following code is for inbound Hook.This hook will be bind for all the packets coming from the
+all the interfaces.But it will trigger for only packets whose entry is there in translation table.
+*/
+
+
+
+CProtocolNaptIn::CProtocolNaptIn(CProtocolNapt* aNapt)
+/*
+ * Consturctor
+*/
+
+ {
+ //giving pointer to CProtocolNapt for table manipulation. Now Pointer check
+ //is quite important here
+ if(aNapt!=NULL)
+ {
+ iNapt=aNapt;
+ iConfigMgr = iNapt->iConfigMgr;
+ }
+ else
+ {
+ Panic(ENAPTPanic_BadCall);
+
+ }
+ }// end constructor
+
+
+CProtocolNaptIn::~CProtocolNaptIn()
+/*
+ * Destructor
+ */
+ {
+ }
+
+
+
+TInt CProtocolNaptIn::ApplyL(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
+/**
+* Function for incoming packets coming from all the interface.
+* Only translate packets whos entry is there in Tanslation table.The query is made to translation table
+* for entry if not found then PASS packets else Tanslate packets and then pass.
+* @param aPacket
+* @param aInfo
+**/
+ {
+ TInt ret=KIp6Hook_PASS;
+
+ //only manipulate packets with IPv4 header other should not be tempered.
+ if(aInfo.iVersion==4)
+ {
+ LOG(Log::Printf(_L("Hi I am packet .I am in Inbound hook of NAPT")));
+ if(aInfo.iProtocol==KProtocolInetUdp || aInfo.iProtocol== KProtocolInetTcp)
+ {
+ //udp and tcp packets coming from all interfaces
+ ret=IncomingPacketManipulation(aPacket,aInfo);
+ }
+ else if(aInfo.iProtocol == KProtocolInetIcmp)
+ {
+ //ICMP packets.
+ ret=IcmpHandler(aPacket , aInfo);
+ }
+ }
+ return ret;
+ }
+
+TInt CProtocolNaptIn::IncomingPacketManipulation(RMBufHookPacket& aPacket, RMBufRecvInfo& aInfo)
+/**
+* Function for incoming packets coming from all the interface.
+* Only translate packets whos entry is there in Tanslation table.The query is made to translation table
+* for entry if not found then PASS packets else Tanslate packets and then pass.
+* @param aPacket
+* @param aInfo
+**/
+ {
+
+ TUint lDstPort;
+ const TUint32 srcIp = (TInetAddr::Cast(aInfo.iSrcAddr)).Address();
+
+ // This flag states that packets have been translated and that KIp6Hook_DONE should be used as return value
+ TBool translatedFlag = EFalse;
+
+ CNaptIPPortMap* table= NULL;
+ TNaptConfigInfo* info = NULL;
+
+ TInet6Checksum<TInet6HeaderIP4> lIp(aPacket);
+ TInt lengthIP = lIp.iHdr->HeaderLength();
+
+ //if node exist and if destination IP is same as targetIp ( this is just to cross check)
+ if(aInfo.iProtocol==KProtocolInetUdp)
+ {
+
+ //UDP packet. Took port information in second line.
+ TInet6Packet<TInet6HeaderUDP> lUdp(aPacket,lengthIP);
+ lDstPort= lUdp.iHdr->DstPort();
+
+ //get translated table node
+ table = iNapt->iNaptMapMgr.GetIPTranslationNode(lDstPort);
+
+ if (table)
+ {
+ //Take original IP and Port number from the table.
+ TUint32 originalIP;
+
+ originalIP=table->iSrcIpAddr;
+ TUint orgPort = table->iSrcPort;
+ info = table->iConfigInfo;
+
+ if (iNapt->iNaptMapMgr.VerifySender(table,srcIp,lUdp.iHdr->SrcPort()))
+ {
+ LOG(Log::Printf(_L("Udp packet translated...see IP's below")));
+
+ lUdp.iHdr->SetDstPort(orgPort);
+ aInfo.iDstAddr.SetPort(orgPort);
+
+ lIp.iHdr->SetDstAddr(originalIP);
+ TInetAddr::Cast(aInfo.iDstAddr).SetV4MappedAddress(originalIP);
+
+ //Compute checksum zero for UDP
+ lUdp.iHdr->SetChecksum(0);
+
+ //Compute IP checksum
+ lIp.ComputeChecksum();
+
+ //This flag states that packets are translated and should be Done
+ translatedFlag = ETrue;
+ }//verify sender
+ }//table
+ }//udp
+
+ else if(aInfo.iProtocol==KProtocolInetTcp)
+ {
+ //TCP packet.Took Port information in second line.
+ TInet6Checksum<TInet6HeaderTCP> lTcp(aPacket,lengthIP);
+ lDstPort =lTcp.iHdr->DstPort();
+
+ //get translated table node
+ table = iNapt->iNaptMapMgr.GetIPTranslationNode(lDstPort);
+ if (table)
+ {
+ TUint32 originalIP;
+ originalIP=table->iSrcIpAddr;
+ TUint orgPort = table->iSrcPort;
+ info = table->iConfigInfo;
+
+ //check for match
+ if (iNapt->iNaptMapMgr.VerifySender(table,srcIp,lTcp.iHdr->SrcPort()))
+ {
+ LOG(Log::Printf(_L("Tcp packet translated...see IP's below")));
+
+ //Change port information. Replace translated port by original port.
+ lTcp.iHdr->SetDstPort(orgPort);
+ aInfo.iDstAddr.SetPort(orgPort);
+
+ //Change IP address.Replace translate IP by original IP.
+ lIp.iHdr->SetDstAddr(originalIP);
+ TInetAddr::Cast(aInfo.iDstAddr).SetV4MappedAddress(originalIP);
+
+ //this one is to avoid armv5 errors and calculate checksum right
+ RMBufChain& payload = static_cast<RMBufChain&>(aPacket);
+
+ //Compute checksum
+ lTcp.ComputeChecksum(payload,&aInfo,aInfo.iOffset);
+ lIp.ComputeChecksum();
+
+ //This flag states that packets are translated and should be Done
+ translatedFlag = ETrue;
+
+ iNapt->iNaptMapMgr.HandleTcpConnectionPhases(lTcp,table,KTcpClosePacketIN);
+
+
+ }//verify sender
+ }//table
+ }//tcp
+
+ 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 packet values are after translation \n src=[%S] dst=[%S] proto=%d"), &tmpSrc, &tmpDst, aInfo.iProtocol));
+ LOG(Log::Printf(_L("I am in Inbound hook of NAPT")));
+ );
+ // 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.
+ if(!iNapt->iCurConfigInfo)
+ LOG(Log::Printf(_L("I am in Inbound hook of NAPT, but no Current Configuration for incoming packet")));
+ TInetAddr::Cast(aInfo.iDstAddr).SetScope(info->iScopeSrc);
+
+ return KIp6Hook_DONE;
+ }
+ return KIp6Hook_PASS;
+ }
+
+
+
+CServProviderBase* CProtocolNapt::NewSAPL(TUint aProtocol)
+/**
+ * Service Access point for the Protocol. Service Access Point supports sockets and allow them
+ * to manipulate protocol. aProtocol is the instance of protocol for which SAP is required.
+**/
+
+ {
+ //avoid warning.
+ (void)aProtocol;
+
+ CSapNapt *nsap = NULL;
+
+ nsap = new(ELeave) CSapNapt;
+ nsap->iProtocol=this;
+ nsap->iConfigMgr = this->iConfigMgr;
+ iSapList.AppendL(nsap);
+ return nsap;
+ }
+
+
+void CProtocolNapt::CancelSap(CSapNapt *aSap)
+/**
+ * This method clears the instance of SAP contained in the SAP table of the protocol.
+ * @param aSap - intance to be set to NULL
+ * @return None
+ *
+**/
+
+ {
+ LOG(Log::Printf(_L("CProtocolNapt::CancelSap...Deleting SAP:%d"), aSap));
+ TInt index = iSapList.Find(aSap);
+
+ //Delete the config and set the reference of the SAP being deleted to NULL
+ if(index != KErrNotFound)
+ {
+ iSapList[index]->iConfigMgr->DeleteConfig(aSap->iConfigInfo);
+ iSapList[index] = NULL;
+ iSapList.Compress();
+ }
+ }
+
+/*
+------------------------------------------------------------------------------------------
+
+ SAP UNUSED FUNTION SECTION
+------------------------------------------------------------------------------------------
+
+SAP definion which are not being used.These functions are not doing anything instead they are
+returning nothing from it.
+
+*/
+
+void CSapNapt::Ioctl(TUint /*level*/,TUint /*name*/,TDes8*/*anOption*/)
+ {}
+
+void CSapNapt::Start()
+ {}
+
+void CSapNapt::Shutdown(TCloseType /*option*/)
+ {}
+
+void CSapNapt::LocalName(TSockAddr& /*anAddr*/) const
+ {}
+
+TInt CSapNapt::SetLocalName(TSockAddr& /*anAddr*/)
+ {
+ return KErrNotSupported;
+ }
+
+void CSapNapt::RemName(TSockAddr& /*anAddr*/) const
+ {}
+
+TInt CSapNapt::SetRemName(TSockAddr& /*anAddr*/)
+ {
+ return KErrNotSupported;
+ }
+
+TInt CSapNapt::GetOption(TUint aLevel, TUint aName, TDes8& aOption)const
+/**
+ * This implements GetOption method for Napt specific service provider.
+ * @param aLevel
+ * @param aName
+ * @param anOption
+ * @return KErrNone in case of success
+**/
+ {
+ TInt err = KErrNone;
+
+ const TUplinkInfo* info= reinterpret_cast<const TUplinkInfo* >(aOption.Ptr());
+ if(aLevel == KSolNapt && aName == KSoNaptUplink)
+ {
+ if(aOption.Length()!=sizeof(TUplinkInfo))
+ {
+ //this means that Block is not filled properly
+ return KErrArgument;
+ }
+ TNaptConfigInfo* conf = iConfigMgr->FindConfig(info->iPrivateIap, EFalse);
+ if(conf != NULL)
+ {
+ TUplinkInfo upinfo;
+ upinfo.iPrivateIap = info->iPrivateIap;
+ upinfo.iPublicIap = conf->iPublicIap;
+ aOption.SetLength(sizeof(TUplinkInfo));
+ aOption.Copy((TUint8 *)&upinfo, sizeof(TUplinkInfo));
+
+ }
+ else
+ err = KErrNotFound;
+ }//For Uplink Information Option
+ else
+ {
+ //Wrong socket option name /level
+ err = KErrArgument;
+ }
+ return err;
+ }
+
+void CSapNapt::ActiveOpen()
+ {}
+
+TInt CSapNapt::PassiveOpen(TUint /*aQueSize*/)
+ {
+ return KErrNotSupported;
+ }
+
+void CSapNapt::Shutdown(TCloseType /*option*/,const TDesC8& /*aDisconnectionData*/)
+ {}
+
+void CSapNapt::AutoBind()
+ {}
+
+TInt CSapNapt::PassiveOpen(TUint /*aQueSize*/,const TDesC8& /*aConnectionData*/)
+ {
+ return KErrNotSupported;
+ }
+
+void CSapNapt::ActiveOpen(const TDesC8& /*aConnectionData*/)
+ {}
+
+void CSapNapt::CancelIoctl(TUint /*aLevel*/,TUint /*aName*/)
+ {}
+
+CSapNapt::~CSapNapt()
+ {
+ //Cancel configuration in sap.This will reset all bits (public & private IAP and IP)
+ iProtocol->CancelSap(this);
+ }
+
+
+