|
1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Name : 6to4.cpp |
|
15 // Part of : 6to4 plugin / 6to4.prt |
|
16 // Implements 6to4 automatic and configured tunnels, see |
|
17 // RFC 3056 & RFC 2893 |
|
18 // Version : 0.2 |
|
19 // |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 // INCLUDE FILES |
|
25 #include <inet6log.h> |
|
26 #include <f32file.h> |
|
27 #include <icmp6_hdr.h> |
|
28 #include <ext_hdr.h> |
|
29 #ifdef SYMBIAN_ENABLE_SPLIT_HEADERS |
|
30 #include <es_prot_internal.h> |
|
31 #endif |
|
32 |
|
33 #include "6to4.h" |
|
34 #include "6to4_flow.h" |
|
35 #include "6to4_listener.h" |
|
36 #include "6to4_tunnel.h" |
|
37 |
|
38 // EXTERNAL DATA STRUCTURES |
|
39 // EXTERNAL FUNCTION PROTOTYPES |
|
40 // CONSTANTS |
|
41 // MACROS |
|
42 // LOCAL CONSTANTS AND MACROS |
|
43 |
|
44 |
|
45 // This is a route that is needed for system to pass automatic tunneled |
|
46 // packets (2002::/16) to the 6to4 module. |
|
47 const TIp6Addr K6to4Prefix = |
|
48 { {{0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} }; |
|
49 |
|
50 static const union {TUint8 a[4]; TUint32 b;} v4Prefix = { {0, 0, 0xff, 0xff} }; |
|
51 |
|
52 |
|
53 // MODULE DATA STRUCTURES |
|
54 // LOCAL FUNCTION PROTOTYPES |
|
55 // FORWARD DECLARATIONS |
|
56 |
|
57 // ============================= LOCAL FUNCTIONS ============================== |
|
58 |
|
59 // ============================ MEMBER FUNCTIONS ============================== |
|
60 |
|
61 // ---------------------------------------------------------------------------- |
|
62 // CProtocol6to4::CProtocol6to4 |
|
63 // C++ default constructor can NOT contain any code, that |
|
64 // might leave. |
|
65 // ---------------------------------------------------------------------------- |
|
66 // |
|
67 CProtocol6to4::CProtocol6to4 () |
|
68 { |
|
69 } |
|
70 |
|
71 // Destructor |
|
72 CProtocol6to4::~CProtocol6to4 () |
|
73 { |
|
74 delete iConfig; |
|
75 delete iEventListener; |
|
76 } |
|
77 |
|
78 // ---------------------------------------------------------------------------- |
|
79 // CProtocol6to4::InitL |
|
80 // Initializes the 6to4. |
|
81 // ---------------------------------------------------------------------------- |
|
82 // |
|
83 void CProtocol6to4::InitL (TDesC & aTag) |
|
84 { |
|
85 CProtocolBase::InitL (aTag); |
|
86 |
|
87 // There are two configuration files. The first one, 6to4.ini |
|
88 // just defines the file name where the tunnels are located. |
|
89 // Because the tunnel file is of variable length, it can't |
|
90 // be parsed in ordinary Symbian way, but it needs it's own parser. |
|
91 LoadConfigurationFile (); |
|
92 } |
|
93 |
|
94 // ---------------------------------------------------------------------------- |
|
95 // CProtocol6to4::LoadConfigurationFile |
|
96 // Reads first file K6to4IniData, e.g., 6to4.ini, and finds out the file |
|
97 // where the configured tunnels are defined. Then parses and creates the |
|
98 // configured tunnels. |
|
99 // ---------------------------------------------------------------------------- |
|
100 // |
|
101 TBool CProtocol6to4::LoadConfigurationFile () |
|
102 { |
|
103 if (iConfig) |
|
104 return EFalse; // Already loaded! |
|
105 |
|
106 // if iConfigErr != 0 (KErrNone), then an attempt for |
|
107 // loading configuration has been made and failed, |
|
108 // assume it never will succeed and avoid further |
|
109 // attemps on each FindVar... |
|
110 if (iConfigErr) |
|
111 return EFalse; |
|
112 |
|
113 LOG (Log::Printf (_L ("CProtocol6to4::LoadConfigurationFile(): %S\r\n"), &K6To4IniData)); |
|
114 TRAP(iConfigErr, iConfig = CESockIniData::NewL (K6To4IniData)); |
|
115 |
|
116 if (iConfigErr) |
|
117 return EFalse; |
|
118 |
|
119 if (iConfig) |
|
120 { |
|
121 TPtrC tunnelIniFile; |
|
122 // Read initialization file name, e.g., 6to4_tunnels.ini. |
|
123 if (iConfig->FindVar (K6To4IniSectionTunnels, K6To4IniTunnelFile, tunnelIniFile)) |
|
124 { |
|
125 // Parse the 6to4_tunnels.ini (or what was defined in 6to4.ini). |
|
126 // NOTE: iConfigErr use must be removed when other definitions |
|
127 // than configuded tunnels are possible in K6To4IniData file -tom |
|
128 TRAP(iConfigErr, LoadFileL (tunnelIniFile)); |
|
129 if (iConfigErr) |
|
130 return EFalse; |
|
131 } |
|
132 // Missing K6To4IniSectionTunnels is fine |
|
133 } |
|
134 return ETrue; |
|
135 } |
|
136 |
|
137 // ---------------------------------------------------------------------------- |
|
138 // CProtocol6to4::NetworkAttachedL |
|
139 // Binds the hooks (inbound & outbound) to the IP6. Creates virtual interfaces |
|
140 // for tunneled packets. The automatically tunneled packets are handled by |
|
141 // virtual interface 6to4, and the configured tunneled packets by virtual |
|
142 // interface named according to the tunnel name. The compatibility to the |
|
143 // TCP/IP stack version is also checked (if not compatible, a log message is |
|
144 // printed). Registers a listener for interface IP addresses. That is used for |
|
145 // filtering purposes. |
|
146 // ---------------------------------------------------------------------------- |
|
147 // |
|
148 void CProtocol6to4::NetworkAttachedL () |
|
149 { |
|
150 // Outbound hook |
|
151 NetworkService()->BindL (this, BindFlowHook ()); |
|
152 |
|
153 // Inbound hook, 41 == IPv6 inner |
|
154 NetworkService()->BindL (this, BindHookFor (KProtocolInet6Ipip)); |
|
155 // Inbound hook, 4, == IPv4 inner |
|
156 NetworkService()->BindL(this, BindHookFor (KProtocolInetIpip)); |
|
157 |
|
158 MInterfaceManager *const ifmgr = NetworkService ()->Interfacer(); |
|
159 |
|
160 ifmgr->AddRouteL (K6to4Prefix, 16, K6to4); |
|
161 // Create a new virtual interface "6to4" for the 6to4. This is used for |
|
162 // automatic tunneling. The interface index of this virtual interface |
|
163 // is saved to this object. |
|
164 const MInterface *const m = ifmgr->Interface (K6to4); |
|
165 iInterfaceIndex = m->Index (); |
|
166 |
|
167 // For each configured tunnel, the same thing is needed. The route is |
|
168 // established using configured ip address and prefix information. The |
|
169 // virtual interface gets the name according to the configured tunnel name. |
|
170 // The virtual interface index is stored to the CTunnel object. |
|
171 TTunnelQueueIter iter (iTunnelParser.TunnelQueue()); |
|
172 CTunnel *tunnel = NULL; |
|
173 while ((tunnel = iter++) != NULL) |
|
174 { |
|
175 ifmgr-> AddRouteL (tunnel->RouteAddr(), tunnel->RoutePrefixLength(), tunnel->Name()); |
|
176 ifmgr-> AddRouteL (tunnel->VirtualIfAddr(), 128, tunnel->Name(), KRouteAdd_MYPREFIX); |
|
177 const MInterface *const vif = ifmgr->Interface (tunnel->Name()); |
|
178 tunnel->SetInterfaceIndex(vif->Index ()); |
|
179 } |
|
180 |
|
181 // The event service was not available, so to make sure it's there, this |
|
182 // Check is made. Prints a log message if any problems. |
|
183 CheckCompatibility (); |
|
184 |
|
185 if (iEventService) |
|
186 { |
|
187 // A listener is needed for getting information on ip addresses |
|
188 // that are added/deleted to/from certain interfaces. This |
|
189 // information is used for filtering incoming packets from |
|
190 // malicious senders. |
|
191 delete iEventListener; |
|
192 iEventListener = NULL; |
|
193 iEventListener = new (ELeave) C6to4Listener (NetworkService(), *iEventService); |
|
194 } |
|
195 } |
|
196 |
|
197 // ---------------------------------------------------------------------------- |
|
198 // CProtocol6to4::NetworkDetached |
|
199 // Unbind the hooks. |
|
200 // ---------------------------------------------------------------------------- |
|
201 // |
|
202 void CProtocol6to4::NetworkDetached () |
|
203 { |
|
204 delete iEventListener; |
|
205 iEventListener = NULL; |
|
206 } |
|
207 |
|
208 // ---------------------------------------------------------------------------- |
|
209 // CProtocol6to4::Identify |
|
210 // Provide identification information to the caller. |
|
211 // ---------------------------------------------------------------------------- |
|
212 // |
|
213 void CProtocol6to4::Identify (TServerProtocolDesc & aEntry) |
|
214 { |
|
215 aEntry.iName = K6to4; |
|
216 aEntry.iAddrFamily = KAfInet6; |
|
217 aEntry.iSockType = KSockDatagram; |
|
218 aEntry.iProtocol = KProtocolInet6Ipip; |
|
219 aEntry.iVersion = TVersion (1, 0, 0); |
|
220 aEntry.iByteOrder = EBigEndian; |
|
221 // aEntry.iServiceInfo=KSIDatagram | KSIConnectionLess; |
|
222 aEntry.iServiceInfo = |
|
223 KSIConnectionLess | KSIMessageBased | KSIBroadcast | KSIPeekData | |
|
224 KSIGracefulClose; |
|
225 aEntry.iNamingServices = 0; |
|
226 aEntry.iSecurity = KSocketNoSecurity; |
|
227 aEntry.iMessageSize = 0xffff; |
|
228 aEntry.iServiceTypeInfo = EPreferMBufChains | ENeedMBufs; |
|
229 aEntry.iNumSockets = KUnlimitedSockets; |
|
230 } |
|
231 |
|
232 void CProtocol6to4::Identify (TServerProtocolDesc * aDesc) const |
|
233 { |
|
234 Identify (*aDesc); |
|
235 } |
|
236 |
|
237 // ---------------------------------------------------------------------------- |
|
238 // CProtocol6to4::ApplyL |
|
239 // This is the handler for incoming packets. Detunnel legal packets. |
|
240 // ---------------------------------------------------------------------------- |
|
241 // |
|
242 TInt CProtocol6to4::ApplyL (RMBufHookPacket & aPacket, RMBufRecvInfo & aInfo) |
|
243 { |
|
244 if (aInfo.iIcmp) |
|
245 { |
|
246 // This is a returned packet inside an ICMP. Could check whether the |
|
247 // IP header is the tunneling generated by this packet and do something |
|
248 // about it, but for now, just ignore and let someone else deal with it. |
|
249 return KIp6Hook_PASS; |
|
250 } |
|
251 TInet6Packet < TIpHeader > ip (aPacket, aInfo.iOffset); |
|
252 if (ip.iHdr == NULL) |
|
253 return KIp6Hook_PASS; |
|
254 |
|
255 // Get inner destination address in "normalized" IPv6 format |
|
256 TIp6Addr inner_dst; |
|
257 if (aInfo.iProtocol == (TInt)KProtocolInet6Ipip) |
|
258 { |
|
259 // Inner header IPv6 |
|
260 |
|
261 // Need to check the mapped length explicitly, because |
|
262 // IPv4 min size is less than IPv6 header... |
|
263 if (ip.iLength < (TInt)sizeof(TInet6HeaderIP)) |
|
264 return KIp6Hook_PASS; |
|
265 inner_dst = ip.iHdr->ip6.DstAddr(); |
|
266 } |
|
267 else if (aInfo.iProtocol == (TInt)KProtocolInetIpip) |
|
268 { |
|
269 // Inner header IPv4 (construct IPv4 mapped address) |
|
270 inner_dst.u.iAddr32[0] = 0; |
|
271 inner_dst.u.iAddr32[1] = 0; |
|
272 inner_dst.u.iAddr32[2] = v4Prefix.b; |
|
273 inner_dst.u.iAddr32[3] = ip.iHdr->ip4.DstAddrRef(); |
|
274 } |
|
275 else |
|
276 return KIp6Hook_PASS; // Ignore all others. |
|
277 |
|
278 // Let those packets through that belong to any configured tunnel |
|
279 TTunnelQueueIter iter (iTunnelParser.TunnelQueue()); |
|
280 for (;;) |
|
281 { |
|
282 CTunnel *const tunnel = iter++; |
|
283 if (tunnel == NULL) |
|
284 { |
|
285 // In case not handled by any of the configured tunnels, check if |
|
286 // the address makes it possible to tunnel it automatically. |
|
287 if (inner_dst.u.iAddr16[0] == K6to4Prefix.u.iAddr16[0]) |
|
288 { |
|
289 // Set interface index of the packet |
|
290 // Should check that inner src is one of my own 6to4 addresses? |
|
291 aInfo.iInterfaceIndex = iInterfaceIndex; |
|
292 } |
|
293 break; |
|
294 } |
|
295 if (inner_dst.IsEqual (tunnel->VirtualIfAddr()) && |
|
296 TInetAddr::Cast(aInfo.iSrcAddr).Ip6Address().IsEqual(tunnel->EndpointAddr())) |
|
297 { |
|
298 // A tunnel willing to accept this incoming packet was found. |
|
299 // Set also virtual interface index for the packet |
|
300 aInfo.iInterfaceIndex = tunnel->InterfaceIndex(); |
|
301 break; |
|
302 } |
|
303 } |
|
304 |
|
305 // Let the IP layer do the actual detunneling process |
|
306 // (peeling off one IP header layer). [This way tunneled |
|
307 // fragments get correctly processed, even if inner IP was |
|
308 // IPv4 -- not currently the case here, inner is always IPv6. |
|
309 // IPv6 fragments would work even if the outer IP layer |
|
310 // was peeled off here]. |
|
311 return KIp6Hook_PASS; |
|
312 }; |
|
313 |
|
314 // ---------------------------------------------------------------------------- |
|
315 // CProtocol6to4::CheckCompatibility |
|
316 // Checks if the MEventService API is implemented. If not, 6to4 is not |
|
317 // compatible with the TCP/IP stack version and log message is printed (and |
|
318 // 6to4 shouldn't be used). |
|
319 // ---------------------------------------------------------------------------- |
|
320 // |
|
321 void CProtocol6to4::CheckCompatibility () |
|
322 { |
|
323 MInterfaceManager *ifacer = NetworkService ()->Interfacer (); |
|
324 TInt err; |
|
325 |
|
326 TRAP (err, iEventService = IMPORT_API_L (ifacer, MEventService)); |
|
327 #ifdef _LOG |
|
328 if (err != KErrNone) |
|
329 LOG (Log::Printf (_L |
|
330 ("MEventService not available. Some features may be missing\n"))); |
|
331 #endif |
|
332 } |
|
333 |
|
334 // ---------------------------------------------------------------------------- |
|
335 // CProtocol6to4::LoadFileL |
|
336 // Loads and parses a tunnel configuration file. |
|
337 // ---------------------------------------------------------------------------- |
|
338 // |
|
339 TInt CProtocol6to4::LoadFileL (const TDesC & aFile) |
|
340 { |
|
341 // Connect to the file server and open the tunnel configuration |
|
342 // file (e.g., 6to4_tunnels.ini or what configured in 6to4.ini). |
|
343 TAutoClose < RFs > fs; |
|
344 User::LeaveIfError (fs.iObj.Connect ()); |
|
345 fs.PushL (); |
|
346 |
|
347 TAutoClose < RFile > file; |
|
348 User::LeaveIfError (file.iObj.Open (fs.iObj, aFile, EFileRead)); |
|
349 file.PushL (); |
|
350 |
|
351 // Read file to a buffer |
|
352 TInt size; |
|
353 User::LeaveIfError (file.iObj.Size (size)); |
|
354 HBufC8 *tmp_buf = HBufC8::NewL (size); |
|
355 |
|
356 CleanupStack::PushL (tmp_buf); |
|
357 |
|
358 TPtr8 tmp_ptr (tmp_buf->Des ()); |
|
359 User::LeaveIfError (file.iObj.Read (tmp_ptr)); |
|
360 HBufC16 *file_data = HBufC16::NewL (size); |
|
361 file_data->Des ().Copy (tmp_buf->Des ()); |
|
362 TPtr16 ptr (file_data->Des ()); |
|
363 |
|
364 CleanupStack::PushL (file_data); |
|
365 |
|
366 // Parse tunnels from the buffer. |
|
367 TInt ret = iTunnelParser.ParseL (ptr); |
|
368 |
|
369 if (ret != KErrNone) |
|
370 { |
|
371 LOG (Log:: |
|
372 Printf (_L |
|
373 ("CProtocol6to4::LoadFileL [%S]: Error [%d] in tunnel conf file\r\n"), |
|
374 &aFile, ret)); |
|
375 } |
|
376 |
|
377 CleanupStack::Pop (); |
|
378 CleanupStack::Pop (); |
|
379 file.Pop (); |
|
380 fs.Pop (); |
|
381 |
|
382 delete file_data; |
|
383 delete tmp_buf; |
|
384 |
|
385 return KErrNone; |
|
386 } |
|
387 |
|
388 // ---------------------------------------------------------------------------- |
|
389 // CProtocol6to4:OpenL |
|
390 // Outbound Open handler for the protocol. Checks first if the packet belongs |
|
391 // to one of the tunnels. If so, creates and configures a 6to4 local flow |
|
392 // object. Sets the |
|
393 // destination IP address according to the IPv4 address of the outer (IPv4) |
|
394 // header. Clears the source IP address of the packet and sets the IP version |
|
395 // to 4. Marks the next header to be IPv6. Returns the newly created flow. |
|
396 // ---------------------------------------------------------------------------- |
|
397 // |
|
398 MFlowHook *CProtocol6to4::OpenL (TPacketHead & aHead, CFlowContext * aFlow) |
|
399 { |
|
400 TIp6Addr & dst = aHead.ip6.DstAddr (); |
|
401 TIp6Addr & src = aHead.ip6.SrcAddr (); |
|
402 TIpAddress outerDst; |
|
403 |
|
404 // Check first if the flow belongs to one of the configured tunnels |
|
405 TTunnelQueueIter iter (iTunnelParser.TunnelQueue()); |
|
406 for (;;) |
|
407 { |
|
408 CTunnel *const tunnel = iter++; |
|
409 if (tunnel == NULL) |
|
410 { |
|
411 // Packet didn't belong to configured tunnels, try automatic |
|
412 // tunneling |
|
413 if (dst.u.iAddr16[0] != K6to4Prefix.u.iAddr16[0]) |
|
414 return NULL; // No configured tunnel or a 6to4 address |
|
415 |
|
416 // Apply the 6to4 conversion for the address |
|
417 // IPv4 format |
|
418 |
|
419 outerDst.u.iAddr32[0] = 0; |
|
420 outerDst.u.iAddr32[1] = 0; |
|
421 outerDst.u.iAddr32[2] = v4Prefix.b; |
|
422 outerDst.u.iAddr8[12] = dst.u.iAddr8[2]; |
|
423 outerDst.u.iAddr8[13] = dst.u.iAddr8[3]; |
|
424 outerDst.u.iAddr8[14] = dst.u.iAddr8[4]; |
|
425 outerDst.u.iAddr8[15] = dst.u.iAddr8[5]; |
|
426 |
|
427 outerDst.iScope = 0; |
|
428 break; |
|
429 } |
|
430 if (aHead.iInterfaceIndex == tunnel->InterfaceIndex()) |
|
431 { |
|
432 // Found a configured tunnel |
|
433 // Use configured endpoint address as the outer destination ipv4 address |
|
434 outerDst = tunnel->EndpointAddr(); |
|
435 break; |
|
436 } |
|
437 } |
|
438 // In current system, the (inner) source is always defined at this point |
|
439 // (cancel flow if it is not!) |
|
440 if (!aHead.iSourceSet) |
|
441 User::Leave(KErrNotReady); |
|
442 |
|
443 // Must generate a value for inner hoplimit. For this, use the socket |
|
444 // option to retrieve the currently defined value. The default is |
|
445 // different for multicast and unicast, so need to test the inner address |
|
446 // [Note: Really, the stack should be doing this for me, but ... -- msa] |
|
447 const TBool is_multicast = |
|
448 dst.IsMulticast() || |
|
449 (dst.u.iAddr32[0] == 0 && |
|
450 dst.u.iAddr32[1] == 0 && |
|
451 dst.u.iAddr32[2] == v4Prefix.b && |
|
452 (dst.u.iAddr8[12] & 0xF0) == 0xE0); |
|
453 TPckgBuf<TInt> opt; |
|
454 (void)aFlow->GetOption(KSolInetIp, is_multicast ? KSoIp6MulticastHops : KSoIp6UnicastHops, opt); |
|
455 aHead.ip6.SetHopLimit(opt()); |
|
456 |
|
457 // We are interested in this flow, let's create a new local flow |
|
458 // instance |
|
459 C6to4FlowInfo *info = new (ELeave) C6to4FlowInfo(aHead); |
|
460 |
|
461 |
|
462 // Next header is going to be 4 or 41 |
|
463 aHead.iProtocol = (TUint8)(dst.IsV4Mapped() ? KProtocolInetIpip : KProtocolInet6Ipip); |
|
464 aHead.ip6.SetNextHeader (aHead.iProtocol); |
|
465 aHead.ip6.SetHopLimit(0); |
|
466 |
|
467 dst = outerDst.Address(); |
|
468 aHead.iDstId = outerDst.iScope; |
|
469 |
|
470 // Clean the source IP address from the packet. Flow sets it |
|
471 // automatically before the ReadyL() is called. |
|
472 aHead.iSourceSet = 0; |
|
473 src = KInet6AddrNone; |
|
474 aHead.iSrcId = 0; |
|
475 |
|
476 if (dst.IsV4Mapped()) |
|
477 { |
|
478 aHead.ip6.SetVersion (4); |
|
479 // Update header size overhead |
|
480 aFlow->iHdrSize += 20; |
|
481 } |
|
482 else |
|
483 { |
|
484 aHead.ip6.SetVersion (6); |
|
485 // Update header size overhead |
|
486 aFlow->iHdrSize += sizeof(TInet6HeaderIP); |
|
487 } |
|
488 aHead.iIcmpType = 0; |
|
489 aHead.iIcmpCode = 0; |
|
490 aHead.iSrcPort = 0; |
|
491 aHead.iDstPort = 0; |
|
492 |
|
493 #if TPACKETHEAD_FRAGMENT |
|
494 // Tunneled packets should be fragmented before tunneling |
|
495 aHead.iFragment = 1; |
|
496 #endif |
|
497 return info; |
|
498 } |
|
499 |
|
500 // ========================== OTHER EXPORTED FUNCTIONS ======================== |
|
501 |
|
502 // End of File |
|
503 |
|
504 |