diff -r 8d540f55e491 -r 425d8f4f7fa5 tcpiputils/tun/src/tun.cpp --- /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 +#include +#include +#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 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(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 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 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 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 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 ip(aPacket); + TInt tmpTos = ip.iHdr->TOS(); + tmpTos |= KTunTos; + ip.iHdr->SetTOS(tmpTos); + TInet6Checksum lIp(aPacket); + lIp.ComputeChecksum(); // recompute checksum as TOS field is updated + } +#ifdef IPV6SUPPORT + else if (protocol == KProtocolInet6Ip) + { + TInet6Packet 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; + } + } +