--- /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 <inet6log.h>
+#include <f32file.h>
+#include <icmp6_hdr.h>
+#include <ext_hdr.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+#include <es_prot_internal.h>
+#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<TInt> 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
+
+