tcpiputils/tun/src/tun.cpp
branchRCL_3
changeset 63 425d8f4f7fa5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpiputils/tun/src/tun.cpp	Wed Sep 15 00:18:51 2010 +0300
@@ -0,0 +1,491 @@
+// Copyright (c) 2010 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 Inbound and Outbound hook
+// 
+//
+
+/**
+ @file
+ @internalTechnology 
+ */
+
+#include <udp_hdr.h>
+#include <in_chk.h>
+#include <es_prot_internal.h>
+#include "tun.pan"
+#include "tun.h"
+
+_LIT(KProtocolTunName, "tun");
+
+void Panic(TTunPanic aPanic)
+    {
+    User::Panic(_L("Tun panic"), aPanic);
+    }
+
+
+// ============================ MEMBER FUNCTIONS ==============================
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::CProtocolTun
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// ----------------------------------------------------------------------------
+//
+CProtocolTun::CProtocolTun ()
+    {}
+
+// Destructor
+CProtocolTun::~CProtocolTun ()
+    {
+    NetworkService()->Protocol()->Unbind((CProtocolBase*)iFlowinfo,0);
+    }
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::NewL
+// ----------------------------------------------------------------------------
+//
+CProtocolTun* CProtocolTun::NewL ()
+    {
+    CProtocolTun* self = new (ELeave) CProtocolTun();
+    CleanupStack::PushL(self);
+    self -> ConstructL ();
+    CleanupStack::Pop();
+    return self;
+    }
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::ConstructL
+// Initializes the CProtocolTun
+// ----------------------------------------------------------------------------
+//
+void CProtocolTun::ConstructL ()
+    {
+    iFlowinfo = new (ELeave) CTunFlowInfo();
+    iSapInstance = new (ELeave) CSapTun();
+    iSapInstance->iFlowInfo= iFlowinfo;
+    iSapInstance->iProtocol=this;
+    }
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::NetworkAttachedL
+// Binds the hooks (inbound, outbound flowhook and forward) to the IP6. 
+// ----------------------------------------------------------------------------
+//
+void CProtocolTun::NetworkAttachedL ()
+    {
+    // Outbound hook
+    NetworkService()->BindL ((CProtocolBase*) this, BindFlowHook());
+    }
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::NetworkDetached
+// Unbind the hooks.
+// ----------------------------------------------------------------------------
+//
+void CProtocolTun::NetworkDetached ()
+    {
+    // Do Nothing
+    // as the destructor does the rest 
+    }
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::Identify
+// Provide identification information to the caller.
+// ----------------------------------------------------------------------------
+//
+void CProtocolTun::Identify (TServerProtocolDesc & aEntry)
+    {
+    aEntry.iName = KProtocolTunName;
+    aEntry.iAddrFamily = KAfInet | KAfInet6;
+    aEntry.iSockType = KSockDatagram;
+    aEntry.iProtocol = KProtocolTUN;
+    aEntry.iVersion = TVersion (1, 0, 0);
+    aEntry.iByteOrder = EBigEndian;
+    aEntry.iServiceInfo=KSIDatagram | KSIConnectionLess;
+    aEntry.iNamingServices = 0;
+    aEntry.iSecurity = KSocketNoSecurity;
+    aEntry.iServiceTypeInfo=0;
+    aEntry.iMessageSize = 0xffff;
+    aEntry.iServiceTypeInfo = ESocketSupport | EInterface;
+    aEntry.iNumSockets = KUnlimitedSockets;
+    }
+
+void CProtocolTun::Identify (TServerProtocolDesc * aDesc) const
+{
+Identify (*aDesc);
+}
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::ApplyL
+// This is the handler for forwarding packets.
+// Udp encapsulation for the packets from the Virtual tunnel nif
+// ----------------------------------------------------------------------------
+//
+TInt CProtocolTun::ApplyL (RMBufHookPacket& /*aPacket*/, RMBufRecvInfo& /*aInfo*/)
+    {
+    return KIp6Hook_PASS;
+    };
+
+// ----------------------------------------------------------------------------
+// CProtocolTun:OpenL
+// Outbound Flow hook Open handler for the protocol. 
+// ----------------------------------------------------------------------------
+//
+MFlowHook *CProtocolTun::OpenL (TPacketHead& /*aHead*/, CFlowContext* aFlow)
+    {
+    // We are interested in this flow, let's create a new local flow instance
+    // create a local copy using copy ctor and return the instance
+    CTunFlowInfo *info = NULL; 
+    CNifIfBase* localNifBase = aFlow->Interface();
+    if(IsPortSet())
+        {
+        TInetAddr localAddr;
+        localAddr.SetPort(iAppPortNum);
+        TPckg<TInetAddr> pckgLocalAddr(localAddr);
+        if(localNifBase->Control(KSolInetIp,KSoTunnelPort,pckgLocalAddr)== KErrNone)
+            {
+            info = new (ELeave) CTunFlowInfo(iFlowinfo);
+            SetCNifBase(localNifBase);
+            }
+        }
+    return info;
+    }
+
+// ----------------------------------------------------------------------------
+// CProtocolTun::NewSAPL
+// Creation of a new SAP instance 
+// ----------------------------------------------------------------------------
+//
+CServProviderBase* CProtocolTun::NewSAPL(TUint /*aProtocol*/)
+    {
+#if 0
+    CSapTun *nsap = new(ELeave) CSapTun();//CSapTun::GetInstanceL();
+    nsap->iProtocol=this;
+    nsap->iFlowInfo= iFlowinfo;
+#endif
+    return iSapInstance;
+    }
+
+/**
+---------------------------------------------------------------------------------------
+                                CSapTun
+---------------------------------------------------------------------------------------
+
+This class is derived from CServProviderBase.CSapTun is the service class for sockets
+loading CProtocolTun.But here only one socket will be able to load protocol.If protocol once
+loaded other socket cannot service protocol by opening socket.
+ */
+
+//CSapTun* CSapTun::iInstance = NULL;
+
+CSapTun::CSapTun()
+    { }
+#if 0
+CSapTun* CSapTun::GetInstanceL()
+    {
+    if(!iInstance)
+        {
+        iInstance = new (ELeave) CSapTun();
+        }
+    return iInstance;
+    }
+#endif 
+TInt CSapTun::SetOption(TUint aName ,TUint aLevel ,const TDesC8& anOption)
+/** 
+ * This class is used to set PortNumber information to be used by the hook to perform
+ * UDP encapsulation.
+ * @param aName  -- KSoTunnelPort
+ * @param aLevel --KSolInetIp.
+ * return - KErrNone if no value is assigned else KErrPermissionDenied
+ **/
+
+    {
+    TInt err = KErrNotSupported;
+    if((aName == KSoTunnelPort) && (aLevel == KSolInetIp))
+        {
+        const TUint opt = *reinterpret_cast<const TUint*>(anOption.Ptr());
+        iProtocol->SetAppPortNum(opt);
+        iFlowInfo->SetAppPortNum(opt);
+        err= KErrNone;
+        }
+    return err;
+    }
+
+TInt CSapTun::SecurityCheck(MProvdSecurityChecker* aChecker)
+/**
+ * Capability check for the TUN Hook sockets.
+ *
+ * TUN Hook 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, "TUN Hook Loading failed.");
+    }
+
+/*
+------------------------------------------------------------------------------------------
+
+                        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 CSapTun::Ioctl(TUint /*level*/,TUint /*name*/,TDes8*/*anOption*/)
+    {}
+
+void CSapTun::Start()
+    {}
+
+void CSapTun::Shutdown(TCloseType /*option*/)
+    {}
+
+void CSapTun::LocalName(TSockAddr& /*anAddr*/) const
+{}
+
+TInt CSapTun::SetLocalName(TSockAddr& /*anAddr*/)
+    {
+    return KErrNotSupported;
+    }
+
+void CSapTun::RemName(TSockAddr& /*anAddr*/) const 
+{}
+
+TInt CSapTun::SetRemName(TSockAddr& /*anAddr*/) 
+    { 
+    return KErrNotSupported;
+    }
+
+TInt CSapTun::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
+ **/
+{
+return KErrNone;
+}
+
+
+void CSapTun::ActiveOpen()
+    {}
+
+TInt CSapTun::PassiveOpen(TUint /*aQueSize*/)
+    {
+    return KErrNotSupported;
+    }
+
+void CSapTun::Shutdown(TCloseType /*option*/,const TDesC8& /*aDisconnectionData*/)
+    {}
+
+void CSapTun::AutoBind()
+    {}
+
+TInt CSapTun::PassiveOpen(TUint /*aQueSize*/,const TDesC8& /*aConnectionData*/)
+    {
+    return KErrNotSupported;
+    }
+
+void CSapTun::ActiveOpen(const TDesC8& /*aConnectionData*/)
+    {}
+
+void CSapTun::CancelIoctl(TUint /*aLevel*/,TUint /*aName*/)
+    {}
+
+CSapTun::~CSapTun()
+    {
+    }
+
+// TUN OUTBOUND FLOW HOOK functions.
+
+// ----------------------------------------------------------------------------
+// CTunFlowInfo::CTunFlowInfo
+// ----------------------------------------------------------------------------
+CTunFlowInfo::CTunFlowInfo ()
+    {}
+
+// ----------------------------------------------------------------------------
+// CTunFlowInfo::~CTunFlowInfo
+// ----------------------------------------------------------------------------
+CTunFlowInfo::~CTunFlowInfo ()
+    {}
+
+// ----------------------------------------------------------------------------
+// CTunFlowInfo::ReadyL
+// The stack asks if the flow is ready to send. 
+// ----------------------------------------------------------------------------
+//
+TInt CTunFlowInfo::ReadyL (TPacketHead& /*aHead*/)
+    {
+    return EFlow_READY;
+    }
+
+// ----------------------------------------------------------------------------
+// CTunFlowInfo::ApplyL
+// Intial stage where the CTunFlowInfo touches the outgoing packet. 
+// ----------------------------------------------------------------------------
+TInt CTunFlowInfo::ApplyL(RMBufSendPacket & aPacket, RMBufSendInfo & aInfo)
+    {
+    const TInetAddr& dest = aInfo.iDstAddr;
+    const TInetAddr& src = aInfo.iSrcAddr;
+
+    TInt protocol = aInfo.iProtocol;
+
+    // protocolnum check is added to avoid loopin in the same hook as the 
+    // source and destination address will not be changed in the RMBufSendInfo.
+    if (dest.Address() == src.Address())
+        {
+        if (protocol == KProtocolInetIp  )
+            {
+            TInet6Packet<TInet6HeaderIP4> localIP(aPacket);
+            TUint protocol = localIP.iHdr->Protocol();
+
+            if (protocol == KProtocolInetUdp)
+                {
+                TInet6HeaderUDP* udpHdr = (TInet6HeaderUDP*) localIP.iHdr->EndPtr();
+                TUint srcPort = udpHdr->SrcPort();
+
+                if (srcPort == iAppPortNum)
+                    {
+                    // Ingress traffic forwarded from TUN Client Application. Trim the
+                    // outer header and send the original pkt back to the ip stack.
+                    TInt outerHdrLen = TInet6HeaderIP4::MinHeaderLength() + TInet6HeaderUDP::MinHeaderLength();
+
+                    // the info length will be updated by TrimStart
+                    aPacket.TrimStart(outerHdrLen);
+                    
+                    TInet6Packet<TInet6HeaderIP4> ip(aPacket);
+                    //Update the info Address information
+                    TInetAddr::Cast(aInfo.iSrcAddr).SetAddress(ip.iHdr->SrcAddr());
+                    TInetAddr::Cast(aInfo.iDstAddr).SetAddress(ip.iHdr->DstAddr());
+
+                    // restart the hook processing from the begining.
+                    return KIp6Hook_DONE;
+                    }
+                }
+            }
+#ifdef IPV6SUPPORT
+        else if (protocol == KProtocolInet6Ip)
+            {
+            TInet6Packet<TInet6HeaderIP> localIP6(aPacket);
+            TInt protocol = localIP6.iHdr->NextHeader();
+            if (protocol == KProtocolInetUdp)
+                {
+                TInet6HeaderUDP* udpHdr =
+                (TInet6HeaderUDP*) localIP6.iHdr->EndPtr();
+                TUint srcPort = udpHdr->SrcPort();
+
+                if (srcPort == iAppPortNum)
+                    {
+                    // Ingress traffic forwarded from TUN Client Application. Trim the
+                    // outer header and send the original pkt back to the ip stack.
+                    TInt outerHdrLen = TInet6HeaderIP::MinHeaderLength()
+                    + TInet6HeaderUDP::MinHeaderLength();
+
+                    // the info length will be updated by TrimStart
+                    aPacket.TrimStart(outerHdrLen);
+                    
+                    TInet6Packet<TInet6HeaderIP> ip6(aPacket);
+                    //Update the info Address information
+                    TInetAddr::Cast(aInfo.iSrcAddr).SetAddress(ip6.iHdr->SrcAddr());
+                    TInetAddr::Cast(aInfo.iDstAddr).SetAddress(ip6.iHdr->DstAddr());
+
+                    // restart the hook processing from the begining.
+                    return KIp6Hook_DONE;
+                    }
+                else
+                    {
+                    return KIp6Hook_PASS;
+                    }
+                }
+            }
+#endif //IPV6SUPPORT
+        else
+            {
+            Panic(ETunPanic_BadHeader);
+            }
+       }
+    else 
+        {
+        // Outgoing packet from the application to the TUN Client Application
+        // need to mark this packet to be handled at Forward hook.
+
+        if (protocol == KProtocolInetIp)
+            {
+            TInet6Packet<TInet6HeaderIP4> ip(aPacket);
+            TInt tmpTos = ip.iHdr->TOS();
+            tmpTos |= KTunTos;
+            ip.iHdr->SetTOS(tmpTos);
+            TInet6Checksum<TInet6HeaderIP4> lIp(aPacket);
+            lIp.ComputeChecksum(); // recompute checksum as TOS field is updated
+            }
+#ifdef IPV6SUPPORT
+        else if (protocol == KProtocolInet6Ip)
+            {
+            TInet6Packet<TInet6HeaderIP> ip6(aPacket);
+            TInt tmpTrafficClass = ip6.iHdr->TrafficClass();
+            tmpTrafficClass |= KTunTos;
+            ip6.iHdr->SetTrafficClass(tmpTrafficClass);
+            // No need to update checksum in case of IPV6
+            }
+#endif //IPV6SUPPORT        
+        else
+            {
+            Panic(ETunPanic_BadHeader);
+            }
+        return KIp6Hook_PASS;
+        }
+   
+    return KIp6Hook_PASS;
+    }
+
+
+// ----------------------------------------------------------------------------
+// CTunFlowInfo::Open
+// Open the flow, keep reference count.
+// ----------------------------------------------------------------------------
+//
+
+void CTunFlowInfo::Open ()
+    {
+    iRef++;
+    }
+
+// ----------------------------------------------------------------------------
+// CTunFlowInfo::Close
+// Close the flow if the reference count has reached zero. Remove the flow 
+// from any list it is stored.
+// ----------------------------------------------------------------------------
+//
+void CTunFlowInfo::Close ()
+    {
+    if (--iRef < 0)
+        {
+        delete this;
+        }
+    }
+