├── .swiftlint.yml ├── Cartfile ├── Cartfile.resolved ├── License.md ├── Readme.md ├── TunnelPacketKit.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── TunnelPacketKit ├── BinaryDataScanner.swift ├── BlockManager.swift ├── Checksum.swift ├── DataManager.swift ├── IPAddress.swift ├── IPPacket.swift ├── Info.plist ├── LinkedList.swift ├── NetworkInterface.swift ├── Options.swift ├── Packet.swift ├── ProtocolPacket.swift ├── Queue.swift ├── SNWTCPTunnel.swift ├── SNWUDPTunnel.swift ├── SequenceManager.swift ├── TCPDataBlock.swift ├── TCPPacket.swift ├── TCPTunnel.swift ├── TCPUtils.swift ├── Tunnel.swift ├── TunnelManager.swift ├── TunnelPacketKit.h └── enums.swift └── TunnelPacketKitTests ├── IPPacketSpec.swift ├── Info.plist ├── Packet_1.bin ├── TCPPacketSpec.swift ├── Utils └── ChecksumSpec.swift └── dump /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | excluded: 2 | - Carthage -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "CocoaLumberjack/CocoaLumberjack" 2 | github "Quick/Quick" 3 | github "Quick/Nimble" -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "CocoaLumberjack/CocoaLumberjack" "2.2.0" 2 | github "Quick/Nimble" "v3.1.0" 3 | github "Quick/Quick" "v0.9.0" 4 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 Zhuhao Wang 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # This is an experimental implemention of a TCP/IP stack in Swift.# 2 | 3 | **Try [tun2socks](https://github.com/zhuhaow/tun2socks) if you need a functional IP stack with tun interface support.** 4 | 5 | The whole project is just some toy codes which compile but won't work. There are many known errors but they won't be fixed. 6 | 7 | The initial goal is to create an IP stack accompanying NetworkExtension. However, I found it's just too difficult to create and maintain a correctly implemented IP stack, so probably it should be better to use a modified lwip or pico as the tun2socks library. 8 | -------------------------------------------------------------------------------- /TunnelPacketKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 361D15061C4A7184002446F3 /* TunnelPacketKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 361D15051C4A7184002446F3 /* TunnelPacketKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 361D150D1C4A7184002446F3 /* TunnelPacketKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 361D15021C4A7184002446F3 /* TunnelPacketKit.framework */; }; 12 | 361D151D1C4A71F8002446F3 /* IPPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D151C1C4A71F8002446F3 /* IPPacket.swift */; }; 13 | 361D151F1C4A77C8002446F3 /* IPAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D151E1C4A77C8002446F3 /* IPAddress.swift */; }; 14 | 361D15251C4A94B6002446F3 /* CocoaLumberjack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 361D15231C4A94B6002446F3 /* CocoaLumberjack.framework */; }; 15 | 361D15261C4A94B6002446F3 /* CocoaLumberjackSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 361D15241C4A94B6002446F3 /* CocoaLumberjackSwift.framework */; }; 16 | 361D15291C4B3214002446F3 /* BinaryDataScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D15281C4B3214002446F3 /* BinaryDataScanner.swift */; }; 17 | 361D152B1C4B39AB002446F3 /* Packet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D152A1C4B39AB002446F3 /* Packet.swift */; }; 18 | 361D152D1C4B39F8002446F3 /* TCPPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D152C1C4B39F8002446F3 /* TCPPacket.swift */; }; 19 | 361D15301C4B4585002446F3 /* NetworkInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D152F1C4B4585002446F3 /* NetworkInterface.swift */; }; 20 | 361D15321C4B4878002446F3 /* Tunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D15311C4B4878002446F3 /* Tunnel.swift */; }; 21 | 361D15351C4B4886002446F3 /* TCPTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D15341C4B4886002446F3 /* TCPTunnel.swift */; }; 22 | 361D15371C4B4983002446F3 /* TunnelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D15361C4B4983002446F3 /* TunnelManager.swift */; }; 23 | 361D15391C4B4BBC002446F3 /* enums.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D15381C4B4BBC002446F3 /* enums.swift */; }; 24 | 361D153B1C4B5A0D002446F3 /* ProtocolPacket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 361D153A1C4B5A0D002446F3 /* ProtocolPacket.swift */; }; 25 | 364181631C524F9D0041D94A /* LinkedList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 364181621C524F9D0041D94A /* LinkedList.swift */; }; 26 | 364181661C52536A0041D94A /* SequenceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 364181651C52536A0041D94A /* SequenceManager.swift */; }; 27 | 364A8F6F1C4E652C001E0D1A /* Checksum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 364A8F6E1C4E652C001E0D1A /* Checksum.swift */; }; 28 | 36530F2D1C4FA421003DFFD5 /* Packet_1.bin in Resources */ = {isa = PBXBuildFile; fileRef = 36530F2C1C4FA421003DFFD5 /* Packet_1.bin */; }; 29 | 36530F301C4FA48C003DFFD5 /* IPPacketSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36530F2F1C4FA48C003DFFD5 /* IPPacketSpec.swift */; }; 30 | 36530F341C4FABAA003DFFD5 /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 36530F221C4F8407003DFFD5 /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 31 | 36530F351C4FABAE003DFFD5 /* Quick.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 36530F231C4F8407003DFFD5 /* Quick.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 32 | 36530F361C4FABB9003DFFD5 /* CocoaLumberjack.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 361D15231C4A94B6002446F3 /* CocoaLumberjack.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 33 | 36530F371C4FABBB003DFFD5 /* CocoaLumberjackSwift.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 361D15241C4A94B6002446F3 /* CocoaLumberjackSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 34 | 36530F391C4FC8E9003DFFD5 /* ChecksumSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36530F381C4FC8E9003DFFD5 /* ChecksumSpec.swift */; }; 35 | 367C27881C65D87400EAC5F4 /* TCPUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 367C27871C65D87400EAC5F4 /* TCPUtils.swift */; }; 36 | 36A7BD5D1C7DB487002793CC /* SNWTCPTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36A7BD5C1C7DB487002793CC /* SNWTCPTunnel.swift */; }; 37 | 36A7BD601C7F222B002793CC /* Queue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36A7BD5F1C7F222B002793CC /* Queue.swift */; }; 38 | 36A7BD621C7F360E002793CC /* SNWUDPTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36A7BD611C7F360E002793CC /* SNWUDPTunnel.swift */; }; 39 | 36D0EE4D1C57AC2C00DD18AE /* TCPDataBlock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36D0EE4C1C57AC2C00DD18AE /* TCPDataBlock.swift */; }; 40 | 36D0EE4F1C58F31900DD18AE /* BlockManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36D0EE4E1C58F31900DD18AE /* BlockManager.swift */; }; 41 | 36D0EE511C58FE2800DD18AE /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36D0EE501C58FE2800DD18AE /* DataManager.swift */; }; 42 | 36F6CE411C4B9EC000DA7D4C /* Options.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36F6CE401C4B9EC000DA7D4C /* Options.swift */; }; 43 | 36FF26C81C5A0C13008D8056 /* TCPPacketSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36FF26C71C5A0C13008D8056 /* TCPPacketSpec.swift */; }; 44 | /* End PBXBuildFile section */ 45 | 46 | /* Begin PBXContainerItemProxy section */ 47 | 361D150E1C4A7184002446F3 /* PBXContainerItemProxy */ = { 48 | isa = PBXContainerItemProxy; 49 | containerPortal = 361D14F91C4A7184002446F3 /* Project object */; 50 | proxyType = 1; 51 | remoteGlobalIDString = 361D15011C4A7184002446F3; 52 | remoteInfo = TunnelPacketKit; 53 | }; 54 | /* End PBXContainerItemProxy section */ 55 | 56 | /* Begin PBXCopyFilesBuildPhase section */ 57 | 36530F331C4FAB9E003DFFD5 /* CopyFiles */ = { 58 | isa = PBXCopyFilesBuildPhase; 59 | buildActionMask = 2147483647; 60 | dstPath = ""; 61 | dstSubfolderSpec = 10; 62 | files = ( 63 | 36530F341C4FABAA003DFFD5 /* Nimble.framework in CopyFiles */, 64 | 36530F351C4FABAE003DFFD5 /* Quick.framework in CopyFiles */, 65 | 36530F361C4FABB9003DFFD5 /* CocoaLumberjack.framework in CopyFiles */, 66 | 36530F371C4FABBB003DFFD5 /* CocoaLumberjackSwift.framework in CopyFiles */, 67 | ); 68 | runOnlyForDeploymentPostprocessing = 0; 69 | }; 70 | /* End PBXCopyFilesBuildPhase section */ 71 | 72 | /* Begin PBXFileReference section */ 73 | 361D15021C4A7184002446F3 /* TunnelPacketKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TunnelPacketKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 74 | 361D15051C4A7184002446F3 /* TunnelPacketKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TunnelPacketKit.h; sourceTree = ""; }; 75 | 361D15071C4A7184002446F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | 361D150C1C4A7184002446F3 /* TunnelPacketKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TunnelPacketKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 77 | 361D15131C4A7184002446F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 78 | 361D151C1C4A71F8002446F3 /* IPPacket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IPPacket.swift; sourceTree = ""; }; 79 | 361D151E1C4A77C8002446F3 /* IPAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IPAddress.swift; sourceTree = ""; }; 80 | 361D15201C4A898F002446F3 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = ""; }; 81 | 361D15231C4A94B6002446F3 /* CocoaLumberjack.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaLumberjack.framework; path = Carthage/Build/Mac/CocoaLumberjack.framework; sourceTree = ""; }; 82 | 361D15241C4A94B6002446F3 /* CocoaLumberjackSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CocoaLumberjackSwift.framework; path = Carthage/Build/Mac/CocoaLumberjackSwift.framework; sourceTree = ""; }; 83 | 361D15281C4B3214002446F3 /* BinaryDataScanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryDataScanner.swift; sourceTree = ""; }; 84 | 361D152A1C4B39AB002446F3 /* Packet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Packet.swift; sourceTree = ""; }; 85 | 361D152C1C4B39F8002446F3 /* TCPPacket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TCPPacket.swift; sourceTree = ""; }; 86 | 361D152F1C4B4585002446F3 /* NetworkInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkInterface.swift; sourceTree = ""; }; 87 | 361D15311C4B4878002446F3 /* Tunnel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Tunnel.swift; sourceTree = ""; }; 88 | 361D15341C4B4886002446F3 /* TCPTunnel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TCPTunnel.swift; sourceTree = ""; }; 89 | 361D15361C4B4983002446F3 /* TunnelManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TunnelManager.swift; sourceTree = ""; }; 90 | 361D15381C4B4BBC002446F3 /* enums.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = enums.swift; sourceTree = ""; }; 91 | 361D153A1C4B5A0D002446F3 /* ProtocolPacket.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProtocolPacket.swift; sourceTree = ""; }; 92 | 36315AF61C59E060001E2A5B /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = .swiftlint.yml; sourceTree = ""; }; 93 | 364181621C524F9D0041D94A /* LinkedList.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkedList.swift; sourceTree = ""; }; 94 | 364181651C52536A0041D94A /* SequenceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceManager.swift; sourceTree = ""; }; 95 | 364A8F6E1C4E652C001E0D1A /* Checksum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Checksum.swift; sourceTree = ""; }; 96 | 36530F221C4F8407003DFFD5 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/Mac/Nimble.framework; sourceTree = ""; }; 97 | 36530F231C4F8407003DFFD5 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/Mac/Quick.framework; sourceTree = ""; }; 98 | 36530F2C1C4FA421003DFFD5 /* Packet_1.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = Packet_1.bin; sourceTree = ""; }; 99 | 36530F2F1C4FA48C003DFFD5 /* IPPacketSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IPPacketSpec.swift; sourceTree = ""; }; 100 | 36530F381C4FC8E9003DFFD5 /* ChecksumSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ChecksumSpec.swift; path = Utils/ChecksumSpec.swift; sourceTree = ""; }; 101 | 367C27871C65D87400EAC5F4 /* TCPUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TCPUtils.swift; sourceTree = ""; }; 102 | 36A7BD5C1C7DB487002793CC /* SNWTCPTunnel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SNWTCPTunnel.swift; sourceTree = ""; }; 103 | 36A7BD5F1C7F222B002793CC /* Queue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queue.swift; sourceTree = ""; }; 104 | 36A7BD611C7F360E002793CC /* SNWUDPTunnel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SNWUDPTunnel.swift; sourceTree = ""; }; 105 | 36D0EE4C1C57AC2C00DD18AE /* TCPDataBlock.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TCPDataBlock.swift; sourceTree = ""; }; 106 | 36D0EE4E1C58F31900DD18AE /* BlockManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockManager.swift; sourceTree = ""; }; 107 | 36D0EE501C58FE2800DD18AE /* DataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = ""; }; 108 | 36F6CE401C4B9EC000DA7D4C /* Options.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Options.swift; sourceTree = ""; }; 109 | 36FF26C71C5A0C13008D8056 /* TCPPacketSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TCPPacketSpec.swift; sourceTree = ""; }; 110 | /* End PBXFileReference section */ 111 | 112 | /* Begin PBXFrameworksBuildPhase section */ 113 | 361D14FE1C4A7184002446F3 /* Frameworks */ = { 114 | isa = PBXFrameworksBuildPhase; 115 | buildActionMask = 2147483647; 116 | files = ( 117 | 361D15251C4A94B6002446F3 /* CocoaLumberjack.framework in Frameworks */, 118 | 361D15261C4A94B6002446F3 /* CocoaLumberjackSwift.framework in Frameworks */, 119 | ); 120 | runOnlyForDeploymentPostprocessing = 0; 121 | }; 122 | 361D15091C4A7184002446F3 /* Frameworks */ = { 123 | isa = PBXFrameworksBuildPhase; 124 | buildActionMask = 2147483647; 125 | files = ( 126 | 361D150D1C4A7184002446F3 /* TunnelPacketKit.framework in Frameworks */, 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | /* End PBXFrameworksBuildPhase section */ 131 | 132 | /* Begin PBXGroup section */ 133 | 361D14F81C4A7184002446F3 = { 134 | isa = PBXGroup; 135 | children = ( 136 | 36315AF61C59E060001E2A5B /* .swiftlint.yml */, 137 | 36530F221C4F8407003DFFD5 /* Nimble.framework */, 138 | 36530F231C4F8407003DFFD5 /* Quick.framework */, 139 | 361D15231C4A94B6002446F3 /* CocoaLumberjack.framework */, 140 | 361D15241C4A94B6002446F3 /* CocoaLumberjackSwift.framework */, 141 | 361D15041C4A7184002446F3 /* TunnelPacketKit */, 142 | 361D15101C4A7184002446F3 /* TunnelPacketKitTests */, 143 | 361D15031C4A7184002446F3 /* Products */, 144 | 361D15201C4A898F002446F3 /* Cartfile */, 145 | ); 146 | sourceTree = ""; 147 | }; 148 | 361D15031C4A7184002446F3 /* Products */ = { 149 | isa = PBXGroup; 150 | children = ( 151 | 361D15021C4A7184002446F3 /* TunnelPacketKit.framework */, 152 | 361D150C1C4A7184002446F3 /* TunnelPacketKitTests.xctest */, 153 | ); 154 | name = Products; 155 | sourceTree = ""; 156 | }; 157 | 361D15041C4A7184002446F3 /* TunnelPacketKit */ = { 158 | isa = PBXGroup; 159 | children = ( 160 | 361D15271C4B3184002446F3 /* Utils */, 161 | 361D15051C4A7184002446F3 /* TunnelPacketKit.h */, 162 | 361D15071C4A7184002446F3 /* Info.plist */, 163 | 361D152E1C4B433D002446F3 /* Packet */, 164 | 361D151E1C4A77C8002446F3 /* IPAddress.swift */, 165 | 361D152F1C4B4585002446F3 /* NetworkInterface.swift */, 166 | 361D15331C4B487D002446F3 /* Tunnel */, 167 | 36A7BD5E1C7DB48D002793CC /* SNWTunnel */, 168 | ); 169 | path = TunnelPacketKit; 170 | sourceTree = ""; 171 | }; 172 | 361D15101C4A7184002446F3 /* TunnelPacketKitTests */ = { 173 | isa = PBXGroup; 174 | children = ( 175 | 36530F3B1C50E6CE003DFFD5 /* Resources */, 176 | 36530F3A1C4FC8EF003DFFD5 /* Utils */, 177 | 36530F2E1C4FA431003DFFD5 /* Packet */, 178 | 361D15131C4A7184002446F3 /* Info.plist */, 179 | ); 180 | path = TunnelPacketKitTests; 181 | sourceTree = ""; 182 | }; 183 | 361D15271C4B3184002446F3 /* Utils */ = { 184 | isa = PBXGroup; 185 | children = ( 186 | 361D15381C4B4BBC002446F3 /* enums.swift */, 187 | 361D15281C4B3214002446F3 /* BinaryDataScanner.swift */, 188 | 36F6CE401C4B9EC000DA7D4C /* Options.swift */, 189 | 364A8F6E1C4E652C001E0D1A /* Checksum.swift */, 190 | 364181621C524F9D0041D94A /* LinkedList.swift */, 191 | 367C27871C65D87400EAC5F4 /* TCPUtils.swift */, 192 | 36A7BD5F1C7F222B002793CC /* Queue.swift */, 193 | ); 194 | name = Utils; 195 | sourceTree = ""; 196 | }; 197 | 361D152E1C4B433D002446F3 /* Packet */ = { 198 | isa = PBXGroup; 199 | children = ( 200 | 361D151C1C4A71F8002446F3 /* IPPacket.swift */, 201 | 361D152A1C4B39AB002446F3 /* Packet.swift */, 202 | 361D152C1C4B39F8002446F3 /* TCPPacket.swift */, 203 | 361D153A1C4B5A0D002446F3 /* ProtocolPacket.swift */, 204 | ); 205 | name = Packet; 206 | sourceTree = ""; 207 | }; 208 | 361D15331C4B487D002446F3 /* Tunnel */ = { 209 | isa = PBXGroup; 210 | children = ( 211 | 361D15361C4B4983002446F3 /* TunnelManager.swift */, 212 | 361D15311C4B4878002446F3 /* Tunnel.swift */, 213 | 364181641C52532D0041D94A /* TCPTunnel */, 214 | ); 215 | name = Tunnel; 216 | sourceTree = ""; 217 | }; 218 | 364181641C52532D0041D94A /* TCPTunnel */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | 361D15341C4B4886002446F3 /* TCPTunnel.swift */, 222 | 36D0EE501C58FE2800DD18AE /* DataManager.swift */, 223 | 364181651C52536A0041D94A /* SequenceManager.swift */, 224 | 36D0EE4C1C57AC2C00DD18AE /* TCPDataBlock.swift */, 225 | 36D0EE4E1C58F31900DD18AE /* BlockManager.swift */, 226 | ); 227 | name = TCPTunnel; 228 | sourceTree = ""; 229 | }; 230 | 36530F2E1C4FA431003DFFD5 /* Packet */ = { 231 | isa = PBXGroup; 232 | children = ( 233 | 36530F2F1C4FA48C003DFFD5 /* IPPacketSpec.swift */, 234 | 36FF26C71C5A0C13008D8056 /* TCPPacketSpec.swift */, 235 | ); 236 | name = Packet; 237 | sourceTree = ""; 238 | }; 239 | 36530F3A1C4FC8EF003DFFD5 /* Utils */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | 36530F381C4FC8E9003DFFD5 /* ChecksumSpec.swift */, 243 | ); 244 | name = Utils; 245 | sourceTree = ""; 246 | }; 247 | 36530F3B1C50E6CE003DFFD5 /* Resources */ = { 248 | isa = PBXGroup; 249 | children = ( 250 | 36530F2C1C4FA421003DFFD5 /* Packet_1.bin */, 251 | ); 252 | name = Resources; 253 | sourceTree = ""; 254 | }; 255 | 36A7BD5E1C7DB48D002793CC /* SNWTunnel */ = { 256 | isa = PBXGroup; 257 | children = ( 258 | 36A7BD5C1C7DB487002793CC /* SNWTCPTunnel.swift */, 259 | 36A7BD611C7F360E002793CC /* SNWUDPTunnel.swift */, 260 | ); 261 | name = SNWTunnel; 262 | sourceTree = ""; 263 | }; 264 | /* End PBXGroup section */ 265 | 266 | /* Begin PBXHeadersBuildPhase section */ 267 | 361D14FF1C4A7184002446F3 /* Headers */ = { 268 | isa = PBXHeadersBuildPhase; 269 | buildActionMask = 2147483647; 270 | files = ( 271 | 361D15061C4A7184002446F3 /* TunnelPacketKit.h in Headers */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | /* End PBXHeadersBuildPhase section */ 276 | 277 | /* Begin PBXNativeTarget section */ 278 | 361D15011C4A7184002446F3 /* TunnelPacketKit */ = { 279 | isa = PBXNativeTarget; 280 | buildConfigurationList = 361D15161C4A7184002446F3 /* Build configuration list for PBXNativeTarget "TunnelPacketKit" */; 281 | buildPhases = ( 282 | 361D14FD1C4A7184002446F3 /* Sources */, 283 | 361D14FE1C4A7184002446F3 /* Frameworks */, 284 | 361D14FF1C4A7184002446F3 /* Headers */, 285 | 361D15001C4A7184002446F3 /* Resources */, 286 | ); 287 | buildRules = ( 288 | ); 289 | dependencies = ( 290 | ); 291 | name = TunnelPacketKit; 292 | productName = TunnelPacketKit; 293 | productReference = 361D15021C4A7184002446F3 /* TunnelPacketKit.framework */; 294 | productType = "com.apple.product-type.framework"; 295 | }; 296 | 361D150B1C4A7184002446F3 /* TunnelPacketKitTests */ = { 297 | isa = PBXNativeTarget; 298 | buildConfigurationList = 361D15191C4A7184002446F3 /* Build configuration list for PBXNativeTarget "TunnelPacketKitTests" */; 299 | buildPhases = ( 300 | 361D15081C4A7184002446F3 /* Sources */, 301 | 361D15091C4A7184002446F3 /* Frameworks */, 302 | 361D150A1C4A7184002446F3 /* Resources */, 303 | 36530F331C4FAB9E003DFFD5 /* CopyFiles */, 304 | ); 305 | buildRules = ( 306 | ); 307 | dependencies = ( 308 | 361D150F1C4A7184002446F3 /* PBXTargetDependency */, 309 | ); 310 | name = TunnelPacketKitTests; 311 | productName = TunnelPacketKitTests; 312 | productReference = 361D150C1C4A7184002446F3 /* TunnelPacketKitTests.xctest */; 313 | productType = "com.apple.product-type.bundle.unit-test"; 314 | }; 315 | /* End PBXNativeTarget section */ 316 | 317 | /* Begin PBXProject section */ 318 | 361D14F91C4A7184002446F3 /* Project object */ = { 319 | isa = PBXProject; 320 | attributes = { 321 | LastSwiftUpdateCheck = 0720; 322 | LastUpgradeCheck = 0720; 323 | ORGANIZATIONNAME = "Zhuhao Wang"; 324 | TargetAttributes = { 325 | 361D15011C4A7184002446F3 = { 326 | CreatedOnToolsVersion = 7.2; 327 | }; 328 | 361D150B1C4A7184002446F3 = { 329 | CreatedOnToolsVersion = 7.2; 330 | }; 331 | }; 332 | }; 333 | buildConfigurationList = 361D14FC1C4A7184002446F3 /* Build configuration list for PBXProject "TunnelPacketKit" */; 334 | compatibilityVersion = "Xcode 3.2"; 335 | developmentRegion = English; 336 | hasScannedForEncodings = 0; 337 | knownRegions = ( 338 | en, 339 | ); 340 | mainGroup = 361D14F81C4A7184002446F3; 341 | productRefGroup = 361D15031C4A7184002446F3 /* Products */; 342 | projectDirPath = ""; 343 | projectRoot = ""; 344 | targets = ( 345 | 361D15011C4A7184002446F3 /* TunnelPacketKit */, 346 | 361D150B1C4A7184002446F3 /* TunnelPacketKitTests */, 347 | ); 348 | }; 349 | /* End PBXProject section */ 350 | 351 | /* Begin PBXResourcesBuildPhase section */ 352 | 361D15001C4A7184002446F3 /* Resources */ = { 353 | isa = PBXResourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | ); 357 | runOnlyForDeploymentPostprocessing = 0; 358 | }; 359 | 361D150A1C4A7184002446F3 /* Resources */ = { 360 | isa = PBXResourcesBuildPhase; 361 | buildActionMask = 2147483647; 362 | files = ( 363 | 36530F2D1C4FA421003DFFD5 /* Packet_1.bin in Resources */, 364 | ); 365 | runOnlyForDeploymentPostprocessing = 0; 366 | }; 367 | /* End PBXResourcesBuildPhase section */ 368 | 369 | /* Begin PBXSourcesBuildPhase section */ 370 | 361D14FD1C4A7184002446F3 /* Sources */ = { 371 | isa = PBXSourcesBuildPhase; 372 | buildActionMask = 2147483647; 373 | files = ( 374 | 361D15371C4B4983002446F3 /* TunnelManager.swift in Sources */, 375 | 36A7BD601C7F222B002793CC /* Queue.swift in Sources */, 376 | 361D151D1C4A71F8002446F3 /* IPPacket.swift in Sources */, 377 | 361D152B1C4B39AB002446F3 /* Packet.swift in Sources */, 378 | 36F6CE411C4B9EC000DA7D4C /* Options.swift in Sources */, 379 | 361D15291C4B3214002446F3 /* BinaryDataScanner.swift in Sources */, 380 | 36A7BD621C7F360E002793CC /* SNWUDPTunnel.swift in Sources */, 381 | 361D152D1C4B39F8002446F3 /* TCPPacket.swift in Sources */, 382 | 36D0EE4F1C58F31900DD18AE /* BlockManager.swift in Sources */, 383 | 36D0EE4D1C57AC2C00DD18AE /* TCPDataBlock.swift in Sources */, 384 | 364181631C524F9D0041D94A /* LinkedList.swift in Sources */, 385 | 364181661C52536A0041D94A /* SequenceManager.swift in Sources */, 386 | 36A7BD5D1C7DB487002793CC /* SNWTCPTunnel.swift in Sources */, 387 | 361D153B1C4B5A0D002446F3 /* ProtocolPacket.swift in Sources */, 388 | 361D15301C4B4585002446F3 /* NetworkInterface.swift in Sources */, 389 | 361D15391C4B4BBC002446F3 /* enums.swift in Sources */, 390 | 367C27881C65D87400EAC5F4 /* TCPUtils.swift in Sources */, 391 | 36D0EE511C58FE2800DD18AE /* DataManager.swift in Sources */, 392 | 361D151F1C4A77C8002446F3 /* IPAddress.swift in Sources */, 393 | 364A8F6F1C4E652C001E0D1A /* Checksum.swift in Sources */, 394 | 361D15321C4B4878002446F3 /* Tunnel.swift in Sources */, 395 | 361D15351C4B4886002446F3 /* TCPTunnel.swift in Sources */, 396 | ); 397 | runOnlyForDeploymentPostprocessing = 0; 398 | }; 399 | 361D15081C4A7184002446F3 /* Sources */ = { 400 | isa = PBXSourcesBuildPhase; 401 | buildActionMask = 2147483647; 402 | files = ( 403 | 36530F301C4FA48C003DFFD5 /* IPPacketSpec.swift in Sources */, 404 | 36530F391C4FC8E9003DFFD5 /* ChecksumSpec.swift in Sources */, 405 | 36FF26C81C5A0C13008D8056 /* TCPPacketSpec.swift in Sources */, 406 | ); 407 | runOnlyForDeploymentPostprocessing = 0; 408 | }; 409 | /* End PBXSourcesBuildPhase section */ 410 | 411 | /* Begin PBXTargetDependency section */ 412 | 361D150F1C4A7184002446F3 /* PBXTargetDependency */ = { 413 | isa = PBXTargetDependency; 414 | target = 361D15011C4A7184002446F3 /* TunnelPacketKit */; 415 | targetProxy = 361D150E1C4A7184002446F3 /* PBXContainerItemProxy */; 416 | }; 417 | /* End PBXTargetDependency section */ 418 | 419 | /* Begin XCBuildConfiguration section */ 420 | 361D15141C4A7184002446F3 /* Debug */ = { 421 | isa = XCBuildConfiguration; 422 | buildSettings = { 423 | ALWAYS_SEARCH_USER_PATHS = NO; 424 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 425 | CLANG_CXX_LIBRARY = "libc++"; 426 | CLANG_ENABLE_MODULES = YES; 427 | CLANG_ENABLE_OBJC_ARC = YES; 428 | CLANG_WARN_BOOL_CONVERSION = YES; 429 | CLANG_WARN_CONSTANT_CONVERSION = YES; 430 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 431 | CLANG_WARN_EMPTY_BODY = YES; 432 | CLANG_WARN_ENUM_CONVERSION = YES; 433 | CLANG_WARN_INT_CONVERSION = YES; 434 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 435 | CLANG_WARN_UNREACHABLE_CODE = YES; 436 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 437 | CODE_SIGN_IDENTITY = "-"; 438 | COPY_PHASE_STRIP = NO; 439 | CURRENT_PROJECT_VERSION = 1; 440 | DEBUG_INFORMATION_FORMAT = dwarf; 441 | ENABLE_STRICT_OBJC_MSGSEND = YES; 442 | ENABLE_TESTABILITY = YES; 443 | GCC_C_LANGUAGE_STANDARD = gnu99; 444 | GCC_DYNAMIC_NO_PIC = NO; 445 | GCC_NO_COMMON_BLOCKS = YES; 446 | GCC_OPTIMIZATION_LEVEL = 0; 447 | GCC_PREPROCESSOR_DEFINITIONS = ( 448 | "DEBUG=1", 449 | "$(inherited)", 450 | ); 451 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 452 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 453 | GCC_WARN_UNDECLARED_SELECTOR = YES; 454 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 455 | GCC_WARN_UNUSED_FUNCTION = YES; 456 | GCC_WARN_UNUSED_VARIABLE = YES; 457 | MACOSX_DEPLOYMENT_TARGET = 10.11; 458 | MTL_ENABLE_DEBUG_INFO = YES; 459 | ONLY_ACTIVE_ARCH = YES; 460 | SDKROOT = macosx; 461 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 462 | VERSIONING_SYSTEM = "apple-generic"; 463 | VERSION_INFO_PREFIX = ""; 464 | }; 465 | name = Debug; 466 | }; 467 | 361D15151C4A7184002446F3 /* Release */ = { 468 | isa = XCBuildConfiguration; 469 | buildSettings = { 470 | ALWAYS_SEARCH_USER_PATHS = NO; 471 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 472 | CLANG_CXX_LIBRARY = "libc++"; 473 | CLANG_ENABLE_MODULES = YES; 474 | CLANG_ENABLE_OBJC_ARC = YES; 475 | CLANG_WARN_BOOL_CONVERSION = YES; 476 | CLANG_WARN_CONSTANT_CONVERSION = YES; 477 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 478 | CLANG_WARN_EMPTY_BODY = YES; 479 | CLANG_WARN_ENUM_CONVERSION = YES; 480 | CLANG_WARN_INT_CONVERSION = YES; 481 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 482 | CLANG_WARN_UNREACHABLE_CODE = YES; 483 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 484 | CODE_SIGN_IDENTITY = "-"; 485 | COPY_PHASE_STRIP = NO; 486 | CURRENT_PROJECT_VERSION = 1; 487 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 488 | ENABLE_NS_ASSERTIONS = NO; 489 | ENABLE_STRICT_OBJC_MSGSEND = YES; 490 | GCC_C_LANGUAGE_STANDARD = gnu99; 491 | GCC_NO_COMMON_BLOCKS = YES; 492 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 493 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 494 | GCC_WARN_UNDECLARED_SELECTOR = YES; 495 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 496 | GCC_WARN_UNUSED_FUNCTION = YES; 497 | GCC_WARN_UNUSED_VARIABLE = YES; 498 | MACOSX_DEPLOYMENT_TARGET = 10.11; 499 | MTL_ENABLE_DEBUG_INFO = NO; 500 | SDKROOT = macosx; 501 | VERSIONING_SYSTEM = "apple-generic"; 502 | VERSION_INFO_PREFIX = ""; 503 | }; 504 | name = Release; 505 | }; 506 | 361D15171C4A7184002446F3 /* Debug */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | CLANG_ENABLE_MODULES = YES; 510 | COMBINE_HIDPI_IMAGES = YES; 511 | DEFINES_MODULE = YES; 512 | DYLIB_COMPATIBILITY_VERSION = 1; 513 | DYLIB_CURRENT_VERSION = 1; 514 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 515 | FRAMEWORK_VERSION = A; 516 | INFOPLIST_FILE = TunnelPacketKit/Info.plist; 517 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 518 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 519 | PRODUCT_BUNDLE_IDENTIFIER = me.zhuhaow.TunnelPacketKit; 520 | PRODUCT_NAME = "$(TARGET_NAME)"; 521 | SKIP_INSTALL = YES; 522 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 523 | }; 524 | name = Debug; 525 | }; 526 | 361D15181C4A7184002446F3 /* Release */ = { 527 | isa = XCBuildConfiguration; 528 | buildSettings = { 529 | CLANG_ENABLE_MODULES = YES; 530 | COMBINE_HIDPI_IMAGES = YES; 531 | DEFINES_MODULE = YES; 532 | DYLIB_COMPATIBILITY_VERSION = 1; 533 | DYLIB_CURRENT_VERSION = 1; 534 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 535 | FRAMEWORK_VERSION = A; 536 | INFOPLIST_FILE = TunnelPacketKit/Info.plist; 537 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 538 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 539 | PRODUCT_BUNDLE_IDENTIFIER = me.zhuhaow.TunnelPacketKit; 540 | PRODUCT_NAME = "$(TARGET_NAME)"; 541 | SKIP_INSTALL = YES; 542 | }; 543 | name = Release; 544 | }; 545 | 361D151A1C4A7184002446F3 /* Debug */ = { 546 | isa = XCBuildConfiguration; 547 | buildSettings = { 548 | COMBINE_HIDPI_IMAGES = YES; 549 | FRAMEWORK_SEARCH_PATHS = ( 550 | "$(inherited)", 551 | "$(PROJECT_DIR)/Carthage/Build/Mac", 552 | ); 553 | INFOPLIST_FILE = TunnelPacketKitTests/Info.plist; 554 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 555 | PRODUCT_BUNDLE_IDENTIFIER = me.zhuhaow.TunnelPacketKitTests; 556 | PRODUCT_NAME = "$(TARGET_NAME)"; 557 | }; 558 | name = Debug; 559 | }; 560 | 361D151B1C4A7184002446F3 /* Release */ = { 561 | isa = XCBuildConfiguration; 562 | buildSettings = { 563 | COMBINE_HIDPI_IMAGES = YES; 564 | FRAMEWORK_SEARCH_PATHS = ( 565 | "$(inherited)", 566 | "$(PROJECT_DIR)/Carthage/Build/Mac", 567 | ); 568 | INFOPLIST_FILE = TunnelPacketKitTests/Info.plist; 569 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 570 | PRODUCT_BUNDLE_IDENTIFIER = me.zhuhaow.TunnelPacketKitTests; 571 | PRODUCT_NAME = "$(TARGET_NAME)"; 572 | }; 573 | name = Release; 574 | }; 575 | /* End XCBuildConfiguration section */ 576 | 577 | /* Begin XCConfigurationList section */ 578 | 361D14FC1C4A7184002446F3 /* Build configuration list for PBXProject "TunnelPacketKit" */ = { 579 | isa = XCConfigurationList; 580 | buildConfigurations = ( 581 | 361D15141C4A7184002446F3 /* Debug */, 582 | 361D15151C4A7184002446F3 /* Release */, 583 | ); 584 | defaultConfigurationIsVisible = 0; 585 | defaultConfigurationName = Release; 586 | }; 587 | 361D15161C4A7184002446F3 /* Build configuration list for PBXNativeTarget "TunnelPacketKit" */ = { 588 | isa = XCConfigurationList; 589 | buildConfigurations = ( 590 | 361D15171C4A7184002446F3 /* Debug */, 591 | 361D15181C4A7184002446F3 /* Release */, 592 | ); 593 | defaultConfigurationIsVisible = 0; 594 | defaultConfigurationName = Release; 595 | }; 596 | 361D15191C4A7184002446F3 /* Build configuration list for PBXNativeTarget "TunnelPacketKitTests" */ = { 597 | isa = XCConfigurationList; 598 | buildConfigurations = ( 599 | 361D151A1C4A7184002446F3 /* Debug */, 600 | 361D151B1C4A7184002446F3 /* Release */, 601 | ); 602 | defaultConfigurationIsVisible = 0; 603 | defaultConfigurationName = Release; 604 | }; 605 | /* End XCConfigurationList section */ 606 | }; 607 | rootObject = 361D14F91C4A7184002446F3 /* Project object */; 608 | } 609 | -------------------------------------------------------------------------------- /TunnelPacketKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /TunnelPacketKit/BinaryDataScanner.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BinaryDataScanner.swift 3 | // Murphy 4 | // 5 | // Created by Dave Peck on 7/20/14. 6 | // Copyright (c) 2014 Dave Peck. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /* 12 | Toying with tools to help read binary formats. 13 | 14 | I've seen lots of approaches in swift that create 15 | an intermediate object per-read (usually another NSData) 16 | but even if these are lightweight under the hood, 17 | it seems like overkill. Plus this taught me about <()> aka 18 | 19 | And it would be nice to have an extension to 20 | NSFileHandle too that does much the same. 21 | */ 22 | 23 | protocol BinaryReadable { 24 | var littleEndian: Self { get } 25 | var bigEndian: Self { get } 26 | } 27 | 28 | extension UInt8: BinaryReadable { 29 | var littleEndian: UInt8 { return self } 30 | var bigEndian: UInt8 { return self } 31 | } 32 | 33 | extension UInt16: BinaryReadable {} 34 | 35 | extension UInt32: BinaryReadable {} 36 | 37 | extension UInt64: BinaryReadable {} 38 | 39 | class BinaryDataScanner { 40 | let data: NSData 41 | let littleEndian: Bool 42 | // let encoding: NSStringEncoding 43 | 44 | var current: UnsafePointer 45 | var remaining: Int 46 | var position: Int { 47 | get { 48 | return data.length - remaining 49 | } 50 | } 51 | 52 | init(data: NSData, littleEndian: Bool) { 53 | self.data = data 54 | self.littleEndian = littleEndian 55 | // self.encoding = encoding 56 | 57 | self.current = self.data.bytes 58 | self.remaining = self.data.length 59 | } 60 | 61 | func read() -> T? { 62 | if remaining < sizeof(T) { 63 | return nil 64 | } 65 | 66 | let tCurrent = UnsafePointer(current) 67 | let v = tCurrent.memory 68 | current = UnsafePointer(tCurrent.successor()) 69 | remaining -= sizeof(T) 70 | return littleEndian ? v.littleEndian : v.bigEndian 71 | } 72 | 73 | func skipTo(n: Int) { 74 | remaining = data.length - n 75 | current = data.bytes.advancedBy(n) 76 | } 77 | 78 | func advanceBy(n: Int) { 79 | remaining -= n 80 | current = current.advancedBy(n) 81 | } 82 | 83 | /* convenience read funcs */ 84 | 85 | func readByte() -> UInt8? { 86 | return read() 87 | } 88 | 89 | func read16() -> UInt16? { 90 | return read() 91 | } 92 | 93 | func read32() -> UInt32? { 94 | return read() 95 | } 96 | 97 | func read64() -> UInt64? { 98 | return read() 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /TunnelPacketKit/BlockManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BlockManager.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/27. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class BlockManager { 12 | var blockList: LinkedList? 13 | 14 | func addPacket(packet: IPPacket) { 15 | var blockIter = blockList 16 | while let cBlock = blockIter { 17 | if cBlock.item.takeIn(packet) { 18 | break 19 | } 20 | blockIter = cBlock.next 21 | } 22 | 23 | if blockIter == nil { 24 | // no block takes this in 25 | let block = TCPDataBlock(fromPacket: packet) 26 | let listItem = LinkedList(item: block) 27 | 28 | if blockList == nil { 29 | blockList = listItem 30 | return 31 | } 32 | 33 | if TCPUtils.sequenceLessThanOrEqualTo(block.startSequence, blockList!.item.startSequence) { 34 | listItem.append(blockList!) 35 | blockList = listItem 36 | } 37 | 38 | var blockIter = blockList! 39 | while true { 40 | if blockIter.next == nil { 41 | blockIter.append(listItem) 42 | return 43 | } 44 | 45 | if blockIter.next!.item.startSequence > block.endSequence { 46 | // since next is after current block, it must be inserted now 47 | blockIter.insertAfter(listItem) 48 | return 49 | } 50 | 51 | blockIter = blockIter.next! 52 | } 53 | 54 | } else { 55 | if let nextBlock = blockIter!.next { 56 | if blockIter!.item.merge(nextBlock.item) { 57 | blockIter!.takeOffNext() 58 | } 59 | } 60 | } 61 | } 62 | 63 | func getData(sequenceNumber: UInt32) -> (NSData, Bool)? { 64 | if let block = blockList?.item { 65 | if TCPUtils.sequenceBetween(sequenceNumber, block.startSequence, block.endSequence) { 66 | block.skipToSequenceNumber(sequenceNumber) 67 | return (block.getData(), block.FIN) 68 | } 69 | } 70 | return nil 71 | } 72 | } -------------------------------------------------------------------------------- /TunnelPacketKit/Checksum.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Checksum.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/19. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Checksum { 12 | 13 | static func computeChecksum(data: NSData, from start: Int = 0, to end: Int? = nil, withPseudoHeaderChecksum initChecksum: UInt32 = 0) -> UInt16 { 14 | return toChecksum(computeChecksumUnfold(data, from: start, to: end, withPseudoHeaderChecksum: initChecksum)) 15 | } 16 | 17 | static func validateChecksum(payload: NSData, from start: Int = 0, to end: Int? = nil) -> Bool { 18 | let cs = computeChecksumUnfold(payload, from: start, to: end) 19 | return toChecksum(cs) == 0 20 | } 21 | 22 | static func computeChecksumUnfold(data: NSData, from start: Int = 0, var to end: Int? = nil, withPseudoHeaderChecksum initChecksum: UInt32 = 0) -> UInt32 { 23 | let scanner = BinaryDataScanner(data: data, littleEndian: true) 24 | scanner.skipTo(start) 25 | var result: UInt32 = initChecksum 26 | if end == nil { 27 | end = data.length 28 | } 29 | while scanner.position + 2 <= end { 30 | let value = scanner.read16()! 31 | result += UInt32(value) 32 | } 33 | 34 | if scanner.position != end { 35 | // data is of odd size 36 | // Intel and ARM are both litten endian 37 | // so just add it 38 | let value = scanner.readByte()! 39 | result += UInt32(value) 40 | } 41 | return result 42 | } 43 | 44 | 45 | static func toChecksum(checksum: UInt32) -> UInt16 { 46 | var result = checksum 47 | while (result) >> 16 != 0 { 48 | result = result >> 16 + result & 0xFFFF 49 | } 50 | return ~UInt16(result) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /TunnelPacketKit/DataManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataManager.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/24. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class DataManager { 12 | private var dataArray = [NSData]() 13 | var offset = 0 14 | var length = 0 15 | 16 | func append(data: NSData) { 17 | dataArray.append(data) 18 | length += data.length 19 | } 20 | 21 | func fillTo(data: NSMutableData, offset: Int, length: Int) -> Bool { 22 | guard length <= self.length else { 23 | return false 24 | } 25 | 26 | guard data.length >= offset + length else { 27 | return false 28 | } 29 | 30 | var lengthLeft = length 31 | var currentOffset = offset 32 | while lengthLeft > 0 { 33 | if dataArray[0].length - self.offset <= lengthLeft { 34 | // exhaust first data 35 | data.replaceBytesInRange(NSMakeRange(currentOffset, dataArray[0].length - self.offset), withBytes: dataArray[0].bytes.advancedBy(self.offset)) 36 | self.offset = 0 37 | dataArray.removeFirst() 38 | lengthLeft -= dataArray[0].length - self.offset 39 | currentOffset += dataArray[0].length - self.offset 40 | } else { 41 | // only fills in part data in first data object 42 | data.replaceBytesInRange(NSMakeRange(currentOffset, lengthLeft), withBytes: dataArray[0].bytes.advancedBy(self.offset)) 43 | currentOffset += lengthLeft 44 | lengthLeft = 0 45 | } 46 | } 47 | return true 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /TunnelPacketKit/IPAddress.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IPAddress.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/16. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class IPAddress: CustomStringConvertible { 12 | // this should not return 32 bit value 13 | func toNetworkEndian() -> UInt32 { 14 | return 0 15 | } 16 | 17 | func equalTo(address: IPAddress) -> Bool { 18 | return false 19 | } 20 | 21 | var description: String { 22 | return "IP address" 23 | } 24 | } 25 | 26 | class IPv4Address: IPAddress { 27 | let intRepresentation: UInt32 28 | override var description: String { 29 | return "IPv4 address: \(intRepresentation >> 24).\(intRepresentation >> 16 & 0xFF).\(intRepresentation >> 8 & 0xFF).\(intRepresentation & 0xFF)" 30 | } 31 | 32 | init(fromInt: UInt32) { 33 | intRepresentation = fromInt 34 | } 35 | 36 | convenience init(_ a: Int, _ b: Int, _ c: Int, _ d: Int) { 37 | self.init(fromInt: UInt32(a << 24 + b << 16 + c << 8 + d)) 38 | } 39 | 40 | override func toNetworkEndian() -> UInt32 { 41 | return CFSwapInt32HostToBig(intRepresentation) 42 | } 43 | 44 | override func equalTo(address: IPAddress) -> Bool { 45 | if let address = address as? IPv4Address { 46 | return address.intRepresentation == intRepresentation 47 | } 48 | return false 49 | } 50 | } 51 | 52 | class IPv6Address: IPAddress { 53 | } 54 | -------------------------------------------------------------------------------- /TunnelPacketKit/IPPacket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IPPacket.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/16. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CocoaLumberjackSwift 11 | 12 | protocol OrderedPacket { 13 | var startSequence: UInt32 { get } 14 | /// The last sequence number of the current packet (excluded). 15 | var endSequence: UInt32 { get } 16 | } 17 | 18 | class IPPacket: Packet, OrderedPacket { 19 | /// The version of the current IP packet. 20 | var version: IPVersion = .IPv4 21 | /// The length of the IP packet header. 22 | var headerLength: UInt8 = 20 23 | /// This contains the DSCP and ECN of the IP packet. Since we can not send custom IP packet on iOS/OSX, this is useless and simply ignored. 24 | var ToS: UInt8 = 0 25 | /// This should be the length of the datagram which should be the length of the payload. 26 | /// This value is not read from header since NEPacketTunnelFlow has already taken care of it for us. 27 | var totalLength: UInt16 { 28 | get { 29 | // payloadOffset should always be 0 30 | return UInt16(payloadLength - payloadOffset) 31 | } 32 | } 33 | 34 | /// Identification of the current packet. Since we do not support fragment, this is ignored and always will be zero. 35 | /// - note: Theoratically, this should be a sequentially increasing number. It probably will be implemented. 36 | var identification: UInt16 = 0 37 | /// Offset of the current packet. Since we do not support fragment, this is ignored and always will be zero. 38 | var offset: UInt16 = 0 39 | 40 | var TTL: UInt8 = 64 41 | var packetType: PacketType = .TCP 42 | var sourceAddress: IPAddress! 43 | var destinationAddress: IPAddress! 44 | var protocolPacket: ProtocolPacket! 45 | 46 | /// Short hand for the contained TCP packet. 47 | var tcpPacket: TCPPacket? { 48 | return protocolPacket as? TCPPacket 49 | } 50 | 51 | var startSequence: UInt32 { 52 | if let tcpPacket = tcpPacket { 53 | return tcpPacket.sequenceNumber 54 | } else { 55 | return 0 56 | } 57 | } 58 | 59 | var endSequence: UInt32 { 60 | if let tcpPacket = tcpPacket { 61 | return tcpPacket.endSequence 62 | } else { 63 | return 0 64 | } 65 | } 66 | 67 | var sourcePort: UInt16 { 68 | get { 69 | return protocolPacket.sourcePort 70 | } 71 | set { 72 | protocolPacket.sourcePort = newValue 73 | } 74 | } 75 | 76 | var destinationPort: UInt16 { 77 | get { 78 | return protocolPacket.destinationPort 79 | } 80 | set { 81 | protocolPacket.destinationPort = newValue 82 | } 83 | } 84 | 85 | override func parsePacket() -> Bool { 86 | guard validate() else { 87 | DDLogWarn("Received invalid IP packet which should never happen.") 88 | return false 89 | } 90 | 91 | let scanner = BinaryDataScanner(data: datagram!, littleEndian: false) 92 | scanner.skipTo(payloadOffset) 93 | 94 | let vhl = scanner.readByte()! 95 | guard let v = IPVersion(rawValue: vhl >> 4) else { 96 | DDLogError("Got unknown ip packet version \(vhl >> 4)") 97 | return false 98 | } 99 | version = v 100 | headerLength = vhl & 0x0F * 4 101 | if headerLength != 20 { 102 | DDLogDebug("Received an IP packet with option, which is not supported yet. The option is ignored.") 103 | } 104 | 105 | ToS = scanner.readByte()! 106 | 107 | guard totalLength == scanner.read16()! else { 108 | DDLogError("Packet length mismatches from header.") 109 | return false 110 | } 111 | 112 | identification = scanner.read16()! 113 | offset = scanner.read16()! 114 | TTL = scanner.readByte()! 115 | 116 | guard let proto = PacketType(rawValue: scanner.readByte()!) else { 117 | DDLogWarn("Get unsupported packet protocol.") 118 | return false 119 | } 120 | packetType = proto 121 | 122 | // ignore checksum 123 | _ = scanner.read16()! 124 | 125 | switch version { 126 | case .IPv4: 127 | sourceAddress = IPv4Address(fromInt: scanner.read32()!) 128 | destinationAddress = IPv4Address(fromInt: scanner.read32()!) 129 | default: 130 | // IPv6 is not supported yet. 131 | return false 132 | } 133 | 134 | switch packetType { 135 | case .TCP: 136 | protocolPacket = TCPPacket(datagram, andOffset: Int(headerLength)) 137 | default: 138 | DDLogError("Can not parse packet header of type \(packetType) yet") 139 | return false 140 | } 141 | 142 | return protocolPacket.parsePacket() 143 | } 144 | 145 | override func buildPacket() -> Bool { 146 | guard super.buildPacket() else { 147 | return false 148 | } 149 | 150 | protocolPacket.setDatagram(datagram!, withOffset: Int(headerLength) + payloadOffset) 151 | 152 | // set header 153 | setPayloadWithUInt8(headerLength / 4 + version.rawValue << 4, at: 0) 154 | setPayloadWithUInt8(ToS, at: 1) 155 | setPayloadWithUInt16(totalLength, at: 2) 156 | setPayloadWithUInt16(identification, at: 4) 157 | setPayloadWithUInt16(offset, at: 6) 158 | setPayloadWithUInt8(TTL, at: 8) 159 | setPayloadWithUInt8(packetType.rawValue, at: 9) 160 | // clear checksum bytes 161 | resetPayloadAt(10, length: 2) 162 | setPayloadWithUInt32(sourceAddress.toNetworkEndian(), at: 12, swap: false) 163 | setPayloadWithUInt32(destinationAddress.toNetworkEndian(), at: 16, swap: false) 164 | 165 | // let TCP or UDP packet build 166 | return protocolPacket.buildPacket() 167 | } 168 | 169 | func computePseudoHeaderChecksum() -> UInt32 { 170 | var result: UInt32 = 0 171 | if let address = sourceAddress as? IPv4Address { 172 | result += address.intRepresentation >> 16 + address.intRepresentation & 0xFFFF 173 | } 174 | if let address = destinationAddress as? IPv4Address { 175 | result += address.intRepresentation >> 16 + address.intRepresentation & 0xFFFF 176 | } 177 | result += UInt32(packetType.rawValue) 178 | result += UInt32(protocolPacket.payloadLength) 179 | return result 180 | } 181 | 182 | override func setChecksum(withPseudoHeaderChecksum: UInt32 = 0) { 183 | protocolPacket.setChecksum(computePseudoHeaderChecksum()) 184 | setPayloadWithUInt16(Checksum.computeChecksum(datagram!, from: payloadOffset, to: Int(headerLength) + payloadOffset, withPseudoHeaderChecksum: 0), at: 10, swap: false) 185 | } 186 | 187 | override internal func computePacketLength() -> Int { 188 | return protocolPacket.computePacketLength() + Int(headerLength) 189 | } 190 | 191 | override func validate() -> Bool { 192 | return Checksum.validateChecksum(datagram!, from: payloadOffset, to: Int(headerLength) + payloadOffset) 193 | } 194 | 195 | override func maxDataLength(payloadLength: Int? = nil) -> Int { 196 | var length: Int 197 | if payloadLength != nil { 198 | length = payloadLength! 199 | } else { 200 | length = Int(Options.MTU) 201 | } 202 | length -= Int(headerLength) 203 | 204 | return maxDataLength(length) 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /TunnelPacketKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2016年 Zhuhao Wang. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /TunnelPacketKit/LinkedList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkedList.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/22. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class LinkedList { 12 | var item: T 13 | var next: LinkedList? 14 | var last: LinkedList { 15 | var n = self 16 | while n.next != nil { 17 | n = n.next! 18 | } 19 | return n 20 | } 21 | 22 | init(item: T) { 23 | self.item = item 24 | } 25 | 26 | func append(list: LinkedList) { 27 | last.next = list 28 | } 29 | 30 | func takeOffNext() -> LinkedList? { 31 | let head = next 32 | next = nil 33 | return head 34 | } 35 | 36 | func insertAfter(list: LinkedList) { 37 | let n = next 38 | next = list 39 | list.last.next = n 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /TunnelPacketKit/NetworkInterface.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NetworkInterface.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CocoaLumberjackSwift 11 | 12 | protocol NetworkInterfaceDelegate: class { 13 | func acceptedNewTunnel(_: Tunnel) 14 | func sendPackets(_: [IPPacket]) 15 | } 16 | 17 | class NetworkInterface { 18 | let queue: dispatch_queue_t 19 | let slowTimer: dispatch_source_t 20 | let fastTimer: dispatch_source_t 21 | let tunnelManager: TunnelManager 22 | weak var delegate: NetworkInterfaceDelegate? 23 | 24 | init() { 25 | DDLogVerbose("Start initialize virtual network interface.") 26 | 27 | queue = dispatch_queue_create("TunnelPacketKit.ProcessQueue", DISPATCH_QUEUE_SERIAL) 28 | slowTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue) 29 | fastTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue) 30 | DDLogDebug("Process queue and timer created.") 31 | 32 | tunnelManager = TunnelManager() 33 | tunnelManager.newTunnelHandler = { 34 | [weak self] tunnel in 35 | self?.acceptedNewTunnel(tunnel) 36 | } 37 | tunnelManager.sendPackets = { 38 | [weak self] packets in 39 | self?.sendPackets(packets) 40 | } 41 | DDLogDebug("Tunnel manager created.") 42 | 43 | DDLogDebug("Start fast and slow timer.") 44 | dispatch_source_set_timer(slowTimer, DISPATCH_TIME_NOW , Options.slowTimerInterval * NSEC_PER_MSEC, Options.timerLeeway * NSEC_PER_MSEC) 45 | dispatch_source_set_event_handler(slowTimer) { 46 | [weak self] in 47 | self?.slowTimerHandler() 48 | } 49 | dispatch_source_set_timer(fastTimer, DISPATCH_TIME_NOW , Options.fastTimerInterval * NSEC_PER_MSEC, Options.timerLeeway * NSEC_PER_MSEC) 50 | dispatch_source_set_event_handler(fastTimer) { 51 | [weak self] in 52 | self?.fastTimerHandler() 53 | } 54 | dispatch_resume(slowTimer) 55 | dispatch_resume(fastTimer) 56 | DDLogDebug("Timer started.") 57 | 58 | DDLogVerbose("Successfully initialized virtual network interface.") 59 | } 60 | 61 | func perform(block: () -> ()) { 62 | dispatch_async(queue, block) 63 | } 64 | 65 | private func receivedPacket(packet: NSData, version: NSNumber) { 66 | self.tunnelManager.receivedPacket(packet, version: version) 67 | } 68 | 69 | func receivedPackets(packets: [NSData], versions: [NSNumber]) { 70 | DDLogDebug("Virtual network interface recieved \(packets.count) packets. Processing them now.") 71 | perform { 72 | for var i = 0; i < packets.count; ++i { 73 | self.receivedPacket(packets[i], version: versions[i]) 74 | } 75 | } 76 | } 77 | 78 | func acceptedNewTunnel(tunnel: Tunnel) { 79 | delegate?.acceptedNewTunnel(tunnel) 80 | } 81 | 82 | func sendPackets(packets: [IPPacket]) { 83 | delegate?.sendPackets(packets) 84 | } 85 | 86 | func slowTimerHandler() { 87 | DDLogDebug("Slow timer triggered.") 88 | tunnelManager.slowTimerHandler() 89 | } 90 | 91 | func fastTimerHandler() { 92 | DDLogDebug("Fast timer triggered.") 93 | tunnelManager.fastTimerHandler() 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /TunnelPacketKit/Options.swift: -------------------------------------------------------------------------------- 1 | // 2 | // opts.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Options { 12 | static let MTU: UInt16 = 1500 13 | static let localTCPMSS: UInt16 = 1420 14 | static let localTCPWindowScale: UInt8 = 8 15 | /// Time interval for fast timer in ms. 16 | static let fastTimerInterval: UInt64 = 200 17 | /// Time interval for slow timer in ms. 18 | static let slowTimerInterval: UInt64 = 500 19 | static let timerLeeway: UInt64 = 50 20 | } 21 | -------------------------------------------------------------------------------- /TunnelPacketKit/Packet.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProtocolPacket.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Base class for any packet. 12 | class Packet { 13 | /// The datagram. 14 | /// - seealso: `payloadOffset` 15 | var datagram: NSData? 16 | /// The offset of this packet's payload in datagram. 17 | /// - note: In order to archive zero-copy in parsing and building packet, we share the `datagram` in `IPPacket` and the protocol packet (e.g., TCP, UDP) it contains, with the `payloadOffset` marking the offset. 18 | var payloadOffset: Int = 0 19 | /// The length of the payload. 20 | /// - note: This returns the total length of the recevied payload data object, not the payload of current packet. 21 | var payloadLength: Int { 22 | if let datagram = datagram { 23 | return datagram.length - payloadOffset 24 | } else { 25 | return 0 26 | } 27 | } 28 | 29 | /// Return the mutable version of the datagram 30 | /// - warning: The datagram must be able to be case into NSMutableData. 31 | var mutableDatagram: NSMutableData { 32 | return datagram as! NSMutableData 33 | } 34 | 35 | /** 36 | Initialize a packet with datagram and offset of the payload. 37 | 38 | - parameter datagram: Data of the datagram. 39 | - parameter offset: The offset of the payload of current packet. 40 | */ 41 | init(_ datagram: NSData? = nil, andOffset offset: Int = 0) { 42 | self.datagram = datagram 43 | self.payloadOffset = offset 44 | } 45 | 46 | /** 47 | Parse the payload and get all the information. 48 | 49 | - returns: If sucessfully parsed the packet or not. 50 | */ 51 | func parsePacket() -> Bool { 52 | return false 53 | } 54 | 55 | /** 56 | Validate if the current packet is valid based on the Checksum. 57 | - Note: This is not needed in real application since there usually is no error in intranet. 58 | 59 | - returns: If the packet is valid or not. 60 | */ 61 | func validate() -> Bool { 62 | // there is simply no need to verify the packet data against checksum 63 | return true 64 | } 65 | 66 | /** 67 | Generate the payload of the current packet. 68 | - warning: Should only be called after the payload length of the current packet can be determined by `computePacketLength()`. 69 | - seealso: `computePacketLength()` 70 | 71 | - returns: If the packet is build successfully or not. 72 | */ 73 | func buildPacket() -> Bool { 74 | createMutableDatagram() 75 | return true 76 | } 77 | 78 | /** 79 | Compute and set the checksum. 80 | - note: This should be called in the last since it requires that everything else in payload is set. Any further modification invalidate this packet and requires resetting the checksum. 81 | 82 | - parameter withInitChecksum: This is useful with protocol like TCP which requires the checksum of a pseudo header. 83 | */ 84 | func setChecksum(withInitChecksum: UInt32 = 0) {} 85 | 86 | /** 87 | Just a helper method. 88 | - note: Should use it whenever possible. 89 | 90 | - parameter datagram: the datagram data 91 | - parameter offset: the offset of the payload in the datagram 92 | */ 93 | func setDatagram(datagram: NSData, withOffset offset: Int = 0) { 94 | self.datagram = datagram 95 | self.payloadOffset = offset 96 | } 97 | 98 | internal func createMutableDatagram() { 99 | self.datagram = NSMutableData(length: computePacketLength()) 100 | } 101 | 102 | func setPayloadWithUInt8(value: UInt8, at: Int) { 103 | var v = value 104 | mutableDatagram.replaceBytesInRange(NSMakeRange(at + payloadOffset, 1), withBytes: &v) 105 | } 106 | 107 | func setPayloadWithUInt16(value: UInt16, at: Int, swap: Bool = true) { 108 | var v: UInt16 109 | if swap { 110 | v = CFSwapInt16HostToBig(value) 111 | } else { 112 | v = value 113 | } 114 | mutableDatagram.replaceBytesInRange(NSMakeRange(at + payloadOffset, 2), withBytes: &v) 115 | } 116 | 117 | func setPayloadWithUInt32(value: UInt32, at: Int, swap: Bool = true) { 118 | var v: UInt32 119 | if swap { 120 | v = CFSwapInt32HostToBig(value) 121 | } else { 122 | v = value 123 | } 124 | mutableDatagram.replaceBytesInRange(NSMakeRange(at + payloadOffset, 4), withBytes: &v) 125 | } 126 | 127 | func setPayloadWithData(data: NSData, at: Int, var length: Int? = nil, from: Int = 0) { 128 | if length == nil { 129 | length = data.length - from 130 | } 131 | let pointer = data.bytes.advancedBy(from) 132 | mutableDatagram.replaceBytesInRange(NSMakeRange(at, length!), withBytes: pointer) 133 | } 134 | 135 | func resetPayloadAt(at: Int, length: Int) { 136 | mutableDatagram.resetBytesInRange(NSMakeRange(at, length)) 137 | } 138 | 139 | /// The max size of data. 140 | func maxDataLength(payloadLength: Int? = nil) -> Int { 141 | return 0 142 | } 143 | 144 | internal func computePacketLength() -> Int { 145 | return 0 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /TunnelPacketKit/ProtocolPacket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProtocolPacket.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /// Base class for TCP and UDP packet. 12 | /// - note: Since it not possible to send out packet other than TCP and UDP, the protocol packet must have port information. 13 | class ProtocolPacket: Packet { 14 | var sourcePort: UInt16! 15 | var destinationPort: UInt16! 16 | var dataOffsetInDatagram: Int { return payloadOffset } 17 | } 18 | -------------------------------------------------------------------------------- /TunnelPacketKit/Queue.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Queue.swift 3 | // NTBSwift 4 | // 5 | // Created by Kåre Morstøl on 11/07/14. 6 | // 7 | // Using the "Two-Lock Concurrent Queue Algorithm" from http://www.cs.rochester.edu/research/synchronization/pseudocode/queues.html#tlq, without the locks. 8 | 9 | 10 | // should be an inner class of Queue, but inner classes and generics crash the compiler, SourceKit (repeatedly) and occasionally XCode. 11 | class _QueueItem { 12 | let value: T! 13 | var next: _QueueItem? 14 | 15 | init(_ newvalue: T?) { 16 | self.value = newvalue 17 | } 18 | } 19 | 20 | /// 21 | /// A standard queue (FIFO - First In First Out). Supports simultaneous adding and removing, but only one item can be added at a time, and only one item can be removed at a time. 22 | /// 23 | public class Queue { 24 | 25 | public typealias Element = T 26 | 27 | var _front: _QueueItem 28 | var _back: _QueueItem 29 | 30 | public init () { 31 | // Insert dummy item. Will disappear when the first item is added. 32 | _back = _QueueItem(nil) 33 | _front = _back 34 | } 35 | 36 | /// Add a new item to the back of the queue. 37 | public func enqueue (value: Element) { 38 | _back.next = _QueueItem(value) 39 | _back = _back.next! 40 | } 41 | 42 | /// Return and remove the item at the front of the queue. 43 | public func dequeue () -> Element? { 44 | if let newhead = _front.next { 45 | _front = newhead 46 | return newhead.value 47 | } else { 48 | return nil 49 | } 50 | } 51 | 52 | public func isEmpty() -> Bool { 53 | return _front === _back 54 | } 55 | } -------------------------------------------------------------------------------- /TunnelPacketKit/SNWTCPTunnel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SNWTCPTunnel.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 2/24/16. 6 | // Copyright © 2016 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import NetworkExtension 11 | import CocoaLumberjackSwift 12 | 13 | @objc protocol SNWTCPTunnelDelegate : class { 14 | func connectionEstablished(_: SNWTCPTunnel) 15 | func connectionClosed(_: SNWTCPTunnel) 16 | func receivedData(_: NSData, fromTunnel: SNWTCPTunnel) 17 | optional func dataSend(_: NSData, fromTunnel: SNWTCPTunnel) 18 | optional func readClosed(_: SNWTCPTunnel) 19 | } 20 | 21 | class SNWTCPTunnel : NSObject { 22 | let connection: NWTCPConnection 23 | private weak var delegate: SNWTCPTunnelDelegate? 24 | var lastError: NSError? 25 | private var dataQueue = Queue() 26 | private var writingData = false 27 | private let dataProcessQueue = dispatch_queue_create("SNWTCPTunnel.dataProcessingQueue", DISPATCH_QUEUE_SERIAL) 28 | 29 | init(connection: NWTCPConnection, delegate: SNWTCPTunnelDelegate?) { 30 | self.connection = connection 31 | self.delegate = delegate 32 | super.init() 33 | 34 | self.connection.addObserver(self, forKeyPath: "state", options: .Initial, context: nil) 35 | } 36 | 37 | override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) { 38 | guard keyPath == "state" else { 39 | super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) 40 | return 41 | } 42 | 43 | DDLogVerbose("SNWTunnel state changed to \(connection.state).") 44 | 45 | switch connection.state { 46 | case .Connected: 47 | delegate?.connectionEstablished(self) 48 | case .Disconnected: 49 | closeTunnel() 50 | case .Cancelled: 51 | connection.removeObserver(self, forKeyPath: "state") 52 | delegate?.connectionClosed(self) 53 | default: 54 | break 55 | } 56 | } 57 | 58 | func sendData(data: NSData) { 59 | dispatch_async(dataProcessQueue) { 60 | self.dataQueue.enqueue(data) 61 | self.writeData() 62 | } 63 | } 64 | 65 | private func writeData() { 66 | dispatch_async(dataProcessQueue) { 67 | if !self.writingData { 68 | if let data = self.dataQueue.dequeue() { 69 | self.writingData = true 70 | self.connection.write(data) { error in 71 | guard error == nil else { 72 | self.closeTunnelWithError(error) 73 | return 74 | } 75 | 76 | self.delegate?.dataSend?(data, fromTunnel: self) 77 | self.writingData = false 78 | self.writeData() 79 | } 80 | } 81 | } 82 | } 83 | } 84 | 85 | func writeClose() { 86 | connection.writeClose() 87 | } 88 | 89 | func closeTunnel() { 90 | connection.cancel() 91 | } 92 | 93 | func closeTunnelWithError(error: NSError?) { 94 | lastError = error 95 | closeTunnel() 96 | } 97 | 98 | func readData() { 99 | connection.readMinimumLength(0, maximumLength: 0) { data, error in 100 | if let error = error { 101 | DDLogError("SNWTunnel got an error when reading data: \(error)") 102 | self.closeTunnelWithError(error) 103 | return 104 | } 105 | 106 | guard let data = data else { 107 | self.delegate?.readClosed?(self) 108 | return 109 | } 110 | 111 | self.delegate?.receivedData(data, fromTunnel: self) 112 | self.readData() 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /TunnelPacketKit/SNWUDPTunnel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SNWUDPTunnel.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 2/25/16. 6 | // Copyright © 2016 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import NetworkExtension 11 | import CocoaLumberjackSwift 12 | 13 | @objc protocol SNWUDPTunnelDelegate { 14 | func ready(_: SNWUDPTunnel) 15 | func receivedDatagrams(_: [NSData]) 16 | func closed(_: SNWUDPTunnel) 17 | } 18 | 19 | class SNWUDPTunnel : NSObject { 20 | let session: NWUDPSession 21 | private weak var delegate: SNWUDPTunnelDelegate? 22 | var lastError: NSError? 23 | let maxReadDatagrams = 100 24 | private var dataQueue = [NSData]() 25 | private let dataProcessQueue = dispatch_queue_create("SNWUDPTunnel.dataProcessingQueue", DISPATCH_QUEUE_SERIAL) 26 | 27 | 28 | init(session: NWUDPSession, delegate: SNWUDPTunnelDelegate?) { 29 | self.session = session 30 | self.delegate = delegate 31 | super.init() 32 | 33 | self.session.setReadHandler(readHandler, maxDatagrams: maxReadDatagrams) 34 | self.session.addObserver(self, forKeyPath: "state", options: .Initial, context: nil) 35 | } 36 | 37 | override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) { 38 | guard keyPath == "state" else { 39 | super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context) 40 | return 41 | } 42 | 43 | DDLogVerbose("SNWTunnel state changed to \(session.state).") 44 | 45 | switch session.state { 46 | case .Ready: 47 | delegate?.ready(self) 48 | case .Failed: 49 | closeTunnel() 50 | case .Cancelled: 51 | session.removeObserver(self, forKeyPath: "state") 52 | delegate?.closed(self) 53 | default: 54 | break 55 | } 56 | } 57 | 58 | func readHandler(datagrams: [NSData]?, error: NSError?) { 59 | guard error == nil else { 60 | closeTunnelWithError(error) 61 | return 62 | } 63 | 64 | delegate?.receivedDatagrams(datagrams!) 65 | } 66 | 67 | func sendDatagrams(datagrams: [NSData]) { 68 | dispatch_async(dataProcessQueue) { 69 | self.dataQueue.appendContentsOf(datagrams) 70 | self.writeData() 71 | } 72 | } 73 | 74 | private func writeData() { 75 | dispatch_async(dataProcessQueue) { 76 | self.session.writeMultipleDatagrams(self.dataQueue) { 77 | error in 78 | guard error == nil else { 79 | self.closeTunnelWithError(error) 80 | return 81 | } 82 | } 83 | self.dataQueue.removeAll(keepCapacity: true) 84 | } 85 | } 86 | 87 | func closeTunnel() { 88 | session.cancel() 89 | } 90 | 91 | func closeTunnelWithError(error: NSError?) { 92 | lastError = error 93 | closeTunnel() 94 | } 95 | } -------------------------------------------------------------------------------- /TunnelPacketKit/SequenceManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SequenceManager.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/22. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class SequenceManager : SequenceType { 12 | var list: LinkedList? 13 | 14 | func generate() -> AnyGenerator { 15 | var iterator: LinkedList? = list 16 | return anyGenerator { 17 | if let iter = iterator { 18 | defer { 19 | iterator = iter.next 20 | } 21 | return iter.item 22 | } else { 23 | return nil 24 | } 25 | } 26 | } 27 | } 28 | 29 | class SequencePacketManager: SequenceManager { 30 | var sequenceNumber: UInt32? { 31 | return list?.item.startSequence 32 | } 33 | 34 | func insertPacket(packet: IPPacket) { 35 | let listItem: LinkedList = LinkedList(item: packet) 36 | 37 | if list == nil { 38 | list = listItem 39 | return 40 | } 41 | 42 | if let list = list { 43 | var iter = list 44 | 45 | while true { 46 | if iter.next == nil { 47 | iter.next = listItem 48 | return 49 | } else { 50 | if TCPUtils.sequenceLessThanOrEqualTo(iter.item.startSequence, packet.tcpPacket!.sequenceNumber) && 51 | TCPUtils.sequenceLessThan(packet.tcpPacket!.sequenceNumber, iter.next!.item.startSequence) { 52 | iter.insertAfter(listItem) 53 | return 54 | } else { 55 | iter = iter.next! 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | // not include the number 63 | func removeBefore(sequenceNumber: UInt32) { 64 | while true { 65 | guard let iter = list else { 66 | return 67 | } 68 | 69 | if TCPUtils.sequenceLessThan(iter.item.endSequence, sequenceNumber) { 70 | list = iter.next 71 | } else { 72 | return 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /TunnelPacketKit/TCPDataBlock.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataBlock.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/26. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class TCPDataBlock { 12 | /// Continuous data stored in tuple as (data, offsetIndex, endIndex). 13 | var datagrams: [(NSData, Int, Int)] 14 | var dataLength: Int 15 | var startSequence: UInt32 16 | var endSequence: UInt32 17 | var FIN = false 18 | 19 | init(fromPacket packet: IPPacket) { 20 | datagrams = [(packet.datagram!, packet.tcpPacket!.dataOffsetInDatagram, packet.datagram!.length)] 21 | dataLength = packet.tcpPacket!.dataLength 22 | startSequence = packet.startSequence 23 | endSequence = packet.endSequence 24 | FIN = packet.tcpPacket!.FIN 25 | } 26 | 27 | /** 28 | Take in the packet if this packet is contained or can be appended to this data block. 29 | 30 | - parameter packet: The packet to be taken in. 31 | 32 | - returns: If this data block has taken in this packet. 33 | */ 34 | func takeIn(packet: IPPacket) -> Bool { 35 | guard let tcpPacket = packet.tcpPacket else { 36 | return false 37 | } 38 | 39 | if TCPUtils.sequenceGreaterThanOrEqualTo(tcpPacket.startSequence, startSequence) && TCPUtils.sequenceLessThanOrEqualTo(tcpPacket.endSequence, endSequence) { 40 | // Got a duplicated packet already contained, just takes it in. 41 | return true 42 | } 43 | 44 | if TCPUtils.sequenceBetween(tcpPacket.startSequence, startSequence, endSequence) && TCPUtils.sequenceGreaterThan(tcpPacket.endSequence, endSequence) { 45 | // have new data can be appended 46 | let offset = tcpPacket.dataOffsetInDatagram + Int(endSequence - tcpPacket.startSequence) 47 | let end = tcpPacket.datagram!.length 48 | datagrams.append((tcpPacket.datagram!, offset, end)) 49 | 50 | dataLength += end - offset 51 | endSequence = tcpPacket.endSequence 52 | // we should only take the FIN from the last packet. 53 | FIN = FIN || tcpPacket.FIN 54 | return true 55 | } 56 | 57 | return false 58 | } 59 | 60 | /** 61 | Merge the two data block if possible. 62 | - note: Only appendation is considered. 63 | 64 | - parameter block: The block to be merged. 65 | 66 | - returns: If the block is merged. 67 | */ 68 | func merge(block: TCPDataBlock) -> Bool { 69 | guard TCPUtils.sequenceGreaterThanOrEqualTo(endSequence &+ 1, block.startSequence) else { 70 | return false 71 | } 72 | 73 | block.skipToSequenceNumber(endSequence) 74 | datagrams.appendContentsOf(block.datagrams) 75 | dataLength += block.dataLength 76 | endSequence = block.endSequence 77 | FIN = FIN || block.FIN 78 | 79 | return true 80 | } 81 | 82 | func skipToSequenceNumber(sequenceNumber: UInt32) { 83 | guard datagrams.count > 0 else { 84 | return 85 | } 86 | 87 | if TCPUtils.sequenceLessThan(endSequence, sequenceNumber) { 88 | datagrams = [] 89 | startSequence = sequenceNumber 90 | endSequence = sequenceNumber 91 | dataLength = 0 92 | FIN = false 93 | return 94 | } 95 | 96 | while TCPUtils.sequenceLessThan(startSequence, sequenceNumber) { 97 | // the packet should not contain SYN anyway, this case is ignored. 98 | // we assume the only case that `dataLength != endSequence - startSequence` is that FIN is received at the last data packet, thus we can assume the following is right. 99 | let firstDataEnd = startSequence &+ UInt32(datagrams[0].2 - datagrams[0].1) 100 | if TCPUtils.sequenceLessThan(firstDataEnd, sequenceNumber) { 101 | // remove first data object 102 | datagrams.removeFirst() 103 | startSequence = firstDataEnd &+ 1 104 | dataLength -= datagrams[0].2 - datagrams[0].1 105 | } else { 106 | datagrams[0].1 += Int(sequenceNumber &- startSequence) 107 | dataLength -= Int(sequenceNumber &- startSequence) 108 | startSequence = sequenceNumber 109 | return 110 | } 111 | } 112 | } 113 | 114 | func getData() -> NSData { 115 | let data = NSMutableData(capacity: dataLength)! 116 | var offset = 0 117 | for (datagram, offsetIndex, endIndex) in datagrams { 118 | data.replaceBytesInRange(NSMakeRange(offset, endIndex - offsetIndex), withBytes: datagram.bytes.advancedBy(offsetIndex)) 119 | offset += endIndex - offsetIndex 120 | } 121 | return data 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /TunnelPacketKit/TCPPacket.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TCPPacket.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CocoaLumberjackSwift 11 | 12 | class TCPPacket: ProtocolPacket, OrderedPacket { 13 | let fixedHeaderLength = 20 14 | var sequenceNumber: UInt32! 15 | var acknowledgmentNumber: UInt32! 16 | /// The offset in the header. 17 | var _dataOffset: UInt8! 18 | /// The real offset in bytes. 19 | var dataOffset: Int { 20 | get { 21 | return Int(_dataOffset) * 4 22 | } 23 | set { 24 | _dataOffset = UInt8(newValue / 4) 25 | } 26 | } 27 | var ECN: UInt8! = 0 28 | var controlType: ControlType! 29 | var window: UInt16! 30 | var checksum: UInt16! 31 | var urgentPointer: UInt16! 32 | var option: TCPOption! 33 | 34 | var optionLength: Int { 35 | if let option = option { 36 | return option.length 37 | } else { 38 | return 0 39 | } 40 | } 41 | 42 | var headerLength: Int { 43 | return fixedHeaderLength + optionLength 44 | } 45 | 46 | /// This should be set before any call to any method depending on `computePacketLength()` 47 | var lengthOfDataToSend: Int = 0 48 | 49 | // MARK: Flags Accessors 50 | var URG: Bool { 51 | get { 52 | return controlType.contains(.URG) 53 | } 54 | set { 55 | if newValue { 56 | controlType.intersectInPlace(.URG) 57 | } else { 58 | controlType.subtractInPlace(.URG) 59 | } 60 | } 61 | } 62 | 63 | var ACK: Bool { 64 | get { 65 | return controlType.contains(.ACK) 66 | } 67 | set { 68 | if newValue { 69 | controlType.intersectInPlace(.ACK) 70 | } else { 71 | controlType.subtractInPlace(.ACK) 72 | } 73 | } 74 | } 75 | 76 | var PSH: Bool { 77 | get { 78 | return controlType.contains(.PSH) 79 | } 80 | set { 81 | if newValue { 82 | controlType.intersectInPlace(.PSH) 83 | } else { 84 | controlType.subtractInPlace(.PSH) 85 | } 86 | } 87 | } 88 | 89 | var RST: Bool { 90 | get { 91 | return controlType.contains(.RST) 92 | } 93 | set { 94 | if newValue { 95 | controlType.intersectInPlace(.RST) 96 | } else { 97 | controlType.subtractInPlace(.RST) 98 | } 99 | } 100 | } 101 | 102 | var SYN: Bool { 103 | get { 104 | return controlType.contains(.SYN) 105 | } 106 | set { 107 | if newValue { 108 | controlType.intersectInPlace(.SYN) 109 | } else { 110 | controlType.subtractInPlace(.SYN) 111 | } 112 | } 113 | } 114 | 115 | var FIN: Bool { 116 | get { 117 | return controlType.contains(.FIN) 118 | } 119 | set { 120 | if newValue { 121 | controlType.intersectInPlace(.FIN) 122 | } else { 123 | controlType.subtractInPlace(.FIN) 124 | } 125 | } 126 | } 127 | 128 | /// The length of data contained in the packet. 129 | var dataLength: Int { 130 | return datagram!.length - dataOffsetInDatagram 131 | } 132 | 133 | /// The length of this packet based on sequence number. 134 | var sequenceLength: Int { 135 | if controlType.contains(.FIN) || controlType.contains(.SYN) { 136 | return dataLength + 1 137 | } else { 138 | return dataLength 139 | } 140 | } 141 | 142 | /// If there is any data in this packet. 143 | var dataAvailable: Bool { 144 | return dataLength > 0 145 | } 146 | 147 | /// The offset of data in the datagram. 148 | /// Use this name since `dataOffset` is already taken as the variable for the header field. 149 | override var dataOffsetInDatagram: Int { 150 | return dataOffset + payloadOffset 151 | } 152 | 153 | /// Get data. 154 | var data: NSData { 155 | return datagram!.subdataWithRange(NSMakeRange(dataOffsetInDatagram, dataLength)) 156 | } 157 | 158 | /// If this packet has option field. 159 | var hasOption: Bool { 160 | return dataOffset > fixedHeaderLength 161 | } 162 | 163 | // MARK: OrderedPacket Protocol 164 | var startSequence: UInt32 { 165 | return sequenceNumber 166 | } 167 | 168 | var endSequence: UInt32 { 169 | return sequenceNumber + UInt32(sequenceLength) 170 | } 171 | 172 | override func parsePacket() -> Bool { 173 | let scanner = BinaryDataScanner(data: datagram!, littleEndian: false) 174 | scanner.skipTo(payloadOffset) 175 | 176 | sourcePort = scanner.read16()! 177 | destinationPort = scanner.read16()! 178 | sequenceNumber = scanner.read32()! 179 | acknowledgmentNumber = scanner.read32()! 180 | 181 | var info = scanner.readByte()! 182 | // dataOffset returns the real dataOffset in 8bit 183 | _dataOffset = info >> 4 184 | 185 | // ignore ECN info 186 | info = scanner.readByte()! 187 | controlType = ControlType(rawValue: info & 0x3F) 188 | 189 | window = scanner.read16()! 190 | checksum = scanner.read16()! 191 | urgentPointer = scanner.read16()! 192 | 193 | parseOptions() 194 | 195 | return true 196 | } 197 | 198 | private func parseOptions() { 199 | option = TCPOption() 200 | if hasOption { 201 | option.parseDatagram(datagram!, offset: payloadOffset + fixedHeaderLength, to: dataOffsetInDatagram) 202 | } 203 | } 204 | 205 | /** 206 | Build the TCP packet based on current information. 207 | - note: Since TCP packet is contained in IP packet, the datagram shoule already be created by `IPPacket`. If not, datagram should be set first with `setDataGram` 208 | - note: Data is not set yet. 209 | 210 | - returns: If the packet successfully built. 211 | */ 212 | override func buildPacket() -> Bool { 213 | dataOffset = headerLength 214 | 215 | setPayloadWithUInt16(sourcePort, at: 0) 216 | setPayloadWithUInt16(destinationPort, at: 2) 217 | setPayloadWithUInt32(sequenceNumber, at: 4) 218 | setPayloadWithUInt32(acknowledgmentNumber, at: 8) 219 | setPayloadWithUInt8(_dataOffset << 4, at: 12) 220 | setPayloadWithUInt8(controlType.rawValue, at: 13) 221 | setPayloadWithUInt16(window, at: 14) 222 | // reset checksum and urgent pointer 223 | resetPayloadAt(16, length: 4) 224 | if let option = option { 225 | option.setOptionInPacket(self, offset: fixedHeaderLength) 226 | } 227 | 228 | return true 229 | } 230 | 231 | override internal func computePacketLength() -> Int { 232 | return 20 + optionLength + lengthOfDataToSend 233 | } 234 | 235 | override func maxDataLength(payloadLength: Int?) -> Int { 236 | guard let payloadLength = payloadLength else { 237 | DDLogError("Must know max payload lenth before compute max data length can be embeded in current TCP packet, try to use the best value possible.") 238 | return Int(Options.localTCPMSS) - Int(optionLength) 239 | } 240 | let dataLength = payloadLength - headerLength 241 | return Int(Options.localTCPMSS) < dataLength ? Int(Options.localTCPMSS) : dataLength 242 | } 243 | 244 | override func setChecksum(withPseudoHeaderChecksum: UInt32) { 245 | setPayloadWithUInt16(Checksum.computeChecksum(datagram!, from: payloadOffset, withPseudoHeaderChecksum: withPseudoHeaderChecksum), at: 16, swap: false) 246 | } 247 | 248 | /** 249 | If this packet contains the given sequence. 250 | 251 | - parameter sequence: The sequence number to be checked. 252 | 253 | - returns: If this packet contains this sequence. 254 | */ 255 | func containSequence(sequence: UInt32) -> Bool { 256 | if startSequence <= sequence && endSequence > sequence { 257 | return true 258 | } else { 259 | return false 260 | } 261 | } 262 | 263 | // func findSequenceData(sequence: UInt32) -> UnsafePointer? { 264 | // if containSequence(sequence) { 265 | // return datagram!.bytes.advancedBy(payloadOffset + dataOffset + Int(sequence - sequenceNumber)) 266 | // } else { 267 | // return nil 268 | // } 269 | // } 270 | } 271 | 272 | class TCPOption { 273 | var MSS: UInt16? 274 | var windowScale: UInt8? { 275 | get { 276 | if let ws = _windowScale { 277 | return ws > 14 ? 14 : ws 278 | } 279 | return nil 280 | } 281 | set { 282 | _windowScale = newValue 283 | } 284 | } 285 | private var _windowScale: UInt8? 286 | var _length: Int? 287 | var length: Int { 288 | get { 289 | if let len = _length { 290 | return len 291 | } else { 292 | return computeLength() 293 | } 294 | } 295 | set { 296 | _length = newValue 297 | } 298 | } 299 | 300 | init() {} 301 | 302 | func parseDatagram(datagram: NSData, offset: Int, to: Int) { 303 | length = to - offset 304 | let scanner = BinaryDataScanner(data: datagram, littleEndian: false) 305 | scanner.skipTo(offset) 306 | 307 | scanLoop: while scanner.position < to { 308 | let kind = scanner.readByte()! 309 | guard kind != 0 else { 310 | break 311 | } 312 | 313 | switch kind { 314 | case 1: 315 | break 316 | case 2: 317 | // MSS 318 | let length = scanner.readByte()! 319 | // expect length to be 4 320 | guard length != 4 else { 321 | DDLogError("Invalid MSS option, length should be 4 instead of \(length)") 322 | break scanLoop 323 | } 324 | MSS = scanner.read16()! 325 | case 3: 326 | // Window Scale 327 | let length = scanner.readByte()! 328 | guard length != 3 else { 329 | DDLogError("Invalid Window Scale option, length should be 3 instead of \(length)") 330 | break scanLoop 331 | } 332 | windowScale = scanner.readByte()! 333 | default: 334 | // does not support any other options for now 335 | let length = scanner.readByte()! 336 | for _ in 0..<(length-2) { 337 | scanner.readByte()! 338 | } 339 | } 340 | } 341 | } 342 | 343 | private func computeLength() -> Int { 344 | var length = 0 345 | if MSS != nil { 346 | length += 4 347 | } 348 | if windowScale != nil { 349 | length += 3 350 | } 351 | // length should be the multiple of 4 352 | length = Int(ceil(Float(length) / Float(4)) * 4) 353 | return length 354 | } 355 | 356 | func setOptionInPacket(tcpPacket: TCPPacket, offset: Int) { 357 | tcpPacket.resetPayloadAt(offset, length: computeLength()) 358 | var currentOffset = offset 359 | if MSS != nil { 360 | tcpPacket.setPayloadWithUInt8(2, at: currentOffset) 361 | tcpPacket.setPayloadWithUInt8(4, at: currentOffset + 1) 362 | tcpPacket.setPayloadWithUInt16(MSS!, at: currentOffset + 2) 363 | currentOffset += 4 364 | } 365 | if windowScale != nil { 366 | tcpPacket.setPayloadWithUInt8(3, at: currentOffset) 367 | tcpPacket.setPayloadWithUInt8(3, at: currentOffset + 1) 368 | tcpPacket.setPayloadWithUInt8(windowScale!, at: currentOffset + 2) 369 | currentOffset += 3 370 | } 371 | } 372 | 373 | } 374 | -------------------------------------------------------------------------------- /TunnelPacketKit/TCPTunnel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TCPTunnel.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CocoaLumberjackSwift 11 | 12 | class TCPTunnel: Tunnel { 13 | var state: TCPState = .CLOSED 14 | var ACKNow = false 15 | var RXClosed = false 16 | var TXClosed = false 17 | 18 | var _currentIPPacket: IPPacket! 19 | var currentIPPacket: IPPacket! { 20 | get { 21 | return _currentIPPacket 22 | } 23 | set { 24 | _currentIPPacket = newValue 25 | } 26 | } 27 | var currentTCPPacket: TCPPacket { 28 | get { 29 | return _currentIPPacket.protocolPacket as! TCPPacket 30 | } 31 | } 32 | 33 | // MARK: receive related variables 34 | 35 | /// The next sequence number expected to recieve. Packet with sequence later then this and in the window will be put in the `outOfSequenceIPPacket`. 36 | var nextReceiveSequenceNumber: UInt32 = 0 37 | /// The total size of the read window, this should be a constant. 38 | var readWindowSize: UInt32 = 0xFFFF 39 | /// The size of the available window. 40 | var availableReadWindowSize: UInt32 { 41 | // since the application will always accept unlimited data, there is no need to change this. 42 | return readWindowSize 43 | } 44 | var readWindowScale: UInt8 = Options.localTCPWindowScale 45 | /// This is the literal window size to be set in the next send packet header. 46 | var announceWindowSize: UInt16 { 47 | return UInt16(availableReadWindowSize >> UInt32(readWindowScale)) 48 | } 49 | /// This is the acknowledged number in the last send ACK packet. 50 | var announcedReceivedSequenceNumber: UInt32 = 0 51 | /// If we have anything new to ACK. 52 | var shouldACK: Bool { 53 | return TCPUtils.sequenceLessThan(announcedReceivedSequenceNumber, nextReceiveSequenceNumber) 54 | } 55 | /// This is the largest sequence number we expected, we use a simple (but not standard and wrong) way to compute it. This works fine anyway. 56 | var announcedWindowRightEdge: UInt32 { 57 | return nextReceiveSequenceNumber &+ availableReadWindowSize 58 | } 59 | var receiveFlag = TCPReceiveFlag() 60 | let outOfSequenceIPPacket = BlockManager() 61 | 62 | 63 | // MARK: send related 64 | 65 | /// The sequence number of the next send packet. If the `unsendData` is not empty, then it should be the sequence number of the first packet. 66 | var nextSendSequenceNumber: UInt32 = 0 67 | /// The largest number that has been send to remote. Since sometimes packets are re-trasmitted, thus `nextSendSequenceNumber` is not the right edge of the send data. If there is no re-trasmission, this should always be one less than `nextSendSequenceNumber`. 68 | var largestSendSequenceNumber: UInt32 = 0 69 | /// The highest sequence number acknowledged by remote 70 | var acknowledgedSequenceNumber: UInt32 = 0 71 | /// The size of the announced send window. 72 | var sendWindowSize: UInt32 { 73 | return UInt32(announcedSendWindowSize) << UInt32(sendWindowScale) 74 | } 75 | /// The literal window size announced by remote TCP header in the window field. 76 | var announcedSendWindowSize: UInt16 = 0 77 | /// Send window scale set by the SYN packet 78 | var sendWindowScale: UInt8 = 0 79 | /// Current available send window. 80 | var availableSendWindowSize: UInt32 { 81 | return sendWindowSize > (nextSendSequenceNumber &- acknowledgedSequenceNumber) ? 82 | sendWindowSize - (nextSendSequenceNumber &- acknowledgedSequenceNumber) : 0 83 | } 84 | var sequenceNumberOfLastWindowUpdate: UInt32 = 0 85 | var acknowledgedNumberOfLastWindowUpdate: UInt32 = 0 86 | var MSS: UInt16 = 0 87 | var nextFlag: ControlType = ControlType() 88 | var nextOption: TCPOption? 89 | 90 | var unackedList = SequencePacketManager() 91 | var unsendPackets = [IPPacket]() 92 | var unsendData = DataManager() 93 | 94 | var maxSendPacketDataSize: Int { 95 | return Int(min(UInt32(MSS), availableSendWindowSize)) 96 | } 97 | 98 | override init?(fromIPPacket packet: IPPacket, withManager manager: TunnelManager?) { 99 | super.init(fromIPPacket: packet, withManager: manager) 100 | 101 | currentIPPacket = packet 102 | defer { 103 | currentIPPacket = nil 104 | } 105 | 106 | guard currentTCPPacket.validate() else { 107 | DDLogError("Recieved an invalid TCP packet, checksum validation failed.") 108 | return nil 109 | } 110 | 111 | guard !currentTCPPacket.RST else { 112 | DDLogDebug("Recieved an unknown RST packet, ignored.") 113 | return nil 114 | } 115 | 116 | guard !currentTCPPacket.ACK else { 117 | // TODO: we should send a RST back 118 | DDLogDebug("Recieved an unknown ACK packet, send RST back now.") 119 | return nil 120 | } 121 | 122 | guard currentTCPPacket.SYN else { 123 | DDLogDebug("Recieved an unknown TCP packet with no SYN, ignored.") 124 | return nil 125 | } 126 | 127 | // The incoming packet is not processed now since we have to give a chance to set handler before any event happens. 128 | } 129 | 130 | override func handleIPPacket(packet: IPPacket) { 131 | if !packet.protocolPacket.validate() { 132 | DDLogError("Recieved an invalid TCP packet, checksum validation failed.") 133 | return 134 | } 135 | 136 | currentIPPacket = packet 137 | defer { 138 | currentIPPacket = nil 139 | } 140 | 141 | if state == .TIME_WAIT { 142 | processInTimeWait() 143 | return 144 | } 145 | 146 | processPacket() 147 | 148 | if receiveFlag.contains(.GotRST) { 149 | delegate?.reset(self) 150 | DDLogVerbose("TCP Tunnel \(self) got reseted by RST. Close now.") 151 | doClosed() 152 | return 153 | } 154 | 155 | if receiveFlag.contains(.GotFIN) { 156 | delegate?.remoteClosed(self) 157 | } 158 | 159 | output() 160 | } 161 | 162 | override func close() { 163 | sendFin() 164 | state = .FIN_WAIT_1 165 | } 166 | 167 | private func doClosed() { 168 | delegate?.closed(self) 169 | manager?.tunnelClosed(self) 170 | } 171 | 172 | private func processInTimeWait() { 173 | if currentTCPPacket.RST { 174 | return 175 | } 176 | 177 | if currentTCPPacket.SYN { 178 | if packetInReceiveWindow() { 179 | // TODO: send back an RST 180 | return 181 | } 182 | } else if currentTCPPacket.FIN { 183 | // TODO: restart the timeout 184 | } 185 | 186 | if currentTCPPacket.sequenceLength > 0 { 187 | ACKNow = true 188 | output() 189 | } 190 | } 191 | 192 | // MARK: input related method 193 | private func processPacket() { 194 | // reset receive flag now 195 | receiveFlag = TCPReceiveFlag() 196 | 197 | // handle RST 198 | if currentTCPPacket.RST { 199 | processRST() 200 | return 201 | } 202 | 203 | /* Cope with new connection attempt after remote end crashed */ 204 | if currentTCPPacket.SYN && state != .SYN_RECEIVED { 205 | ACKNow = true 206 | return 207 | } 208 | 209 | switch state { 210 | // the initial state of new TCP tunnel 211 | case .CLOSED: 212 | // the control flag of this packet should already be checked, do not check it now 213 | changeStateTo(.SYN_RECEIVED) 214 | 215 | nextReceiveSequenceNumber = currentTCPPacket.sequenceNumber &+ 1 216 | 217 | // force update window 218 | sequenceNumberOfLastWindowUpdate = currentTCPPacket.sequenceNumber &- 1 219 | announcedSendWindowSize = currentTCPPacket.window 220 | 221 | // TODO: per the standard, number should be generated with an increasing fashion. 222 | nextSendSequenceNumber = arc4random() 223 | acknowledgedSequenceNumber = nextSendSequenceNumber 224 | largestSendSequenceNumber = nextSendSequenceNumber &- 1 225 | 226 | if let mss = currentTCPPacket.option.MSS { 227 | MSS = (Options.MTU - 40) < mss ? Options.MTU - 40 : mss 228 | } else { 229 | switch currentIPPacket.version { 230 | case .IPv4: 231 | MSS = 536 232 | case .IPv6: 233 | MSS = 1220 234 | } 235 | } 236 | 237 | if let ws = currentTCPPacket.option.windowScale { 238 | sendWindowScale = ws 239 | } 240 | 241 | // prepare for reply 242 | enqueueFlag([.SYN, .ACK]) 243 | let option = TCPOption() 244 | option.MSS = Options.localTCPMSS 245 | option.windowScale = Options.localTCPWindowScale 246 | enqueueOption(option) 247 | // we have received the SYN from remote, waiting for the ACK for our SYN. 248 | case .SYN_RECEIVED: 249 | if currentTCPPacket.ACK { 250 | if TCPUtils.sequenceBetween(currentTCPPacket.acknowledgmentNumber, acknowledgedSequenceNumber &+ 1, nextSendSequenceNumber) { 251 | // change state 252 | changeStateTo(.ESTABLISHED) 253 | 254 | // call delegate 255 | delegate?.tunnelEstablished(self) 256 | 257 | // if there is data, we should process it 258 | receive() 259 | 260 | if receiveFlag.contains(.GotFIN) { 261 | ACKNow = true 262 | changeStateTo(.CLOSE_WAIT) 263 | } 264 | } else { 265 | // TODO: send RST 266 | } 267 | } else if currentTCPPacket.SYN && currentTCPPacket.sequenceNumber == nextReceiveSequenceNumber &- 1 { 268 | DDLogError("Received another copy of SYN, we shoule be able to handle this in the future") 269 | } 270 | // we received FIN from remote but we have not send FIN out, we should expect remote send only ACK for data we send out. 271 | case .CLOSE_WAIT: 272 | fallthrough 273 | case .ESTABLISHED: 274 | receive() 275 | if receiveFlag.contains(.GotFIN) { 276 | ACKNow = true 277 | changeStateTo(.CLOSE_WAIT) 278 | } 279 | // we send out FIN and expect remote to send new data or FIN. 280 | case .FIN_WAIT_1: 281 | receive() 282 | if receiveFlag.contains(.GotFIN) { 283 | // we should ACK the FIN now. 284 | ACKNow = true 285 | if currentTCPPacket.ACK && currentTCPPacket.acknowledgmentNumber == nextSendSequenceNumber { 286 | // remote has acknowledged our FIN 287 | changeStateTo(.TIME_WAIT) 288 | } else { 289 | // remote hasn't ACK our FIN, so we wait. 290 | changeStateTo(.CLOSING) 291 | } 292 | } else if currentTCPPacket.ACK && currentTCPPacket.acknowledgmentNumber == nextSendSequenceNumber { 293 | // we will not send anything more and everything we send is acknowledged now, we just wait for new data from remote or FIN. 294 | changeStateTo(.FIN_WAIT_2) 295 | } 296 | // remote has acknowledged the FIN we send, but hasn't send FIN yet. 297 | case .FIN_WAIT_2: 298 | receive() 299 | 300 | if receiveFlag.contains(.GotFIN) { 301 | ACKNow = true 302 | changeStateTo(.TIME_WAIT) 303 | } 304 | // everything is done expect remote hasn't ACK our FIN. 305 | case .CLOSING: 306 | receive() 307 | if currentTCPPacket.ACK && currentTCPPacket.acknowledgmentNumber == nextSendSequenceNumber { 308 | changeStateTo(.TIME_WAIT) 309 | } 310 | // TODO: what does this do? 311 | case .LAST_ACK: 312 | receive() 313 | if currentTCPPacket.controlType.contains(.ACK) && currentTCPPacket.acknowledgmentNumber == nextSendSequenceNumber { 314 | doClosed() 315 | } 316 | break 317 | default: 318 | break 319 | } 320 | } 321 | 322 | func processRST() { 323 | // first determine if RST is acceptable 324 | let acceptable = TCPUtils.sequenceBetween(currentTCPPacket.sequenceNumber, nextReceiveSequenceNumber, announcedWindowRightEdge) 325 | 326 | if acceptable { 327 | receiveFlag.insert(.GotRST) 328 | } else { 329 | DDLogVerbose("Received unacceptable RST packet, ignored.") 330 | } 331 | } 332 | 333 | // this should only be called later than .ESTABLISHED state 334 | func receive() { 335 | if currentTCPPacket.ACK { 336 | updateWindowStatus() 337 | 338 | if TCPUtils.sequenceLessThanOrEqualTo(currentTCPPacket.acknowledgmentNumber, acknowledgedSequenceNumber) { 339 | // we should handle duplicate ACK here if we want to 340 | // but skip that for now 341 | } else if TCPUtils.sequenceBetween(currentTCPPacket.acknowledgmentNumber, acknowledgedSequenceNumber &+ 1, largestSendSequenceNumber &+ 1) { 342 | // Remote ACKed new data. 343 | acknowledgedSequenceNumber = currentTCPPacket.acknowledgmentNumber 344 | updateUnackedList() 345 | // theoraically, it is possible to go through the unsend list to see if any is acknowleged now 346 | // we do not support such case for simplicity 347 | 348 | // TODO: reset re-transmit timer. 349 | 350 | // this is also the place where RTT estimation happens, but that's not need here. 351 | } else { 352 | DDLogWarn("Received out of sequence ACK, expect ACK smaller than \(largestSendSequenceNumber &+ 1), but got \(currentTCPPacket.acknowledgmentNumber). This should have no consequences, but is not expected.") 353 | } 354 | } 355 | 356 | // if there is any data in this packet and the tunnel can process it 357 | if currentTCPPacket.dataAvailable && [TCPState.SYN_RECEIVED, TCPState.ESTABLISHED, TCPState.FIN_WAIT_1, TCPState.FIN_WAIT_2].contains(state) { 358 | processData() 359 | } 360 | } 361 | 362 | private func updateUnackedList() { 363 | unackedList.removeBefore(acknowledgedSequenceNumber) 364 | } 365 | 366 | private func processData() { 367 | // if received data not in window, send ACK again 368 | guard TCPUtils.sequenceBetween(currentTCPPacket.sequenceNumber, nextReceiveSequenceNumber, nextReceiveSequenceNumber &+ readWindowSize &- 1) else { 369 | ACKNow = true 370 | return 371 | } 372 | 373 | outOfSequenceIPPacket.addPacket(currentIPPacket) 374 | if let (data, FIN) = outOfSequenceIPPacket.getData(nextReceiveSequenceNumber) { 375 | delegate?.receivedData(data, from: self) 376 | if FIN { 377 | receiveFlag.insert(.GotFIN) 378 | } 379 | } 380 | } 381 | 382 | private func updateWindowStatus() { 383 | // if we received new data 384 | if TCPUtils.sequenceLessThan(sequenceNumberOfLastWindowUpdate, currentTCPPacket.sequenceNumber) || 385 | // or ACKed data received 386 | (sequenceNumberOfLastWindowUpdate == currentTCPPacket.sequenceNumber && TCPUtils.sequenceLessThan(acknowledgedNumberOfLastWindowUpdate, currentTCPPacket.acknowledgmentNumber)) || 387 | // or nothing is new but window became larger 388 | (acknowledgedNumberOfLastWindowUpdate == currentTCPPacket.acknowledgmentNumber && currentTCPPacket.window > announcedSendWindowSize) { 389 | // set up new send window size 390 | announcedSendWindowSize = currentTCPPacket.window 391 | sequenceNumberOfLastWindowUpdate = currentTCPPacket.sequenceNumber 392 | acknowledgedNumberOfLastWindowUpdate = currentTCPPacket.acknowledgmentNumber 393 | if announcedSendWindowSize == 0 { 394 | DDLogError("The send window is set to 0, this is something not expected but we should be able to handle in the future.") 395 | } 396 | } 397 | } 398 | 399 | func changeStateTo(state: TCPState) { 400 | DDLogDebug("State of tunnel \(self) changes from \(self.state) to \(state)") 401 | 402 | if state == .TIME_WAIT && self.state != .TIME_WAIT { 403 | delegate?.closed(self) 404 | } 405 | 406 | self.state = state 407 | } 408 | 409 | // MARK: Packet creation 410 | func createRawPacket() -> IPPacket { 411 | let packet = IPPacket() 412 | packet.sourceAddress = remoteIP 413 | packet.sourcePort = remotePort 414 | packet.destinationAddress = localIP 415 | packet.destinationPort = localPort 416 | let tcpPacket = TCPPacket() 417 | tcpPacket.sequenceNumber = nextSendSequenceNumber 418 | tcpPacket.window = announceWindowSize 419 | packet.protocolPacket = tcpPacket 420 | return packet 421 | } 422 | 423 | func exhaustFlagToPacket(packet: IPPacket) -> IPPacket { 424 | let tcpPacket = packet.protocolPacket as! TCPPacket 425 | 426 | tcpPacket.controlType.unionInPlace(nextFlag) 427 | nextFlag = ControlType() 428 | 429 | tcpPacket.option = nextOption 430 | nextOption = nil 431 | return packet 432 | } 433 | 434 | func createACKPacket() -> IPPacket { 435 | let packet = createRawPacket() 436 | let tcpPacket = packet.protocolPacket as! TCPPacket 437 | 438 | tcpPacket.acknowledgmentNumber = nextReceiveSequenceNumber 439 | tcpPacket.ACK = true 440 | return packet 441 | } 442 | 443 | func sendRSTforCurrentPacket() { 444 | // TODO: create right RST packet 445 | // let packet = createRawPacket() 446 | // let tcpPacket = packet.tcpPacket! 447 | // tcpPacket.controlType = [.RST] 448 | // sendPacket(packet) 449 | } 450 | 451 | // MARK: output related 452 | 453 | override func sendData(data: NSData) { 454 | guard !TXClosed else { 455 | DDLogError("Try to send data after TX closed.") 456 | return 457 | } 458 | 459 | unsendData.append(data) 460 | output() 461 | } 462 | 463 | func sendFin() { 464 | // append FIN to the last unsend packet if there is any 465 | if let lastPacket = unsendPackets.last { 466 | lastPacket.tcpPacket!.FIN = true 467 | return 468 | } 469 | enqueueFlag(.FIN) 470 | } 471 | 472 | func output(fromTimer: Bool = false) { 473 | var sendNow = false 474 | if !nextFlag.isDisjointWith([.ACK, .SYN, .FIN]) || ACKNow { 475 | sendNow = true 476 | } 477 | 478 | if unsendPackets.count > 0 { 479 | sendNow = true 480 | } 481 | 482 | if sendNow { 483 | outputPackets() 484 | } 485 | 486 | ACKNow = false 487 | } 488 | 489 | private func outputPackets() { 490 | var packets = [IPPacket]() 491 | // send at least one packet. 492 | repeat { 493 | let packet = createACKPacket() 494 | exhaustFlagToPacket(packet) 495 | packet.tcpPacket!.lengthOfDataToSend = min(packet.maxDataLength(), unsendData.length) 496 | packet.buildPacket() 497 | unsendData.fillTo(packet.datagram as! NSMutableData, offset: packet.tcpPacket!.dataOffsetInDatagram, length: packet.tcpPacket!.lengthOfDataToSend) 498 | packet.setChecksum() 499 | packets.append(packet) 500 | } while unsendData.length > 0 && sendWindowSize > 0 501 | 502 | sendPackets(packets) 503 | for packet in packets { 504 | if packet.tcpPacket!.sequenceLength > 0 { 505 | unackedList.insertPacket(packet) 506 | } 507 | } 508 | } 509 | 510 | func enqueueFlag(flag: ControlType) { 511 | nextFlag.intersectInPlace(flag) 512 | } 513 | 514 | func dequeueFlag(flag: ControlType) { 515 | nextFlag.subtractInPlace(flag) 516 | } 517 | 518 | func enqueueOption(option: TCPOption) { 519 | nextOption = option 520 | } 521 | 522 | func packetInReceiveWindow() -> Bool { 523 | return TCPUtils.sequenceBetween(currentTCPPacket.sequenceNumber, nextReceiveSequenceNumber, nextReceiveSequenceNumber &+ readWindowSize &- 1) 524 | } 525 | 526 | override func fastTimerHandler() { 527 | super.fastTimerHandler() 528 | if shouldACK { 529 | ACKNow = true 530 | output() 531 | } 532 | 533 | if state == .TIME_WAIT { 534 | doClosed() 535 | } 536 | } 537 | } 538 | -------------------------------------------------------------------------------- /TunnelPacketKit/TCPUtils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TCPUtils.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/2/6. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct TCPUtils { 12 | static func sequenceLessThan(a: UInt32, _ b: UInt32) -> Bool { 13 | return Int32(bitPattern: a &- b) < 0 14 | } 15 | 16 | static func sequenceLessThanOrEqualTo(a: UInt32, _ b: UInt32) -> Bool { 17 | return Int32(bitPattern: a &- b) <= 0 18 | } 19 | 20 | static func sequenceGreaterThan(a: UInt32, _ b: UInt32) -> Bool { 21 | return Int32(bitPattern: a &- b) > 0 22 | } 23 | 24 | static func sequenceGreaterThanOrEqualTo(a: UInt32, _ b: UInt32) -> Bool { 25 | return Int32(bitPattern: a &- b) >= 0 26 | } 27 | 28 | /** 29 | Compute if `a` is between `b` and `c` (included). 30 | 31 | - parameter a: sequence number 32 | - parameter b: sequence number 33 | - parameter c: sequence number 34 | 35 | - returns: if `a` between `b` and `c`. 36 | */ 37 | static func sequenceBetween(a: UInt32, _ b: UInt32, _ c: UInt32) -> Bool { 38 | return sequenceGreaterThanOrEqualTo(a, b) && sequenceLessThanOrEqualTo(a, c) 39 | } 40 | } -------------------------------------------------------------------------------- /TunnelPacketKit/Tunnel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Tunnel.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CocoaLumberjackSwift 11 | 12 | protocol TunnelDelegateProtocol: class { 13 | func tunnelEstablished(_: Tunnel) 14 | func receivedData(_: NSData, from: Tunnel) 15 | func remoteClosed(_: Tunnel) 16 | func closed(_: Tunnel) 17 | func reset(_: Tunnel) 18 | } 19 | 20 | class Tunnel { 21 | let type: PacketType 22 | let localIP: IPAddress 23 | let localPort: UInt16 24 | let remoteIP: IPAddress 25 | let remotePort: UInt16 26 | weak var manager: TunnelManager? 27 | 28 | weak var delegate: TunnelDelegateProtocol? 29 | 30 | init?(fromIPPacket packet: IPPacket, withManager manager: TunnelManager? = nil) { 31 | type = packet.packetType 32 | localIP = packet.sourceAddress 33 | localPort = packet.sourcePort 34 | remoteIP = packet.destinationAddress 35 | remotePort = packet.destinationPort 36 | self.manager = manager 37 | } 38 | 39 | class func createFromPacket(packet: IPPacket, withManager manager: TunnelManager) -> Tunnel? { 40 | switch packet.packetType { 41 | case .TCP: 42 | return TCPTunnel(fromIPPacket: packet, withManager: manager) 43 | default: 44 | DDLogError("Can't create tunnel for packet type \(packet.packetType) yet!") 45 | return Tunnel(fromIPPacket: packet) 46 | } 47 | } 48 | 49 | func match(packet: IPPacket) -> Bool { 50 | if type == packet.packetType && 51 | localIP.equalTo(packet.sourceAddress) && 52 | localPort == packet.sourcePort && 53 | remoteIP.equalTo(packet.destinationAddress) && 54 | remotePort == packet.destinationPort { 55 | return true 56 | } else { 57 | return false 58 | } 59 | } 60 | 61 | /** 62 | This should be called by `TunnelManager`. 63 | - warning: Make sure this is called in the process queue. 64 | 65 | - parameter packet: the packet to be processed. 66 | */ 67 | func handleIPPacket(packet: IPPacket) {} 68 | 69 | /** 70 | Close current tunnel. 71 | */ 72 | func close() { 73 | manager?.tunnelClosed(self) 74 | } 75 | 76 | func slowTimerHandler() {} 77 | 78 | func fastTimerHandler() {} 79 | 80 | internal func sendPackets(packet: [IPPacket]) { 81 | manager?.sendPackets?(packet) 82 | } 83 | 84 | func sendData(data: NSData) {} 85 | } 86 | -------------------------------------------------------------------------------- /TunnelPacketKit/TunnelManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TunnelManager.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CocoaLumberjackSwift 11 | 12 | class TunnelManager { 13 | var tunnels = [Tunnel]() 14 | var newTunnelHandler: (Tunnel -> ())? 15 | var sendPackets: ([IPPacket] -> ())? 16 | 17 | func receivedPacket(rawData: NSData, version: NSNumber) { 18 | let packet = IPPacket(rawData) 19 | guard packet.parsePacket() else { 20 | DDLogError("Failed to parse recieved packet.") 21 | return 22 | } 23 | 24 | guard packet.version.rawValue == version.unsignedCharValue else { 25 | DDLogError("Accepted packet with unmatched IP version, system reported \(version) while packet version is \(packet.version)") 26 | return 27 | } 28 | 29 | // TODO: check for broadcast/multicast address? 30 | 31 | guard let tunnel = findOrCreateTunnel(packet) else { 32 | return 33 | } 34 | tunnel.handleIPPacket(packet) 35 | } 36 | 37 | func findTunnel(packet: IPPacket) -> Tunnel? { 38 | for tunnel in tunnels { 39 | if tunnel.match(packet) { 40 | return tunnel 41 | } 42 | } 43 | return nil 44 | } 45 | 46 | func findOrCreateTunnel(packet: IPPacket) -> Tunnel? { 47 | if let tunnel = findTunnel(packet) { 48 | return tunnel 49 | } else { 50 | if let tunnel = Tunnel.createFromPacket(packet, withManager: self) { 51 | DDLogVerbose("Created new tunnel: \(tunnel)") 52 | newTunnelHandler?(tunnel) 53 | tunnels.append(tunnel) 54 | return tunnel 55 | } else { 56 | DDLogError("Eh, received some packet out of nowhere.") 57 | // TODO: send RST packet 58 | return nil 59 | } 60 | } 61 | } 62 | 63 | func tunnelClosed(tunnel: Tunnel) { 64 | guard let index = tunnels.indexOf({$0 === tunnel}) else { 65 | DDLogError("Got closed signal from an unknown Tunnel.") 66 | return 67 | } 68 | tunnels.removeAtIndex(index) 69 | DDLogDebug("Tunnel \(tunnel) closed, removed from tunnel manager.") 70 | } 71 | 72 | func slowTimerHandler() { 73 | for tunnel in tunnels { 74 | tunnel.slowTimerHandler() 75 | } 76 | } 77 | 78 | func fastTimerHandler() { 79 | for tunnel in tunnels { 80 | tunnel.fastTimerHandler() 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /TunnelPacketKit/TunnelPacketKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // TunnelPacketKit.h 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/16. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for TunnelPacketKit. 12 | FOUNDATION_EXPORT double TunnelPacketKitVersionNumber; 13 | 14 | //! Project version string for TunnelPacketKit. 15 | FOUNDATION_EXPORT const unsigned char TunnelPacketKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /TunnelPacketKit/enums.swift: -------------------------------------------------------------------------------- 1 | // 2 | // enums.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/17. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | enum IPVersion: UInt8 { 12 | case IPv4 = 4, IPv6 = 6 13 | } 14 | 15 | enum PacketType: UInt8 { 16 | case TCP = 6, UDP = 17, ICMP = 1 17 | } 18 | 19 | struct ControlType: OptionSetType { 20 | let rawValue: UInt8 21 | 22 | static let URG = ControlType(rawValue: 1 << 5) 23 | static let ACK = ControlType(rawValue: 1 << 4) 24 | static let PSH = ControlType(rawValue: 1 << 3) 25 | static let RST = ControlType(rawValue: 1 << 2) 26 | static let SYN = ControlType(rawValue: 1 << 1) 27 | static let FIN = ControlType(rawValue: 1) 28 | } 29 | 30 | enum TCPState { 31 | case CLOSED, // the initial state for new TCP tunnel 32 | LISTEN, // never used 33 | SYN_SENT, // never used 34 | SYN_RECEIVED, // received SYN from client, should send SYN and ACK now 35 | ESTABLISHED, // sending and recieving data 36 | FIN_WAIT_1, // send FIN packet 37 | FIN_WAIT_2, // received the ACK packet for FIN packet 38 | CLOSE_WAIT, // received FIN packet in ESTABLISHED state and send ACK for it 39 | CLOSING, // never used 40 | LAST_ACK, // send FIN for CLOSE_WAIT, waiting for ACK reply 41 | TIME_WAIT // not necessary since this is not a full ip stack. 42 | } 43 | 44 | struct TCPTunnelFlag: OptionSetType { 45 | let rawValue: UInt8 46 | 47 | static let ACKNow = TCPTunnelFlag(rawValue: 1) // send ACK as soon as possible 48 | static let ACKDelayed = TCPTunnelFlag(rawValue: 1 << 1) // send ACK with data or in next write time interval 49 | static let StopReceive = TCPTunnelFlag(rawValue: 1 << 2) // tunnel is closed locally 50 | static let StopSend = TCPTunnelFlag(rawValue: 1 << 3) // FIN is enqueued 51 | } 52 | 53 | struct TCPReceiveFlag: OptionSetType { 54 | let rawValue: UInt8 55 | 56 | static let GotRST = TCPReceiveFlag(rawValue: 1) // got RST 57 | static let Closed = TCPReceiveFlag(rawValue: 1 << 1) // got ACK for FIN 58 | static let GotFIN = TCPReceiveFlag(rawValue: 1 << 2) // got FIN 59 | } 60 | -------------------------------------------------------------------------------- /TunnelPacketKitTests/IPPacketSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketSpec.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/20. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Nimble 11 | import Quick 12 | @testable import TunnelPacketKit 13 | 14 | class IPPacketSpec: QuickSpec { 15 | override func spec() { 16 | var packetData: NSData! 17 | var packet: IPPacket! 18 | beforeEach { 19 | let bundle = NSBundle(forClass: self.dynamicType) 20 | let file = bundle.pathForResource("Packet_1", ofType: "bin")! 21 | let data = NSData(contentsOfFile: file)! 22 | packetData = data.subdataWithRange(NSMakeRange(14, data.length - 14)) 23 | packet = IPPacket(packetData) 24 | } 25 | 26 | describe("The IPPacket") { 27 | it("Can parse the data") { 28 | expect(packet.parsePacket()) == true 29 | expect(packet.version) == IPVersion.IPv4 30 | expect(packet.headerLength) == 20 31 | expect(packet.totalLength) == 713 32 | expect(packet.TTL) == 64 33 | expect(packet.packetType) == PacketType.TCP 34 | expect(packet.sourceAddress.equalTo(IPv4Address(192, 168, 1, 230))) == true 35 | expect(packet.destinationAddress.equalTo(IPv4Address(17, 172, 233, 92))) == true 36 | expect(packet.tcpPacket).toNot(beNil()) 37 | } 38 | 39 | it("Can validate packet") { 40 | packet.parsePacket() 41 | expect(packet.validate()) == true 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /TunnelPacketKitTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /TunnelPacketKitTests/Packet_1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zhuhaow/TunnelPacketKit/c4c3a49afae0e04bd90133039b4cae2f65ae97b4/TunnelPacketKitTests/Packet_1.bin -------------------------------------------------------------------------------- /TunnelPacketKitTests/TCPPacketSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TCPPacketSpec.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/28. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Nimble 11 | import Quick 12 | @testable import TunnelPacketKit 13 | 14 | class TCPPacketSpec: QuickSpec { 15 | override func spec() { 16 | var packetData: NSData! 17 | var packet: TCPPacket! 18 | beforeEach { 19 | let bundle = NSBundle(forClass: self.dynamicType) 20 | let file = bundle.pathForResource("Packet_1", ofType: "bin")! 21 | let data = NSData(contentsOfFile: file)! 22 | packetData = data.subdataWithRange(NSMakeRange(14, data.length - 14)) 23 | let ippacket = IPPacket(packetData) 24 | ippacket.parsePacket() 25 | packet = ippacket.tcpPacket! 26 | } 27 | 28 | describe("The TCPPacket") { 29 | it ("can parse the datagram") { 30 | expect(packet.validate()) == true 31 | expect(packet.sourcePort) == 59113 32 | expect(packet.destinationPort) == 5223 33 | expect(packet.sequenceNumber) == 0x0E43196E 34 | expect(packet.acknowledgmentNumber) == 0xFBF65E28 35 | expect(packet.headerLength) == 32 36 | expect(packet.PSH) == true 37 | expect(packet.ACK) == true 38 | expect(packet.RST) == false 39 | expect(packet.FIN) == false 40 | expect(packet.URG) == false 41 | expect(packet.SYN) == false 42 | expect(packet.window) == 4096 43 | expect(packet.dataLength) == 661 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /TunnelPacketKitTests/Utils/ChecksumSpec.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PacketSpec.swift 3 | // TunnelPacketKit 4 | // 5 | // Created by Zhuhao Wang on 16/1/20. 6 | // Copyright © 2016年 Zhuhao Wang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Nimble 11 | import Quick 12 | @testable import TunnelPacketKit 13 | 14 | class ChecksumSpec: QuickSpec { 15 | override func spec() { 16 | var bytes: [UInt16] = [0x4500, 0x0073, 0x0000, 0x4000, 0x4011, 0xb861, 0xc0a8, 0x0001, 17 | 0xc0a8, 0x00c7] 18 | var validData: NSData! 19 | 20 | beforeEach { 21 | // let bundle = NSBundle(forClass: self.dynamicType) 22 | // let file = bundle.pathForResource("Packet_1", ofType: "bin")! 23 | // let data = NSData(contentsOfFile: file)! 24 | // packetData = data.subdataWithRange(NSMakeRange(14, data.length - 14)) 25 | 26 | validData = NSData(bytesNoCopy: &bytes, length: 20, freeWhenDone: false) 27 | } 28 | 29 | describe("The checksum helper") { 30 | it("Can compute packet checksum") { 31 | NSLog("\(validData)") 32 | expect(Checksum.computeChecksumUnfold(validData)) == 196605 33 | expect(Checksum.computeChecksum(validData)) == 0 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /TunnelPacketKitTests/dump: -------------------------------------------------------------------------------- 1 | 0000000 6c b0 ce 11 da da b8 e8 56 2f b0 48 08 00 45 00 2 | 0000010 02 c9 b5 f8 40 00 40 06 c4 9f c0 a8 01 e6 11 ac 3 | 0000020 e9 5c e6 e9 14 67 0e 43 19 6e fb f6 5e 28 80 18 4 | 0000030 10 00 e1 18 00 00 01 01 08 0a 1a cf 1a 54 df 77 5 | 0000040 fb 36 17 03 03 02 90 ae ac e8 5c a5 ca 60 91 59 6 | 0000050 98 fc 08 b0 56 77 d0 9f 91 f2 f2 02 49 0c 91 5c 7 | 0000060 9c ce 5e 94 ab ec 91 09 51 c5 c0 d9 51 e1 84 4f 8 | 0000070 c7 e2 6d 7f 9e 37 58 37 c1 36 b9 53 eb c5 f0 9a 9 | 0000080 5d 38 a6 77 a0 e3 e3 59 42 0b 99 a6 c2 87 85 26 10 | 0000090 0f ed ae 5d c6 a0 b8 9c 97 ce 10 92 66 06 2c 78 11 | 00000a0 96 41 52 cb f0 12 25 94 58 e7 78 b5 e5 93 a1 53 12 | 00000b0 34 65 e6 d3 ea 58 c4 e5 0e be ac 5a 33 f4 e4 10 13 | 00000c0 bc e7 14 e9 92 5a 23 1f 33 59 14 5b 23 c1 cb fc 14 | 00000d0 17 eb b2 5c fe 2e 22 2e 77 93 14 2a 88 63 c8 2b 15 | 00000e0 8e 81 c9 45 b3 b5 31 8e 00 70 a3 29 6e 6b 29 23 16 | 00000f0 7b db 4a 1e 46 37 d2 4a 5d 2d f9 d5 2c d8 4e 41 17 | 0000100 3e ba 89 2f 67 64 a8 fb 4b d2 29 3e 46 5d 0a 52 18 | 0000110 0a 06 a5 6b dd 03 e9 a1 0c 0a f2 cb 26 6f 13 0f 19 | 0000120 f3 51 70 48 8f a1 29 76 f5 ce 96 bd a1 42 95 b5 20 | 0000130 cd f5 54 f3 29 4b 01 29 9f 31 36 db e5 de 8f 92 21 | 0000140 ce df b7 12 d4 67 2f 95 b3 c9 ad b9 36 04 b3 ad 22 | 0000150 96 b9 08 1c 88 08 c5 1e 60 f6 b1 7b 3e 82 9c a2 23 | 0000160 28 fe 0e b9 3f ef 52 ac a0 94 f3 d1 8d 0c 09 0b 24 | 0000170 91 0d 6c 31 5e b2 82 76 9c 24 fe c6 a7 34 de 91 25 | 0000180 7c 73 e9 e8 41 d2 c3 9c 90 29 31 a1 14 87 06 0b 26 | 0000190 4b ab 34 d3 99 a2 ca 8d eb 2a d9 13 d0 dc 42 7e 27 | 00001a0 d9 3b e8 e7 ef a9 4d 9d 1d fd d0 a9 53 00 9c e4 28 | 00001b0 fe a9 f4 62 17 72 c1 85 60 33 0d 10 0f b2 c5 fc 29 | 00001c0 4d c3 65 25 cf 38 44 41 92 f2 d2 b5 40 a7 ad 79 30 | 00001d0 01 5a 4a 02 6e fb c6 97 f8 5e 56 d2 81 36 b4 9a 31 | 00001e0 9e e9 01 4e 40 ab 3b 16 e7 73 5d 86 c0 ec d0 c6 32 | 00001f0 85 5f 4b 80 2c 78 fb 22 92 5d 5a d7 10 a8 30 20 33 | 0000200 f0 70 52 fd 8e 82 a3 51 58 70 49 07 4d 2a 04 10 34 | 0000210 c4 56 94 3a 1c 0a 43 af fd 31 4c 12 9c e6 32 9c 35 | 0000220 49 b3 df 7f 9d 68 1a 5d c6 c4 f6 20 15 c4 1a da 36 | 0000230 69 1a 87 34 19 1c 27 31 b5 b9 39 4f b8 7b 2c 20 37 | 0000240 1a 3b aa d7 dd bf 94 8f b6 8f de bf a5 64 5e 75 38 | 0000250 7b 96 5c 04 92 b0 a0 1a 87 14 42 17 98 ed ec 07 39 | 0000260 6b ed fd 2b af 95 6b 1e ed 92 84 d0 35 a3 38 2b 40 | 0000270 84 47 00 fe cd fb e4 ac 00 08 74 88 8c cd a8 f7 41 | 0000280 cc 3c bb df b0 64 38 4e b4 02 fd a5 65 8c 38 a8 42 | 0000290 a1 57 e0 a7 24 ad 51 e5 c0 84 7a f3 e1 db 63 03 43 | 00002a0 85 42 a8 1e a9 52 3f 72 d8 82 39 f4 5b de ae 93 44 | 00002b0 87 87 43 d5 d1 83 8f 55 fa 80 37 1b 26 48 ec 44 45 | 00002c0 bf b9 ce f5 0c aa 30 83 9f 2f f5 c3 90 2d 89 46 46 | 00002d0 8f d9 97 c2 35 b3 d4 47 | 00002d7 48 | --------------------------------------------------------------------------------