diff -r 000000000000 -r af10295192d8 networkingtestandutils/ipv6to4tunnel/src/6to4.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/networkingtestandutils/ipv6to4tunnel/src/6to4.cpp Tue Jan 26 15:23:49 2010 +0200 @@ -0,0 +1,504 @@ +// Copyright (c) 2004-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: +// Name : 6to4.cpp +// Part of : 6to4 plugin / 6to4.prt +// Implements 6to4 automatic and configured tunnels, see +// RFC 3056 & RFC 2893 +// Version : 0.2 +// + + + + +// INCLUDE FILES +#include +#include +#include +#include +#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS +#include +#endif + +#include "6to4.h" +#include "6to4_flow.h" +#include "6to4_listener.h" +#include "6to4_tunnel.h" + +// EXTERNAL DATA STRUCTURES +// EXTERNAL FUNCTION PROTOTYPES +// CONSTANTS +// MACROS +// LOCAL CONSTANTS AND MACROS + + +// This is a route that is needed for system to pass automatic tunneled +// packets (2002::/16) to the 6to4 module. +const TIp6Addr K6to4Prefix = + { {{0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} }; + +static const union {TUint8 a[4]; TUint32 b;} v4Prefix = { {0, 0, 0xff, 0xff} }; + + +// MODULE DATA STRUCTURES +// LOCAL FUNCTION PROTOTYPES +// FORWARD DECLARATIONS + +// ============================= LOCAL FUNCTIONS ============================== + +// ============================ MEMBER FUNCTIONS ============================== + +// ---------------------------------------------------------------------------- +// CProtocol6to4::CProtocol6to4 +// C++ default constructor can NOT contain any code, that +// might leave. +// ---------------------------------------------------------------------------- +// +CProtocol6to4::CProtocol6to4 () + { + } + +// Destructor +CProtocol6to4::~CProtocol6to4 () + { + delete iConfig; + delete iEventListener; + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4::InitL +// Initializes the 6to4. +// ---------------------------------------------------------------------------- +// +void CProtocol6to4::InitL (TDesC & aTag) + { + CProtocolBase::InitL (aTag); + + // There are two configuration files. The first one, 6to4.ini + // just defines the file name where the tunnels are located. + // Because the tunnel file is of variable length, it can't + // be parsed in ordinary Symbian way, but it needs it's own parser. + LoadConfigurationFile (); + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4::LoadConfigurationFile +// Reads first file K6to4IniData, e.g., 6to4.ini, and finds out the file +// where the configured tunnels are defined. Then parses and creates the +// configured tunnels. +// ---------------------------------------------------------------------------- +// +TBool CProtocol6to4::LoadConfigurationFile () + { + if (iConfig) + return EFalse; // Already loaded! + + // if iConfigErr != 0 (KErrNone), then an attempt for + // loading configuration has been made and failed, + // assume it never will succeed and avoid further + // attemps on each FindVar... + if (iConfigErr) + return EFalse; + + LOG (Log::Printf (_L ("CProtocol6to4::LoadConfigurationFile(): %S\r\n"), &K6To4IniData)); + TRAP(iConfigErr, iConfig = CESockIniData::NewL (K6To4IniData)); + + if (iConfigErr) + return EFalse; + + if (iConfig) + { + TPtrC tunnelIniFile; + // Read initialization file name, e.g., 6to4_tunnels.ini. + if (iConfig->FindVar (K6To4IniSectionTunnels, K6To4IniTunnelFile, tunnelIniFile)) + { + // Parse the 6to4_tunnels.ini (or what was defined in 6to4.ini). + // NOTE: iConfigErr use must be removed when other definitions + // than configuded tunnels are possible in K6To4IniData file -tom + TRAP(iConfigErr, LoadFileL (tunnelIniFile)); + if (iConfigErr) + return EFalse; + } + // Missing K6To4IniSectionTunnels is fine + } + return ETrue; + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4::NetworkAttachedL +// Binds the hooks (inbound & outbound) to the IP6. Creates virtual interfaces +// for tunneled packets. The automatically tunneled packets are handled by +// virtual interface 6to4, and the configured tunneled packets by virtual +// interface named according to the tunnel name. The compatibility to the +// TCP/IP stack version is also checked (if not compatible, a log message is +// printed). Registers a listener for interface IP addresses. That is used for +// filtering purposes. +// ---------------------------------------------------------------------------- +// +void CProtocol6to4::NetworkAttachedL () + { + // Outbound hook + NetworkService()->BindL (this, BindFlowHook ()); + + // Inbound hook, 41 == IPv6 inner + NetworkService()->BindL (this, BindHookFor (KProtocolInet6Ipip)); + // Inbound hook, 4, == IPv4 inner + NetworkService()->BindL(this, BindHookFor (KProtocolInetIpip)); + + MInterfaceManager *const ifmgr = NetworkService ()->Interfacer(); + + ifmgr->AddRouteL (K6to4Prefix, 16, K6to4); + // Create a new virtual interface "6to4" for the 6to4. This is used for + // automatic tunneling. The interface index of this virtual interface + // is saved to this object. + const MInterface *const m = ifmgr->Interface (K6to4); + iInterfaceIndex = m->Index (); + + // For each configured tunnel, the same thing is needed. The route is + // established using configured ip address and prefix information. The + // virtual interface gets the name according to the configured tunnel name. + // The virtual interface index is stored to the CTunnel object. + TTunnelQueueIter iter (iTunnelParser.TunnelQueue()); + CTunnel *tunnel = NULL; + while ((tunnel = iter++) != NULL) + { + ifmgr-> AddRouteL (tunnel->RouteAddr(), tunnel->RoutePrefixLength(), tunnel->Name()); + ifmgr-> AddRouteL (tunnel->VirtualIfAddr(), 128, tunnel->Name(), KRouteAdd_MYPREFIX); + const MInterface *const vif = ifmgr->Interface (tunnel->Name()); + tunnel->SetInterfaceIndex(vif->Index ()); + } + + // The event service was not available, so to make sure it's there, this + // Check is made. Prints a log message if any problems. + CheckCompatibility (); + + if (iEventService) + { + // A listener is needed for getting information on ip addresses + // that are added/deleted to/from certain interfaces. This + // information is used for filtering incoming packets from + // malicious senders. + delete iEventListener; + iEventListener = NULL; + iEventListener = new (ELeave) C6to4Listener (NetworkService(), *iEventService); + } + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4::NetworkDetached +// Unbind the hooks. +// ---------------------------------------------------------------------------- +// +void CProtocol6to4::NetworkDetached () + { + delete iEventListener; + iEventListener = NULL; + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4::Identify +// Provide identification information to the caller. +// ---------------------------------------------------------------------------- +// +void CProtocol6to4::Identify (TServerProtocolDesc & aEntry) + { + aEntry.iName = K6to4; + aEntry.iAddrFamily = KAfInet6; + aEntry.iSockType = KSockDatagram; + aEntry.iProtocol = KProtocolInet6Ipip; + aEntry.iVersion = TVersion (1, 0, 0); + aEntry.iByteOrder = EBigEndian; + // aEntry.iServiceInfo=KSIDatagram | KSIConnectionLess; + aEntry.iServiceInfo = + KSIConnectionLess | KSIMessageBased | KSIBroadcast | KSIPeekData | + KSIGracefulClose; + aEntry.iNamingServices = 0; + aEntry.iSecurity = KSocketNoSecurity; + aEntry.iMessageSize = 0xffff; + aEntry.iServiceTypeInfo = EPreferMBufChains | ENeedMBufs; + aEntry.iNumSockets = KUnlimitedSockets; + } + +void CProtocol6to4::Identify (TServerProtocolDesc * aDesc) const + { + Identify (*aDesc); + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4::ApplyL +// This is the handler for incoming packets. Detunnel legal packets. +// ---------------------------------------------------------------------------- +// +TInt CProtocol6to4::ApplyL (RMBufHookPacket & aPacket, RMBufRecvInfo & aInfo) + { + if (aInfo.iIcmp) + { + // This is a returned packet inside an ICMP. Could check whether the + // IP header is the tunneling generated by this packet and do something + // about it, but for now, just ignore and let someone else deal with it. + return KIp6Hook_PASS; + } + TInet6Packet < TIpHeader > ip (aPacket, aInfo.iOffset); + if (ip.iHdr == NULL) + return KIp6Hook_PASS; + + // Get inner destination address in "normalized" IPv6 format + TIp6Addr inner_dst; + if (aInfo.iProtocol == (TInt)KProtocolInet6Ipip) + { + // Inner header IPv6 + + // Need to check the mapped length explicitly, because + // IPv4 min size is less than IPv6 header... + if (ip.iLength < (TInt)sizeof(TInet6HeaderIP)) + return KIp6Hook_PASS; + inner_dst = ip.iHdr->ip6.DstAddr(); + } + else if (aInfo.iProtocol == (TInt)KProtocolInetIpip) + { + // Inner header IPv4 (construct IPv4 mapped address) + inner_dst.u.iAddr32[0] = 0; + inner_dst.u.iAddr32[1] = 0; + inner_dst.u.iAddr32[2] = v4Prefix.b; + inner_dst.u.iAddr32[3] = ip.iHdr->ip4.DstAddrRef(); + } + else + return KIp6Hook_PASS; // Ignore all others. + + // Let those packets through that belong to any configured tunnel + TTunnelQueueIter iter (iTunnelParser.TunnelQueue()); + for (;;) + { + CTunnel *const tunnel = iter++; + if (tunnel == NULL) + { + // In case not handled by any of the configured tunnels, check if + // the address makes it possible to tunnel it automatically. + if (inner_dst.u.iAddr16[0] == K6to4Prefix.u.iAddr16[0]) + { + // Set interface index of the packet + // Should check that inner src is one of my own 6to4 addresses? + aInfo.iInterfaceIndex = iInterfaceIndex; + } + break; + } + if (inner_dst.IsEqual (tunnel->VirtualIfAddr()) && + TInetAddr::Cast(aInfo.iSrcAddr).Ip6Address().IsEqual(tunnel->EndpointAddr())) + { + // A tunnel willing to accept this incoming packet was found. + // Set also virtual interface index for the packet + aInfo.iInterfaceIndex = tunnel->InterfaceIndex(); + break; + } + } + + // Let the IP layer do the actual detunneling process + // (peeling off one IP header layer). [This way tunneled + // fragments get correctly processed, even if inner IP was + // IPv4 -- not currently the case here, inner is always IPv6. + // IPv6 fragments would work even if the outer IP layer + // was peeled off here]. + return KIp6Hook_PASS; + }; + +// ---------------------------------------------------------------------------- +// CProtocol6to4::CheckCompatibility +// Checks if the MEventService API is implemented. If not, 6to4 is not +// compatible with the TCP/IP stack version and log message is printed (and +// 6to4 shouldn't be used). +// ---------------------------------------------------------------------------- +// +void CProtocol6to4::CheckCompatibility () + { + MInterfaceManager *ifacer = NetworkService ()->Interfacer (); + TInt err; + + TRAP (err, iEventService = IMPORT_API_L (ifacer, MEventService)); +#ifdef _LOG + if (err != KErrNone) + LOG (Log::Printf (_L + ("MEventService not available. Some features may be missing\n"))); +#endif + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4::LoadFileL +// Loads and parses a tunnel configuration file. +// ---------------------------------------------------------------------------- +// +TInt CProtocol6to4::LoadFileL (const TDesC & aFile) + { + // Connect to the file server and open the tunnel configuration + // file (e.g., 6to4_tunnels.ini or what configured in 6to4.ini). + TAutoClose < RFs > fs; + User::LeaveIfError (fs.iObj.Connect ()); + fs.PushL (); + + TAutoClose < RFile > file; + User::LeaveIfError (file.iObj.Open (fs.iObj, aFile, EFileRead)); + file.PushL (); + + // Read file to a buffer + TInt size; + User::LeaveIfError (file.iObj.Size (size)); + HBufC8 *tmp_buf = HBufC8::NewL (size); + + CleanupStack::PushL (tmp_buf); + + TPtr8 tmp_ptr (tmp_buf->Des ()); + User::LeaveIfError (file.iObj.Read (tmp_ptr)); + HBufC16 *file_data = HBufC16::NewL (size); + file_data->Des ().Copy (tmp_buf->Des ()); + TPtr16 ptr (file_data->Des ()); + + CleanupStack::PushL (file_data); + + // Parse tunnels from the buffer. + TInt ret = iTunnelParser.ParseL (ptr); + + if (ret != KErrNone) + { + LOG (Log:: + Printf (_L + ("CProtocol6to4::LoadFileL [%S]: Error [%d] in tunnel conf file\r\n"), + &aFile, ret)); + } + + CleanupStack::Pop (); + CleanupStack::Pop (); + file.Pop (); + fs.Pop (); + + delete file_data; + delete tmp_buf; + + return KErrNone; + } + +// ---------------------------------------------------------------------------- +// CProtocol6to4:OpenL +// Outbound Open handler for the protocol. Checks first if the packet belongs +// to one of the tunnels. If so, creates and configures a 6to4 local flow +// object. Sets the +// destination IP address according to the IPv4 address of the outer (IPv4) +// header. Clears the source IP address of the packet and sets the IP version +// to 4. Marks the next header to be IPv6. Returns the newly created flow. +// ---------------------------------------------------------------------------- +// +MFlowHook *CProtocol6to4::OpenL (TPacketHead & aHead, CFlowContext * aFlow) + { + TIp6Addr & dst = aHead.ip6.DstAddr (); + TIp6Addr & src = aHead.ip6.SrcAddr (); + TIpAddress outerDst; + + // Check first if the flow belongs to one of the configured tunnels + TTunnelQueueIter iter (iTunnelParser.TunnelQueue()); + for (;;) + { + CTunnel *const tunnel = iter++; + if (tunnel == NULL) + { + // Packet didn't belong to configured tunnels, try automatic + // tunneling + if (dst.u.iAddr16[0] != K6to4Prefix.u.iAddr16[0]) + return NULL; // No configured tunnel or a 6to4 address + + // Apply the 6to4 conversion for the address + // IPv4 format + + outerDst.u.iAddr32[0] = 0; + outerDst.u.iAddr32[1] = 0; + outerDst.u.iAddr32[2] = v4Prefix.b; + outerDst.u.iAddr8[12] = dst.u.iAddr8[2]; + outerDst.u.iAddr8[13] = dst.u.iAddr8[3]; + outerDst.u.iAddr8[14] = dst.u.iAddr8[4]; + outerDst.u.iAddr8[15] = dst.u.iAddr8[5]; + + outerDst.iScope = 0; + break; + } + if (aHead.iInterfaceIndex == tunnel->InterfaceIndex()) + { + // Found a configured tunnel + // Use configured endpoint address as the outer destination ipv4 address + outerDst = tunnel->EndpointAddr(); + break; + } + } + // In current system, the (inner) source is always defined at this point + // (cancel flow if it is not!) + if (!aHead.iSourceSet) + User::Leave(KErrNotReady); + + // Must generate a value for inner hoplimit. For this, use the socket + // option to retrieve the currently defined value. The default is + // different for multicast and unicast, so need to test the inner address + // [Note: Really, the stack should be doing this for me, but ... -- msa] + const TBool is_multicast = + dst.IsMulticast() || + (dst.u.iAddr32[0] == 0 && + dst.u.iAddr32[1] == 0 && + dst.u.iAddr32[2] == v4Prefix.b && + (dst.u.iAddr8[12] & 0xF0) == 0xE0); + TPckgBuf opt; + (void)aFlow->GetOption(KSolInetIp, is_multicast ? KSoIp6MulticastHops : KSoIp6UnicastHops, opt); + aHead.ip6.SetHopLimit(opt()); + + // We are interested in this flow, let's create a new local flow + // instance + C6to4FlowInfo *info = new (ELeave) C6to4FlowInfo(aHead); + + + // Next header is going to be 4 or 41 + aHead.iProtocol = (TUint8)(dst.IsV4Mapped() ? KProtocolInetIpip : KProtocolInet6Ipip); + aHead.ip6.SetNextHeader (aHead.iProtocol); + aHead.ip6.SetHopLimit(0); + + dst = outerDst.Address(); + aHead.iDstId = outerDst.iScope; + + // Clean the source IP address from the packet. Flow sets it + // automatically before the ReadyL() is called. + aHead.iSourceSet = 0; + src = KInet6AddrNone; + aHead.iSrcId = 0; + + if (dst.IsV4Mapped()) + { + aHead.ip6.SetVersion (4); + // Update header size overhead + aFlow->iHdrSize += 20; + } + else + { + aHead.ip6.SetVersion (6); + // Update header size overhead + aFlow->iHdrSize += sizeof(TInet6HeaderIP); + } + aHead.iIcmpType = 0; + aHead.iIcmpCode = 0; + aHead.iSrcPort = 0; + aHead.iDstPort = 0; + +#if TPACKETHEAD_FRAGMENT + // Tunneled packets should be fragmented before tunneling + aHead.iFragment = 1; +#endif + return info; + } + +// ========================== OTHER EXPORTED FUNCTIONS ======================== + +// End of File + +