diff --git a/OpenVPN Adapter Tests/CustomFlow.swift b/OpenVPN Adapter Tests/CustomFlow.swift index dbd423f..23e0f58 100644 --- a/OpenVPN Adapter Tests/CustomFlow.swift +++ b/OpenVPN Adapter Tests/CustomFlow.swift @@ -6,22 +6,15 @@ // import NetworkExtension +@testable import OpenVPNAdapter -class CustomFlow: NEPacketTunnelFlow { - - override func readPackets(completionHandler: @escaping ([Data], [NSNumber]) -> Void) { +class CustomFlow: NSObject, OpenVPNAdapterPacketFlow { + + func readPackets(completionHandler: @escaping ([Data], [NSNumber]) -> Void) { } - override func writePackets(_ packets: [Data], withProtocols protocols: [NSNumber]) -> Bool { - return true - } - - override func readPacketObjects(completionHandler: @escaping ([NEPacket]) -> Void) { - - } - - override func writePacketObjects(_ packets: [NEPacket]) -> Bool { + func writePackets(_ packets: [Data], withProtocols protocols: [NSNumber]) -> Bool { return true } diff --git a/OpenVPN Adapter Tests/OpenVPNAdapterTests.swift b/OpenVPN Adapter Tests/OpenVPNAdapterTests.swift index 0642e45..40a83f6 100644 --- a/OpenVPN Adapter Tests/OpenVPNAdapterTests.swift +++ b/OpenVPN Adapter Tests/OpenVPNAdapterTests.swift @@ -135,7 +135,7 @@ class OpenVPNAdapterTests: XCTestCase { extension OpenVPNAdapterTests: OpenVPNAdapterDelegate { - func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings, completionHandler: @escaping (NEPacketTunnelFlow?) -> Void) { + func openVPNAdapter(_ openVPNAdapter: OpenVPNAdapter, configureTunnelWithNetworkSettings networkSettings: NEPacketTunnelNetworkSettings, completionHandler: @escaping (OpenVPNAdapterPacketFlow?) -> Void) { completionHandler(customFlow) } diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index 2ff6418..c8f9d41 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -124,12 +124,22 @@ C9C1E4111FA47117006ECA7D /* remote_vpn_server.ovpn in Resources */ = {isa = PBXBuildFile; fileRef = C9C1E40F1FA47117006ECA7D /* remote_vpn_server.ovpn */; }; C9C1E4141FA475B7006ECA7D /* CustomFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9C1E4131FA475B7006ECA7D /* CustomFlow.swift */; }; C9C1E4151FA475B7006ECA7D /* CustomFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9C1E4131FA475B7006ECA7D /* CustomFlow.swift */; }; + C9C2B2B7200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h in Headers */ = {isa = PBXBuildFile; fileRef = C9C2B2B6200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C9C2B2B8200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h in Headers */ = {isa = PBXBuildFile; fileRef = C9C2B2B6200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h */; settings = {ATTRIBUTES = (Public, ); }; }; + C9C2B2BB200CC42A00CA0FF3 /* OpenVPNPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = C9C2B2B9200CC42A00CA0FF3 /* OpenVPNPacket.h */; }; + C9C2B2BC200CC42A00CA0FF3 /* OpenVPNPacket.h in Headers */ = {isa = PBXBuildFile; fileRef = C9C2B2B9200CC42A00CA0FF3 /* OpenVPNPacket.h */; }; + C9C2B2BD200CC42A00CA0FF3 /* OpenVPNPacket.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9C2B2BA200CC42A00CA0FF3 /* OpenVPNPacket.mm */; }; + C9C2B2BE200CC42A00CA0FF3 /* OpenVPNPacket.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9C2B2BA200CC42A00CA0FF3 /* OpenVPNPacket.mm */; }; C9CA4DD31F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */ = {isa = PBXBuildFile; fileRef = C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9CA4DD41F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */ = {isa = PBXBuildFile; fileRef = C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */; settings = {ATTRIBUTES = (Public, ); }; }; C9CA4DD51F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */; }; C9CA4DD61F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */; }; C9CA4DE11F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; }; C9CA4DE21F603A5300C4F184 /* OpenVPNCertificateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */; }; + C9CDFDDB200781AF00323B73 /* OpenVPNClient.h in Headers */ = {isa = PBXBuildFile; fileRef = C9CDFDD9200781AF00323B73 /* OpenVPNClient.h */; }; + C9CDFDDC200781AF00323B73 /* OpenVPNClient.h in Headers */ = {isa = PBXBuildFile; fileRef = C9CDFDD9200781AF00323B73 /* OpenVPNClient.h */; }; + C9CDFDDD200781AF00323B73 /* OpenVPNClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9CDFDDA200781AF00323B73 /* OpenVPNClient.mm */; }; + C9CDFDDE200781AF00323B73 /* OpenVPNClient.mm in Sources */ = {isa = PBXBuildFile; fileRef = C9CDFDDA200781AF00323B73 /* OpenVPNClient.mm */; }; C9D2ABDE1EA20F99007EDF9D /* ovpncli.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9FD92191E9A667600374FC4 /* ovpncli.cpp */; }; C9D2ABE01EA20F99007EDF9D /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C912BB241E7C3339002B9414 /* NetworkExtension.framework */; }; C9D2ABE11EA20F99007EDF9D /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C90BAD301E73FF6C00DEFB32 /* SystemConfiguration.framework */; }; @@ -140,10 +150,10 @@ C9D2ABF61EA212A3007EDF9D /* OpenVPNAdapterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB47901E71821A00F3F98C /* OpenVPNAdapterTests.swift */; }; C9D2ABF71EA212A3007EDF9D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9BB47A11E7183DB00F3F98C /* Bundle.swift */; }; C9D2AC051EA214EA007EDF9D /* OpenVPNAdapter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9D2ABF01EA20F99007EDF9D /* OpenVPNAdapter.framework */; }; - C9E4401D1F6086A1001D7C41 /* NSError+Message.h in Headers */ = {isa = PBXBuildFile; fileRef = C9E4401B1F6086A1001D7C41 /* NSError+Message.h */; }; - C9E4401E1F6086A1001D7C41 /* NSError+Message.h in Headers */ = {isa = PBXBuildFile; fileRef = C9E4401B1F6086A1001D7C41 /* NSError+Message.h */; }; - C9E4401F1F6086A1001D7C41 /* NSError+Message.m in Sources */ = {isa = PBXBuildFile; fileRef = C9E4401C1F6086A1001D7C41 /* NSError+Message.m */; }; - C9E440201F6086A1001D7C41 /* NSError+Message.m in Sources */ = {isa = PBXBuildFile; fileRef = C9E4401C1F6086A1001D7C41 /* NSError+Message.m */; }; + C9E350C1200F6EC0000820D9 /* NSError+OpenVPNError.h in Headers */ = {isa = PBXBuildFile; fileRef = C9E350BF200F6EC0000820D9 /* NSError+OpenVPNError.h */; }; + C9E350C2200F6EC0000820D9 /* NSError+OpenVPNError.h in Headers */ = {isa = PBXBuildFile; fileRef = C9E350BF200F6EC0000820D9 /* NSError+OpenVPNError.h */; }; + C9E350C3200F6EC0000820D9 /* NSError+OpenVPNError.m in Sources */ = {isa = PBXBuildFile; fileRef = C9E350C0200F6EC0000820D9 /* NSError+OpenVPNError.m */; }; + C9E350C4200F6EC0000820D9 /* NSError+OpenVPNError.m in Sources */ = {isa = PBXBuildFile; fileRef = C9E350C0200F6EC0000820D9 /* NSError+OpenVPNError.m */; }; C9FD921A1E9A667600374FC4 /* ovpncli.hpp in Headers */ = {isa = PBXBuildFile; fileRef = C9FD92181E9A667600374FC4 /* ovpncli.hpp */; }; C9FD921B1E9A667600374FC4 /* ovpncli.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C9FD92191E9A667600374FC4 /* ovpncli.cpp */; }; /* End PBXBuildFile section */ @@ -237,13 +247,18 @@ C9BCE25C1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "OpenVPNSessionToken+Internal.h"; sourceTree = ""; }; C9C1E40F1FA47117006ECA7D /* remote_vpn_server.ovpn */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = remote_vpn_server.ovpn; sourceTree = ""; }; C9C1E4131FA475B7006ECA7D /* CustomFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomFlow.swift; sourceTree = ""; }; + C9C2B2B6200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenVPNAdapterPacketFlow.h; sourceTree = ""; }; + C9C2B2B9200CC42A00CA0FF3 /* OpenVPNPacket.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenVPNPacket.h; sourceTree = ""; }; + C9C2B2BA200CC42A00CA0FF3 /* OpenVPNPacket.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNPacket.mm; sourceTree = ""; }; C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OpenVPNCertificate.h; sourceTree = ""; }; C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OpenVPNCertificate.m; sourceTree = ""; }; C9CA4DE01F603A5300C4F184 /* OpenVPNCertificateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenVPNCertificateTests.swift; sourceTree = ""; }; + C9CDFDD9200781AF00323B73 /* OpenVPNClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OpenVPNClient.h; sourceTree = ""; }; + C9CDFDDA200781AF00323B73 /* OpenVPNClient.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OpenVPNClient.mm; sourceTree = ""; }; C9D2ABF01EA20F99007EDF9D /* OpenVPNAdapter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OpenVPNAdapter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; C9D2ABFF1EA212A3007EDF9D /* OpenVPNAdapterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OpenVPNAdapterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - C9E4401B1F6086A1001D7C41 /* NSError+Message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSError+Message.h"; sourceTree = ""; }; - C9E4401C1F6086A1001D7C41 /* NSError+Message.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSError+Message.m"; sourceTree = ""; }; + C9E350BF200F6EC0000820D9 /* NSError+OpenVPNError.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSError+OpenVPNError.h"; sourceTree = ""; }; + C9E350C0200F6EC0000820D9 /* NSError+OpenVPNError.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSError+OpenVPNError.m"; sourceTree = ""; }; C9FD92181E9A667600374FC4 /* ovpncli.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ovpncli.hpp; path = Vendors/openvpn/client/ovpncli.hpp; sourceTree = ""; }; C9FD92191E9A667600374FC4 /* ovpncli.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ovpncli.cpp; path = Vendors/openvpn/client/ovpncli.cpp; sourceTree = ""; }; /* End PBXFileReference section */ @@ -334,6 +349,11 @@ C9235AC41EB24F0100C7D303 /* Configuration */ = { isa = PBXGroup; children = ( + C9657A5D1EB0D60700EFF210 /* OpenVPNTransportProtocol.h */, + C9657A601EB0D64E00EFF210 /* OpenVPNIPv6Preference.h */, + C9657A631EB0D6AD00EFF210 /* OpenVPNCompressionMode.h */, + C9657A661EB0D73200EFF210 /* OpenVPNMinTLSVersion.h */, + C9657A691EB0D75700EFF210 /* OpenVPNTLSCertProfile.h */, C98467A41EAA5B7700272A9A /* OpenVPNConfiguration.h */, C98467AA1EAA5BB500272A9A /* OpenVPNConfiguration+Internal.h */, C98467A51EAA5B7700272A9A /* OpenVPNConfiguration.mm */, @@ -369,26 +389,10 @@ name = "Stats and Info"; sourceTree = ""; }; - C9235AC61EB24F2A00C7D303 /* Types and Constants */ = { - isa = PBXGroup; - children = ( - C9BB476F1E7171A100F3F98C /* OpenVPNError.h */, - C93A4F611EE18009004DC561 /* OpenVPNError.m */, - C9BB47701E7171A100F3F98C /* OpenVPNAdapterEvent.h */, - C9657A5D1EB0D60700EFF210 /* OpenVPNTransportProtocol.h */, - C9657A601EB0D64E00EFF210 /* OpenVPNIPv6Preference.h */, - C9657A631EB0D6AD00EFF210 /* OpenVPNCompressionMode.h */, - C9657A661EB0D73200EFF210 /* OpenVPNMinTLSVersion.h */, - C9657A691EB0D75700EFF210 /* OpenVPNTLSCertProfile.h */, - C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */, - C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */, - ); - name = "Types and Constants"; - sourceTree = ""; - }; C9B7955B1F1D165700CF35FE /* Reachability */ = { isa = PBXGroup; children = ( + C9B795681F1D219C00CF35FE /* OpenVPNReachabilityStatus.h */, C9B795621F1D182500CF35FE /* OpenVPNReachabilityTracker.h */, C9B795631F1D182500CF35FE /* OpenVPNReachabilityTracker.mm */, C9B7955C1F1D16AA00CF35FE /* OpenVPNReachability.h */, @@ -432,12 +436,20 @@ C9BB47671E7169F000F3F98C /* Adapter */ = { isa = PBXGroup; children = ( - ABD6EF151F8F9C37007D3D90 /* OpenVPNAdapter.h */, - ABD6EF161F8F9C38007D3D90 /* OpenVPNAdapter.mm */, + C9BB47701E7171A100F3F98C /* OpenVPNAdapterEvent.h */, + C9BB476F1E7171A100F3F98C /* OpenVPNError.h */, + C93A4F611EE18009004DC561 /* OpenVPNError.m */, + C9CDFDD9200781AF00323B73 /* OpenVPNClient.h */, + C9CDFDDA200781AF00323B73 /* OpenVPNClient.mm */, ABD6EF071F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h */, ABD6EF081F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m */, + C9C2B2B6200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h */, + C9C2B2B9200CC42A00CA0FF3 /* OpenVPNPacket.h */, + C9C2B2BA200CC42A00CA0FF3 /* OpenVPNPacket.mm */, ABD6EF0E1F8F93AB007D3D90 /* OpenVPNPacketFlowBridge.h */, ABD6EF0F1F8F93AB007D3D90 /* OpenVPNPacketFlowBridge.mm */, + ABD6EF151F8F9C37007D3D90 /* OpenVPNAdapter.h */, + ABD6EF161F8F9C38007D3D90 /* OpenVPNAdapter.mm */, ); name = Adapter; sourceTree = ""; @@ -538,6 +550,7 @@ C9CA4DD01F602D8300C4F184 /* Certificates and Keys */ = { isa = PBXGroup; children = ( + C915F1FD1F6164CF00B3DF23 /* OpenVPNKeyType.h */, C9CA4DD11F602F7B00C4F184 /* OpenVPNCertificate.h */, C9CA4DD21F602F7B00C4F184 /* OpenVPNCertificate.m */, C915F1F21F612F3300B3DF23 /* OpenVPNPrivateKey.h */, @@ -546,20 +559,19 @@ name = "Certificates and Keys"; sourceTree = ""; }; - C9E4401A1F6081FF001D7C41 /* Utils */ = { + C9E350C5200F70CA000820D9 /* Extensions */ = { isa = PBXGroup; children = ( - C9E4401B1F6086A1001D7C41 /* NSError+Message.h */, - C9E4401C1F6086A1001D7C41 /* NSError+Message.m */, + C9E350BF200F6EC0000820D9 /* NSError+OpenVPNError.h */, + C9E350C0200F6EC0000820D9 /* NSError+OpenVPNError.m */, ); - name = Utils; + name = Extensions; sourceTree = ""; }; C9FF73B71EB7421600E995AC /* Helpers */ = { isa = PBXGroup; children = ( - C9235AC61EB24F2A00C7D303 /* Types and Constants */, - C9E4401A1F6081FF001D7C41 /* Utils */, + C9E350C5200F70CA000820D9 /* Extensions */, ); name = Helpers; sourceTree = ""; @@ -572,6 +584,7 @@ buildActionMask = 2147483647; files = ( C9CA4DD31F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */, + C9CDFDDB200781AF00323B73 /* OpenVPNClient.h in Headers */, C9657A3A1EB0BAAB00EFF210 /* OpenVPNInterfaceStats+Internal.h in Headers */, C9354F451F1E4A4500F4C935 /* OpenVPNReachabilityStatus.h in Headers */, C9BCE25E1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h in Headers */, @@ -596,13 +609,15 @@ C9657A171EB0A7F800EFF210 /* OpenVPNConnectionInfo.h in Headers */, C9BB47711E7171A100F3F98C /* OpenVPNError.h in Headers */, C9B795641F1D182500CF35FE /* OpenVPNReachabilityTracker.h in Headers */, - C9E4401D1F6086A1001D7C41 /* NSError+Message.h in Headers */, ABD6EF091F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h in Headers */, C9657A611EB0D64E00EFF210 /* OpenVPNIPv6Preference.h in Headers */, C9657A671EB0D73200EFF210 /* OpenVPNMinTLSVersion.h in Headers */, + C9C2B2BB200CC42A00CA0FF3 /* OpenVPNPacket.h in Headers */, C93779D51EAE32670030A362 /* OpenVPNCredentials.h in Headers */, C9657A641EB0D6C200EFF210 /* OpenVPNCompressionMode.h in Headers */, C9FD921A1E9A667600374FC4 /* ovpncli.hpp in Headers */, + C9C2B2B7200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h in Headers */, + C9E350C1200F6EC0000820D9 /* NSError+OpenVPNError.h in Headers */, C93779DB1EAE32880030A362 /* OpenVPNCredentials+Internal.h in Headers */, C9657A6A1EB0D75700EFF210 /* OpenVPNTLSCertProfile.h in Headers */, C9657A461EB0CB5900EFF210 /* OpenVPNServerEntry+Internal.h in Headers */, @@ -615,6 +630,7 @@ buildActionMask = 2147483647; files = ( C9CA4DD41F602F7B00C4F184 /* OpenVPNCertificate.h in Headers */, + C9CDFDDC200781AF00323B73 /* OpenVPNClient.h in Headers */, C9657A3B1EB0BAAB00EFF210 /* OpenVPNInterfaceStats+Internal.h in Headers */, C9354F461F1E4A4600F4C935 /* OpenVPNReachabilityStatus.h in Headers */, C9BCE25F1EB3C201009D6AC1 /* OpenVPNSessionToken+Internal.h in Headers */, @@ -639,13 +655,15 @@ C9657A181EB0A7F800EFF210 /* OpenVPNConnectionInfo.h in Headers */, C9D2ABE81EA20F99007EDF9D /* OpenVPNError.h in Headers */, C9B795651F1D182500CF35FE /* OpenVPNReachabilityTracker.h in Headers */, - C9E4401E1F6086A1001D7C41 /* NSError+Message.h in Headers */, ABD6EF0A1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.h in Headers */, C9657A621EB0D64E00EFF210 /* OpenVPNIPv6Preference.h in Headers */, C9657A681EB0D73200EFF210 /* OpenVPNMinTLSVersion.h in Headers */, + C9C2B2BC200CC42A00CA0FF3 /* OpenVPNPacket.h in Headers */, C93779D61EAE32670030A362 /* OpenVPNCredentials.h in Headers */, C9657A651EB0D6C200EFF210 /* OpenVPNCompressionMode.h in Headers */, C9D2ABEA1EA20F99007EDF9D /* ovpncli.hpp in Headers */, + C9C2B2B8200CB42F00CA0FF3 /* OpenVPNAdapterPacketFlow.h in Headers */, + C9E350C2200F6EC0000820D9 /* NSError+OpenVPNError.h in Headers */, C93779DC1EAE32880030A362 /* OpenVPNCredentials+Internal.h in Headers */, C9657A6B1EB0D75700EFF210 /* OpenVPNTLSCertProfile.h in Headers */, C9657A471EB0CB5900EFF210 /* OpenVPNServerEntry+Internal.h in Headers */, @@ -860,18 +878,20 @@ ABD6EF181F8F9C38007D3D90 /* OpenVPNAdapter.mm in Sources */, C9657A421EB0CAC200EFF210 /* OpenVPNServerEntry.mm in Sources */, C9BCE25A1EB3C0D9009D6AC1 /* OpenVPNSessionToken.mm in Sources */, + C9E350C3200F6EC0000820D9 /* NSError+OpenVPNError.m in Sources */, ABD6EF0B1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m in Sources */, C98467A81EAA5B7700272A9A /* OpenVPNConfiguration.mm in Sources */, ABD6EF121F8F93AB007D3D90 /* OpenVPNPacketFlowBridge.mm in Sources */, - C9E4401F1F6086A1001D7C41 /* NSError+Message.m in Sources */, C9657A311EB0B7A900EFF210 /* OpenVPNTransportStats.mm in Sources */, C9B795661F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, C9657A581EB0CE1300EFF210 /* OpenVPNProperties.mm in Sources */, C9CA4DD51F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */, + C9CDFDDD200781AF00323B73 /* OpenVPNClient.mm in Sources */, C915F1F61F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */, C9FD921B1E9A667600374FC4 /* ovpncli.cpp in Sources */, C9657A361EB0BA3900EFF210 /* OpenVPNInterfaceStats.mm in Sources */, C9657A211EB0ACAE00EFF210 /* OpenVPNConnectionInfo.mm in Sources */, + C9C2B2BD200CC42A00CA0FF3 /* OpenVPNPacket.mm in Sources */, C93A4F621EE18009004DC561 /* OpenVPNError.m in Sources */, C93779D71EAE32670030A362 /* OpenVPNCredentials.mm in Sources */, C9B795601F1D16AA00CF35FE /* OpenVPNReachability.mm in Sources */, @@ -899,18 +919,20 @@ ABD6EF1A1F8F9C3B007D3D90 /* OpenVPNAdapter.mm in Sources */, C9657A431EB0CAC200EFF210 /* OpenVPNServerEntry.mm in Sources */, C9BCE25B1EB3C0D9009D6AC1 /* OpenVPNSessionToken.mm in Sources */, + C9E350C4200F6EC0000820D9 /* NSError+OpenVPNError.m in Sources */, ABD6EF0C1F8F8CCD007D3D90 /* OpenVPNNetworkSettingsBuilder.m in Sources */, C98467A91EAA5B7700272A9A /* OpenVPNConfiguration.mm in Sources */, ABD6EF131F8F93AB007D3D90 /* OpenVPNPacketFlowBridge.mm in Sources */, - C9E440201F6086A1001D7C41 /* NSError+Message.m in Sources */, C9657A301EB0B7A600EFF210 /* OpenVPNTransportStats.mm in Sources */, C9B795671F1D182500CF35FE /* OpenVPNReachabilityTracker.mm in Sources */, C9657A591EB0CE1400EFF210 /* OpenVPNProperties.mm in Sources */, C9CA4DD61F602F7B00C4F184 /* OpenVPNCertificate.m in Sources */, + C9CDFDDE200781AF00323B73 /* OpenVPNClient.mm in Sources */, C915F1F71F612F3300B3DF23 /* OpenVPNPrivateKey.m in Sources */, C9D2ABDE1EA20F99007EDF9D /* ovpncli.cpp in Sources */, C9657A371EB0BA3900EFF210 /* OpenVPNInterfaceStats.mm in Sources */, C9657A221EB0ACAE00EFF210 /* OpenVPNConnectionInfo.mm in Sources */, + C9C2B2BE200CC42A00CA0FF3 /* OpenVPNPacket.mm in Sources */, C93A4F631EE18009004DC561 /* OpenVPNError.m in Sources */, C93779D81EAE32670030A362 /* OpenVPNCredentials.mm in Sources */, C9B795611F1D16AA00CF35FE /* OpenVPNReachability.mm in Sources */, @@ -1357,7 +1379,6 @@ SUPPORTED_PLATFORMS = macosx; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Debug; @@ -1404,7 +1425,6 @@ SDKROOT = macosx; SUPPORTED_PLATFORMS = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; VALIDATE_PRODUCT = YES; }; diff --git a/OpenVPN Adapter/NSError+Message.h b/OpenVPN Adapter/NSError+Message.h deleted file mode 100644 index 6497c74..0000000 --- a/OpenVPN Adapter/NSError+Message.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// NSError+Message.h -// OpenVPN Adapter -// -// Created by Sergey Abramchuk on 06.09.17. -// -// - -#import - -@interface NSError (Message) - -+ (NSString *)reasonFromResult:(NSInteger)result; - -@end diff --git a/OpenVPN Adapter/NSError+Message.m b/OpenVPN Adapter/NSError+Message.m deleted file mode 100644 index 47e3a66..0000000 --- a/OpenVPN Adapter/NSError+Message.m +++ /dev/null @@ -1,28 +0,0 @@ -// -// NSError+Message.m -// OpenVPN Adapter -// -// Created by Sergey Abramchuk on 06.09.17. -// -// - -#import - -#import "NSError+Message.h" - -@implementation NSError (Message) - -+ (NSString *)reasonFromResult:(NSInteger)result { - size_t length = 1024; - char *buffer = malloc(length); - - mbedtls_strerror(result, buffer, length); - - NSString *reason = [NSString stringWithUTF8String:buffer]; - - free(buffer); - - return reason; -} - -@end diff --git a/OpenVPN Adapter/NSError+OpenVPNError.h b/OpenVPN Adapter/NSError+OpenVPNError.h new file mode 100644 index 0000000..c137a26 --- /dev/null +++ b/OpenVPN Adapter/NSError+OpenVPNError.h @@ -0,0 +1,33 @@ +// +// NSError+OpenVPNError.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 17.01.2018. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const OpenVPNAdapterErrorDomain; + +typedef NS_ERROR_ENUM(OpenVPNAdapterErrorDomain, OpenVPNAdapterError); + +@interface NSError (OpenVPNAdapterErrorGeneration) + ++ (NSError *)ovpn_errorObjectForAdapterError:(OpenVPNAdapterError)adapterError + description:(NSString *)description + message:(nullable NSString *)message + fatal:(BOOL)fatal; + ++ (OpenVPNAdapterError)ovpn_adapterErrorByName:(NSString *)errorName; + +@end + +@interface NSError (OpenVPNMbedTLSErrorGeneration) + ++ (NSError *)ovpn_errorObjectForMbedTLSError:(NSInteger)errorCode description:(NSString *)description; + +@end + +NS_ASSUME_NONNULL_END diff --git a/OpenVPN Adapter/NSError+OpenVPNError.m b/OpenVPN Adapter/NSError+OpenVPNError.m new file mode 100644 index 0000000..3a607d4 --- /dev/null +++ b/OpenVPN Adapter/NSError+OpenVPNError.m @@ -0,0 +1,203 @@ +// +// NSError+OpenVPNError.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 17.01.2018. +// + +#import "NSError+OpenVPNError.h" + +#import + +#import "OpenVPNError.h" + +@implementation NSError (OpenVPNAdapterErrorGeneration) + ++ (NSError *)ovpn_errorObjectForAdapterError:(OpenVPNAdapterError)adapterError + description:(NSString *)description + message:(NSString *)message + fatal:(BOOL)fatal +{ + NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ + NSLocalizedDescriptionKey: description, + OpenVPNAdapterErrorFatalKey: @(fatal) + }]; + + NSString *errorReason = [NSError ovpn_reasonForAdapterError:adapterError]; + if (errorReason) { + userInfo[NSLocalizedFailureReasonErrorKey] = errorReason; + } + + if (message.length) { + userInfo[OpenVPNAdapterErrorMessageKey] = message; + } + + return [NSError errorWithDomain:OpenVPNAdapterErrorDomain code:adapterError userInfo:userInfo]; +} + ++ (OpenVPNAdapterError)ovpn_adapterErrorByName:(NSString *)errorName { + NSDictionary *errors = @{ + @"NETWORK_RECV_ERROR": @(OpenVPNAdapterErrorNetworkRecvError), + @"NETWORK_EOF_ERROR": @(OpenVPNAdapterErrorNetworkEOFError), + @"NETWORK_SEND_ERROR": @(OpenVPNAdapterErrorNetworkSendError), + @"NETWORK_UNAVAILABLE": @(OpenVPNAdapterErrorNetworkUnavailable), + @"DECRYPT_ERROR": @(OpenVPNAdapterErrorDecryptError), + @"HMAC_ERROR": @(OpenVPNAdapterErrorDecryptError), + @"REPLAY_ERROR": @(OpenVPNAdapterErrorReplayError), + @"BUFFER_ERROR": @(OpenVPNAdapterErrorBufferError), + @"CC_ERROR": @(OpenVPNAdapterErrorCCError), + @"BAD_SRC_ADDR": @(OpenVPNAdapterErrorBadSrcAddr), + @"COMPRESS_ERROR": @(OpenVPNAdapterErrorCompressError), + @"RESOLVE_ERROR": @(OpenVPNAdapterErrorResolveError), + @"SOCKET_PROTECT_ERROR": @(OpenVPNAdapterErrorSocketProtectError), + @"TUN_READ_ERROR": @(OpenVPNAdapterErrorTUNReadError), + @"TUN_WRITE_ERROR": @(OpenVPNAdapterErrorTUNWriteError), + @"TUN_FRAMING_ERROR": @(OpenVPNAdapterErrorTUNFramingError), + @"TUN_SETUP_FAILED": @(OpenVPNAdapterErrorTUNSetupFailed), + @"TUN_IFACE_CREATE": @(OpenVPNAdapterErrorTUNIfaceCreate), + @"TUN_IFACE_DISABLED": @(OpenVPNAdapterErrorTUNIfaceDisabled), + @"TUN_ERROR": @(OpenVPNAdapterErrorTUNError), + @"TAP_NOT_SUPPORTED": @(OpenVPNAdapterErrorTAPNotSupported), + @"REROUTE_GW_NO_DNS": @(OpenVPNAdapterErrorRerouteGatewayNoDns), + @"TRANSPORT_ERROR": @(OpenVPNAdapterErrorTransportError), + @"TCP_OVERFLOW": @(OpenVPNAdapterErrorTCPOverflow), + @"TCP_SIZE_ERROR": @(OpenVPNAdapterErrorTCPSizeError), + @"TCP_CONNECT_ERROR": @(OpenVPNAdapterErrorTCPConnectError), + @"UDP_CONNECT_ERROR": @(OpenVPNAdapterErrorUDPConnectError), + @"SSL_ERROR": @(OpenVPNAdapterErrorSSLError), + @"SSL_PARTIAL_WRITE": @(OpenVPNAdapterErrorSSLPartialWrite), + @"ENCAPSULATION_ERROR": @(OpenVPNAdapterErrorEncapsulationError), + @"EPKI_CERT_ERROR": @(OpenVPNAdapterErrorEPKICertError), + @"EPKI_SIGN_ERROR": @(OpenVPNAdapterErrorEPKISignError), + @"HANDSHAKE_TIMEOUT": @(OpenVPNAdapterErrorHandshakeTimeout), + @"KEEPALIVE_TIMEOUT": @(OpenVPNAdapterErrorKeepaliveTimeout), + @"INACTIVE_TIMEOUT": @(OpenVPNAdapterErrorInactiveTimeout), + @"CONNECTION_TIMEOUT": @(OpenVPNAdapterErrorConnectionTimeout), + @"PRIMARY_EXPIRE": @(OpenVPNAdapterErrorPrimaryExpire), + @"TLS_VERSION_MIN": @(OpenVPNAdapterErrorTLSVersionMin), + @"TLS_AUTH_FAIL": @(OpenVPNAdapterErrorTLSAuthFail), + @"CERT_VERIFY_FAIL": @(OpenVPNAdapterErrorCertVerifyFail), + @"PEM_PASSWORD_FAIL": @(OpenVPNAdapterErrorPEMPasswordFail), + @"AUTH_FAILED": @(OpenVPNAdapterErrorAuthFailed), + @"CLIENT_HALT": @(OpenVPNAdapterErrorClientHalt), + @"CLIENT_RESTART": @(OpenVPNAdapterErrorClientRestart), + @"RELAY": @(OpenVPNAdapterErrorRelay), + @"RELAY_ERROR": @(OpenVPNAdapterErrorRelayError), + @"N_PAUSE": @(OpenVPNAdapterErrorPauseNumber), + @"N_RECONNECT": @(OpenVPNAdapterErrorReconnectNumber), + @"N_KEY_LIMIT_RENEG": @(OpenVPNAdapterErrorKeyLimitRenegNumber), + @"KEY_STATE_ERROR": @(OpenVPNAdapterErrorKeyStateError), + @"PROXY_ERROR": @(OpenVPNAdapterErrorProxyError), + @"PROXY_NEED_CREDS": @(OpenVPNAdapterErrorProxyNeedCreds), + @"KEV_NEGOTIATE_ERROR": @(OpenVPNAdapterErrorKevNegotiateError), + @"KEV_PENDING_ERROR": @(OpenVPNAdapterErrorKevPendingError), + @"N_KEV_EXPIRE": @(OpenVPNAdapterErrorKevExpireNumber), + @"PKTID_INVALID": @(OpenVPNAdapterErrorPKTIDInvalid), + @"PKTID_BACKTRACK": @(OpenVPNAdapterErrorPKTIDBacktrack), + @"PKTID_EXPIRE": @(OpenVPNAdapterErrorPKTIDExpire), + @"PKTID_REPLAY": @(OpenVPNAdapterErrorPKTIDReplay), + @"PKTID_TIME_BACKTRACK": @(OpenVPNAdapterErrorPKTIDTimeBacktrack), + @"DYNAMIC_CHALLENGE": @(OpenVPNAdapterErrorDynamicChallenge), + @"EPKI_ERROR": @(OpenVPNAdapterErrorEPKIError), + @"EPKI_INVALID_ALIAS": @(OpenVPNAdapterErrorEPKIInvalidAlias) + }; + + OpenVPNAdapterError error = errors[errorName] != nil ? + (OpenVPNAdapterError)[errors[errorName] integerValue] : OpenVPNAdapterErrorUnknown; + + return error; +} + ++ (NSString *)ovpn_reasonForAdapterError:(OpenVPNAdapterError)error { + switch (error) { + case OpenVPNAdapterErrorConfigurationFailure: return @"See OpenVPN error message for more details."; + case OpenVPNAdapterErrorCredentialsFailure: return @"See OpenVPN error message for more details."; + case OpenVPNAdapterErrorNetworkRecvError: return @"Errors receiving on network socket."; + case OpenVPNAdapterErrorNetworkEOFError: return @"EOF received on TCP network socket."; + case OpenVPNAdapterErrorNetworkSendError: return @"Errors sending on network socket"; + case OpenVPNAdapterErrorNetworkUnavailable: return @"Network unavailable."; + case OpenVPNAdapterErrorDecryptError: return @"Data channel encrypt/decrypt error."; + case OpenVPNAdapterErrorHMACError: return @"HMAC verification failure."; + case OpenVPNAdapterErrorReplayError: return @"Error from PacketIDReceive."; + case OpenVPNAdapterErrorBufferError: return @"Exception thrown in Buffer methods."; + case OpenVPNAdapterErrorCCError: return @"General control channel errors."; + case OpenVPNAdapterErrorBadSrcAddr: return @"Packet from unknown source address."; + case OpenVPNAdapterErrorCompressError: return @"Compress/Decompress errors on data channel."; + case OpenVPNAdapterErrorResolveError: return @"DNS resolution error."; + case OpenVPNAdapterErrorSocketSetupFailed: return nil; + case OpenVPNAdapterErrorSocketProtectError: return @"Error calling protect() method on socket."; + case OpenVPNAdapterErrorTUNReadError: return @"Read errors on TUN/TAP interface."; + case OpenVPNAdapterErrorTUNWriteError: return @"Write errors on TUN/TAP interface."; + case OpenVPNAdapterErrorTUNFramingError: return @"Error with tun PF_INET/PF_INET6 prefix."; + case OpenVPNAdapterErrorTUNSetupFailed: return @"Error setting up TUN/TAP interface."; + case OpenVPNAdapterErrorTUNIfaceCreate: return @"Error creating TUN/TAP interface."; + case OpenVPNAdapterErrorTUNIfaceDisabled: return @"TUN/TAP interface is disabled."; + case OpenVPNAdapterErrorTUNError: return @"General tun error."; + case OpenVPNAdapterErrorTAPNotSupported: return @"Dev TAP is present in profile but not supported."; + case OpenVPNAdapterErrorRerouteGatewayNoDns: return @"redirect-gateway specified without alt DNS servers."; + case OpenVPNAdapterErrorTransportError: return @"General transport error"; + case OpenVPNAdapterErrorTCPOverflow: return @"TCP output queue overflow."; + case OpenVPNAdapterErrorTCPSizeError: return @"Bad embedded uint16_t TCP packet size."; + case OpenVPNAdapterErrorTCPConnectError: return @"Client error on TCP connect."; + case OpenVPNAdapterErrorUDPConnectError: return @"Client error on UDP connect."; + case OpenVPNAdapterErrorSSLError: return @"Errors resulting from read/write on SSL object."; + case OpenVPNAdapterErrorSSLPartialWrite: return @"SSL object did not process all written cleartext."; + case OpenVPNAdapterErrorEncapsulationError: return @"Exceptions thrown during packet encapsulation."; + case OpenVPNAdapterErrorEPKICertError: return @"Error obtaining certificate from External PKI provider."; + case OpenVPNAdapterErrorEPKISignError: return @"Error obtaining RSA signature from External PKI provider."; + case OpenVPNAdapterErrorHandshakeTimeout: return @"Handshake failed to complete within given time frame."; + case OpenVPNAdapterErrorKeepaliveTimeout: return @"Lost contact with peer."; + case OpenVPNAdapterErrorInactiveTimeout: return @"Disconnected due to inactive timer."; + case OpenVPNAdapterErrorConnectionTimeout: return @"Connection failed to establish within given time."; + case OpenVPNAdapterErrorPrimaryExpire: return @"Primary key context expired."; + case OpenVPNAdapterErrorTLSVersionMin: return @"Peer cannot handshake at our minimum required TLS version."; + case OpenVPNAdapterErrorTLSAuthFail: return @"tls-auth HMAC verification failed."; + case OpenVPNAdapterErrorCertVerifyFail: return @"Peer certificate verification failure."; + case OpenVPNAdapterErrorPEMPasswordFail: return @"Incorrect or missing PEM private key decryption password."; + case OpenVPNAdapterErrorAuthFailed: return @"General authentication failure"; + case OpenVPNAdapterErrorClientHalt: return @"HALT message from server received."; + case OpenVPNAdapterErrorClientRestart: return @"RESTART message from server received."; + case OpenVPNAdapterErrorRelay: return @"RELAY message from server received."; + case OpenVPNAdapterErrorRelayError: return @"RELAY error."; + case OpenVPNAdapterErrorPauseNumber: return nil; + case OpenVPNAdapterErrorReconnectNumber: return nil; + case OpenVPNAdapterErrorKeyLimitRenegNumber: return nil; + case OpenVPNAdapterErrorKeyStateError: return @"Received packet didn't match expected key state."; + case OpenVPNAdapterErrorProxyError: return @"HTTP proxy error."; + case OpenVPNAdapterErrorProxyNeedCreds: return @"HTTP proxy needs credentials."; + case OpenVPNAdapterErrorKevNegotiateError: return nil; + case OpenVPNAdapterErrorKevPendingError: return nil; + case OpenVPNAdapterErrorKevExpireNumber: return nil; + case OpenVPNAdapterErrorPKTIDInvalid: return nil; + case OpenVPNAdapterErrorPKTIDBacktrack: return nil; + case OpenVPNAdapterErrorPKTIDExpire: return nil; + case OpenVPNAdapterErrorPKTIDReplay: return nil; + case OpenVPNAdapterErrorPKTIDTimeBacktrack: return nil; + case OpenVPNAdapterErrorDynamicChallenge: return nil; + case OpenVPNAdapterErrorEPKIError: return nil; + case OpenVPNAdapterErrorEPKIInvalidAlias: return nil; + case OpenVPNAdapterErrorUnknown: return @"Unknown error."; + } +} + +@end + +@implementation NSError (OpenVPNMbedTLSErrorGeneration) + ++ (NSError *)ovpn_errorObjectForMbedTLSError:(NSInteger)errorCode description:(NSString *)description { + size_t length = 1024; + char *buffer = malloc(length); + + mbedtls_strerror(errorCode, buffer, length); + + NSString *reason = [NSString stringWithUTF8String:buffer]; + + free(buffer); + + return [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:errorCode userInfo:@{ + NSLocalizedDescriptionKey: description, + NSLocalizedFailureReasonErrorKey: reason + }]; +} + +@end diff --git a/OpenVPN Adapter/OpenVPNAdapter.h b/OpenVPN Adapter/OpenVPNAdapter.h index b5714cb..45b5ccb 100644 --- a/OpenVPN Adapter/OpenVPNAdapter.h +++ b/OpenVPN Adapter/OpenVPNAdapter.h @@ -7,12 +7,16 @@ // #import -#import "OpenVPNAdapterEvent.h" NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSInteger, OpenVPNAdapterEvent); + @class NEPacketTunnelFlow; @class NEPacketTunnelNetworkSettings; + +@protocol OpenVPNAdapterPacketFlow; + @class OpenVPNAdapter; @class OpenVPNConfiguration; @class OpenVPNConnectionInfo; @@ -26,17 +30,22 @@ NS_ASSUME_NONNULL_BEGIN /** This method is called once the network settings to be used have been established. - The receiver should call the completion handler once these settings have been set, returning a NEPacketTunnelFlow object for the TUN interface, or nil if an error occurred. + The receiver should call the completion handler once these settings have been set, returning a NEPacketTunnelFlow object for + the TUN interface, or nil if an error occurred. @param openVPNAdapter The OpenVPNAdapter instance requesting this information. @param networkSettings The NEPacketTunnelNetworkSettings to be used for the tunnel. @param completionHandler The completion handler to be called with a NEPacketTunnelFlow object, or nil if an error occurred. */ -- (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter configureTunnelWithNetworkSettings:(NEPacketTunnelNetworkSettings *)networkSettings completionHandler:(void (^)(NEPacketTunnelFlow * _Nullable packetFlow))completionHandler NS_SWIFT_NAME(openVPNAdapter(_:configureTunnelWithNetworkSettings:completionHandler:)); +- (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter +configureTunnelWithNetworkSettings:(NEPacketTunnelNetworkSettings *)networkSettings + completionHandler:(void (^)(id _Nullable packetFlow))completionHandler +NS_SWIFT_NAME(openVPNAdapter(_:configureTunnelWithNetworkSettings:completionHandler:)); /** Informs the receiver that an OpenVPN error has occurred. - Some errors are fatal and should trigger the diconnection of the tunnel, check for fatal errors with the OpenVPNAdapterErrorFatalKey. + Some errors are fatal and should trigger the diconnection of the tunnel, check for fatal errors with the + OpenVPNAdapterErrorFatalKey. @param openVPNAdapter The OpenVPNAdapter instance which encountered the error. @param error The error which has occurred. @@ -50,7 +59,10 @@ NS_ASSUME_NONNULL_BEGIN @param event The event which has occurred. @param message An accompanying message, may be nil. */ -- (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter handleEvent:(OpenVPNAdapterEvent)event message:(nullable NSString *)message NS_SWIFT_NAME(openVPNAdapter(_:handleEvent:message:)); +- (void)openVPNAdapter:(OpenVPNAdapter *)openVPNAdapter + handleEvent:(OpenVPNAdapterEvent)event + message:(nullable NSString *)message +NS_SWIFT_NAME(openVPNAdapter(_:handleEvent:message:)); @optional @@ -122,7 +134,9 @@ NS_ASSUME_NONNULL_BEGIN @param error If there is an error applying the configuration, upon return contains an error object that describes the problem. @return A properties object describing the configuration which has been applied. */ -- (nullable OpenVPNProperties *)applyConfiguration:(OpenVPNConfiguration *)configuration error:(NSError **)error NS_SWIFT_NAME(apply(configuration:)); +- (nullable OpenVPNProperties *)applyConfiguration:(OpenVPNConfiguration *)configuration + error:(NSError **)error +NS_SWIFT_NAME(apply(configuration:)); /** Provides credentials to the receiver. diff --git a/OpenVPN Adapter/OpenVPNAdapter.mm b/OpenVPN Adapter/OpenVPNAdapter.mm index e7f83d8..951d505 100644 --- a/OpenVPN Adapter/OpenVPNAdapter.mm +++ b/OpenVPN Adapter/OpenVPNAdapter.mm @@ -8,265 +8,39 @@ #define OPENVPN_EXTERN extern +#import "OpenVPNAdapter.h" + #import -#import -#import + +#import "OpenVPNClient.h" +#import "OpenVPNError.h" #import "OpenVPNAdapterEvent.h" +#import "OpenVPNPacketFlowBridge.h" +#import "OpenVPNNetworkSettingsBuilder.h" +#import "OpenVPNAdapterPacketFlow.h" #import "OpenVPNCredentials+Internal.h" #import "OpenVPNConfiguration+Internal.h" #import "OpenVPNConnectionInfo+Internal.h" -#import "OpenVPNError.h" #import "OpenVPNInterfaceStats+Internal.h" -#import "OpenVPNNetworkSettingsBuilder.h" -#import "OpenVPNPacketFlowBridge.h" #import "OpenVPNProperties+Internal.h" #import "OpenVPNSessionToken+Internal.h" #import "OpenVPNTransportStats+Internal.h" -#import "OpenVPNAdapter.h" +#import "NSError+OpenVPNError.h" -class Client; +@interface OpenVPNAdapter () -@interface OpenVPNAdapter () - -@property (nonatomic) Client *client; - -@property (nonatomic) NSString *sessionName; - -@property (nonatomic) OpenVPNNetworkSettingsBuilder *networkSettingsBuilder; +@property (nonatomic) OpenVPNClient *vpnClient; @property (nonatomic) OpenVPNPacketFlowBridge *packetFlowBridge; - -- (OpenVPNAdapterError)errorByName:(NSString *)errorName; -- (OpenVPNAdapterEvent)eventByName:(NSString *)errorName; -- (NSString *)reasonForError:(OpenVPNAdapterError)error; +@property (nonatomic) OpenVPNNetworkSettingsBuilder *networkSettingsBuilder; @end -using namespace openvpn; - -class Client : public ClientAPI::OpenVPNClient { -public: - Client(OpenVPNAdapter *adapter) { - this->adapter = adapter; - } - - bool tun_builder_set_remote_address(const std::string& address, bool ipv6) override { - NSString *remoteAddress = [[NSString alloc] initWithUTF8String:address.c_str()]; - adapter.networkSettingsBuilder.remoteAddress = remoteAddress; - return true; - } - - bool tun_builder_add_address(const std::string& address, int prefix_length, const std::string& gateway, bool ipv6, bool net30) override { - NSString *localAddress = [[NSString alloc] initWithUTF8String:address.c_str()]; - NSString *gatewayAddress = [[NSString alloc] initWithUTF8String:gateway.c_str()]; - NSString *defaultGateway = gatewayAddress.length == 0 || [gatewayAddress isEqualToString:@"UNSPEC"] ? nil : gatewayAddress; - if (ipv6) { - adapter.networkSettingsBuilder.ipv6DefaultGateway = defaultGateway; - [adapter.networkSettingsBuilder.ipv6LocalAddresses addObject:localAddress]; - [adapter.networkSettingsBuilder.ipv6NetworkPrefixLengths addObject:@(prefix_length)]; - } else { - NSString *subnetMask = [[NSString alloc] initWithUTF8String:IPv4::Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; - adapter.networkSettingsBuilder.ipv4DefaultGateway = defaultGateway; - [adapter.networkSettingsBuilder.ipv4LocalAddresses addObject:localAddress]; - [adapter.networkSettingsBuilder.ipv4SubnetMasks addObject:subnetMask]; - } - return true; - } - - bool tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) override { - if (ipv4) { - NEIPv4Route *includedRoute = [NEIPv4Route defaultRoute]; - includedRoute.gatewayAddress = adapter.networkSettingsBuilder.ipv4DefaultGateway; - [adapter.networkSettingsBuilder.ipv4IncludedRoutes addObject:includedRoute]; - } - if (ipv6) { - NEIPv6Route *includedRoute = [NEIPv6Route defaultRoute]; - includedRoute.gatewayAddress = adapter.networkSettingsBuilder.ipv6DefaultGateway; - [adapter.networkSettingsBuilder.ipv6IncludedRoutes addObject:includedRoute]; - } - return true; - } - - bool tun_builder_add_route(const std::string& address, int prefix_length, int metric, bool ipv6) override { - NSString *route = [[NSString alloc] initWithUTF8String:address.c_str()]; - if (ipv6) { - NEIPv6Route *includedRoute = [[NEIPv6Route alloc] initWithDestinationAddress:route networkPrefixLength:@(prefix_length)]; - includedRoute.gatewayAddress = adapter.networkSettingsBuilder.ipv6DefaultGateway; - [adapter.networkSettingsBuilder.ipv6IncludedRoutes addObject:includedRoute]; - } else { - NSString *subnetMask = [[NSString alloc] initWithUTF8String:IPv4::Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; - NEIPv4Route *includedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnetMask]; - includedRoute.gatewayAddress = adapter.networkSettingsBuilder.ipv4DefaultGateway; - [adapter.networkSettingsBuilder.ipv4IncludedRoutes addObject:includedRoute]; - } - return true; - } - - bool tun_builder_exclude_route(const std::string& address, int prefix_length, int metric, bool ipv6) override { - NSString *route = [[NSString alloc] initWithUTF8String:address.c_str()]; - if (ipv6) { - NEIPv6Route *excludedRoute = [[NEIPv6Route alloc] initWithDestinationAddress:route networkPrefixLength:@(prefix_length)]; - [adapter.networkSettingsBuilder.ipv6ExcludedRoutes addObject:excludedRoute]; - } else { - NSString *subnetMask = [[NSString alloc] initWithUTF8String:IPv4::Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; - NEIPv4Route *excludedRoute = [[NEIPv4Route alloc] initWithDestinationAddress:route subnetMask:subnetMask]; - [adapter.networkSettingsBuilder.ipv4ExcludedRoutes addObject:excludedRoute]; - } - return true; - } - - bool tun_builder_add_dns_server(const std::string& address, bool ipv6) override { - NSString *dnsAddress = [[NSString alloc] initWithUTF8String:address.c_str()]; - [adapter.networkSettingsBuilder.dnsServers addObject:dnsAddress]; - return true; - } - - bool tun_builder_add_search_domain(const std::string& domain) override { - NSString *searchDomain = [[NSString alloc] initWithUTF8String:domain.c_str()]; - [adapter.networkSettingsBuilder.searchDomains addObject:searchDomain]; - return true; - } - - bool tun_builder_set_mtu(int mtu) override { - adapter.networkSettingsBuilder.mtu = @(mtu); - return true; - } - - bool tun_builder_set_session_name(const std::string& name) override { - adapter.sessionName = [[NSString alloc] initWithUTF8String:name.c_str()]; - return true; - } - - bool tun_builder_add_proxy_bypass(const std::string& bypass_host) override { - NSString *bypassHost = [[NSString alloc] initWithUTF8String:bypass_host.c_str()]; - [adapter.networkSettingsBuilder.proxyExceptionList addObject:bypassHost]; - return true; - } - - bool tun_builder_set_proxy_auto_config_url(const std::string& urlString) override { - NSURL *url = [[NSURL alloc] initWithString:[[NSString alloc] initWithUTF8String:urlString.c_str()]]; - adapter.networkSettingsBuilder.autoProxyConfigurationEnabled = url != nil; - adapter.networkSettingsBuilder.proxyAutoConfigurationURL = url; - return true; - } - - bool tun_builder_set_proxy_http(const std::string& host, int port) override { - NSString *address = [[NSString alloc] initWithUTF8String:host.c_str()]; - adapter.networkSettingsBuilder.httpProxyServerEnabled = YES; - adapter.networkSettingsBuilder.httpProxyServer = [[NEProxyServer alloc] initWithAddress:address port:port]; - return true; - } - - bool tun_builder_set_proxy_https(const std::string& host, int port) override { - NSString *address = [[NSString alloc] initWithUTF8String:host.c_str()]; - adapter.networkSettingsBuilder.httpsProxyServerEnabled = YES; - adapter.networkSettingsBuilder.httpsProxyServer = [[NEProxyServer alloc] initWithAddress:address port:port]; - return true; - } - - bool tun_builder_set_block_ipv6(bool block_ipv6) override { - return false; - } - - bool tun_builder_new() override { - reset_tun(); - return true; - } - - int tun_builder_establish() override { - NEPacketTunnelNetworkSettings *networkSettings = adapter.networkSettingsBuilder.networkSettings; - if (!networkSettings) { - return -1; - } - - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - [adapter.delegate openVPNAdapter:adapter configureTunnelWithNetworkSettings:networkSettings completionHandler:^(NEPacketTunnelFlow * _Nullable flow) { - adapter.packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] initWithPacketFlow:flow]; - dispatch_semaphore_signal(semaphore); - }]; - dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC)); - - if (adapter.packetFlowBridge) { - return adapter.packetFlowBridge.socketHandle; - } else { - return -1; - } - } - - void tun_builder_teardown(bool disconnect) override { - reset_tun(); - } - - bool tun_builder_persist() override { - return true; - } - - bool socket_protect(int socket) override { - return true; - } - - bool pause_on_connection_timeout() override { - return false; - } - - void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) override { - - } - - void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) override { - - } - - void event(const ClientAPI::Event& event) override { - NSString *name = [[NSString alloc] initWithUTF8String:event.name.c_str()]; - NSString *message = [[NSString alloc] initWithUTF8String:event.info.c_str()]; - - if (event.error) { - OpenVPNAdapterError errorCode = [adapter errorByName:name]; - NSString *errorReason = [adapter reasonForError:errorCode]; - - NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"OpenVPN error occured.", - NSLocalizedFailureReasonErrorKey: errorReason, - OpenVPNAdapterErrorMessageKey: message != nil ? message : @"", - OpenVPNAdapterErrorFatalKey: @(event.fatal) }; - - NSError *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain code:errorCode userInfo:userInfo]; - [adapter.delegate openVPNAdapter:adapter handleError:error]; - } else { - OpenVPNAdapterEvent eventIdentifier = [adapter eventByName:name]; - [adapter.delegate openVPNAdapter:adapter handleEvent:eventIdentifier message:message.length ? message : nil]; - } - } - - void log(const ClientAPI::LogInfo& log) override { - if ([adapter.delegate respondsToSelector:@selector(openVPNAdapter:handleLogMessage:)]) { - [adapter.delegate openVPNAdapter:adapter handleLogMessage:[[NSString alloc] initWithUTF8String:log.text.c_str()]]; - } - } - - void clock_tick() override { - if ([adapter.delegate respondsToSelector:@selector(openVPNAdapterDidReceiveClockTick:)]) { - [adapter.delegate openVPNAdapterDidReceiveClockTick:adapter]; - } - } - - void reset_tun() { - adapter.packetFlowBridge = nil; - adapter.networkSettingsBuilder = nil; - adapter.sessionName = nil; - } - -private: - OpenVPNAdapter *adapter; -}; - @implementation OpenVPNAdapter -#pragma mark - Initialization - - (instancetype)init { - if ((self = [super init])) { - self.client = new Client(self); + if (self = [super init]) { + _vpnClient = new OpenVPNClient(self); } return self; } @@ -274,19 +48,17 @@ private: #pragma mark - OpenVPNClient Lifecycle - (OpenVPNProperties *)applyConfiguration:(OpenVPNConfiguration *)configuration error:(NSError * _Nullable __autoreleasing *)error { - ClientAPI::EvalConfig eval = self.client->eval_config(configuration.config); + ClientAPI::EvalConfig eval = self.vpnClient->eval_config(configuration.config); if (eval.error) { if (error) { - NSString *errorReason = [self reasonForError:OpenVPNAdapterErrorConfigurationFailure]; - - NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Failed to apply OpenVPN configuration.", - NSLocalizedFailureReasonErrorKey: errorReason, - OpenVPNAdapterErrorMessageKey: [[NSString alloc] initWithUTF8String:eval.message.c_str()], - OpenVPNAdapterErrorFatalKey: @YES }; - - *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain code:OpenVPNAdapterErrorConfigurationFailure userInfo: userInfo]; + NSString *message = [NSString stringWithUTF8String:eval.message.c_str()]; + *error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorConfigurationFailure + description:@"Failed to apply OpenVPN configuration" + message:message + fatal:YES]; } + return nil; } @@ -294,22 +66,15 @@ private: } - (BOOL)provideCredentials:(OpenVPNCredentials *)credentials error:(NSError * _Nullable __autoreleasing *)error { - ClientAPI::Status status = self.client->provide_creds(credentials.credentials); + ClientAPI::Status status = self.vpnClient->provide_creds(credentials.credentials); if (status.error) { if (error) { - OpenVPNAdapterError errorCode = !status.status.empty() ? - [self errorByName:[[NSString alloc] initWithUTF8String:status.status.c_str()]] : - OpenVPNAdapterErrorCredentialsFailure; - - NSString *errorReason = [self reasonForError:errorCode]; - - NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Failed to provide OpenVPN credentials.", - NSLocalizedFailureReasonErrorKey: errorReason, - OpenVPNAdapterErrorMessageKey: [[NSString alloc] initWithUTF8String:status.message.c_str()], - OpenVPNAdapterErrorFatalKey: @YES }; - - *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain code:errorCode userInfo:userInfo]; + NSString *message = [NSString stringWithUTF8String:status.message.c_str()]; + *error = [NSError ovpn_errorObjectForAdapterError:OpenVPNAdapterErrorCredentialsFailure + description:@"Failed to provide OpenVPN credentials" + message:message + fatal:YES]; } return NO; @@ -320,255 +85,273 @@ private: - (void)connect { dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0); - dispatch_queue_t connectQueue = dispatch_queue_create("com.openvpnadapter.connection", attributes); + dispatch_queue_t connectQueue = dispatch_queue_create("me.ss-abramchuk.openvpn-adapter.connection", attributes); dispatch_async(connectQueue, ^{ - Client::init_process(); - ClientAPI::Status status = self.client->connect(); + OpenVPNClient::init_process(); + + ClientAPI::Status status = self.vpnClient->connect(); [self handleConnectionStatus:status]; - Client::uninit_process(); + + OpenVPNClient::uninit_process(); }); } - (void)reconnectAfterTimeInterval:(NSTimeInterval)timeInterval { - self.client->reconnect(timeInterval); + self.vpnClient->reconnect(timeInterval); } - (void)disconnect { - self.client->stop(); + self.vpnClient->stop(); } - (void)pauseWithReason:(NSString *)reason { - self.client->pause(std::string(reason.UTF8String)); + self.vpnClient->pause(std::string(reason.UTF8String)); } - (void)resume { - self.client->resume(); + self.vpnClient->resume(); } - (void)handleConnectionStatus:(ClientAPI::Status)status { - if (!status.error) { - return; - } + if (!status.error) { return; } - OpenVPNAdapterError errorCode = !status.status.empty() ? [self errorByName:[[NSString alloc] initWithUTF8String:status.status.c_str()]] : OpenVPNAdapterErrorUnknown; - NSString *errorReason = [self reasonForError:errorCode]; + OpenVPNAdapterError adapterError = !status.status.empty() ? + [NSError ovpn_adapterErrorByName:[NSString stringWithUTF8String:status.status.c_str()]] : + OpenVPNAdapterErrorUnknown; - NSDictionary *userInfo = @{ NSLocalizedDescriptionKey: @"Failed to establish connection with OpenVPN server.", - NSLocalizedFailureReasonErrorKey: errorReason, - OpenVPNAdapterErrorMessageKey: [[NSString alloc] initWithUTF8String:status.message.c_str()], - OpenVPNAdapterErrorFatalKey: @YES }; - - NSError *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain code:errorCode userInfo:userInfo]; + NSString *message = [NSString stringWithUTF8String:status.message.c_str()]; + NSError *error = [NSError ovpn_errorObjectForAdapterError:adapterError + description:@"Failed to establish connection with OpenVPN server" + message:message + fatal:YES]; + [self.delegate openVPNAdapter:self handleError:error]; } #pragma mark - OpenVPNClient Information + (NSString *)copyright { - return [[NSString alloc] initWithUTF8String:Client::copyright().c_str()]; + return [NSString stringWithUTF8String:OpenVPNClient::copyright().c_str()]; } + (NSString *)platform { - return [[NSString alloc] initWithUTF8String:Client::platform().c_str()]; + return [NSString stringWithUTF8String:OpenVPNClient::platform().c_str()]; } - (OpenVPNConnectionInfo *)connectionInformation { - ClientAPI::ConnectionInfo information = self.client->connection_info(); + ClientAPI::ConnectionInfo information = self.vpnClient->connection_info(); return information.defined ? [[OpenVPNConnectionInfo alloc] initWithConnectionInfo:information] : nil; } - (OpenVPNInterfaceStats *)interfaceStatistics { - return [[OpenVPNInterfaceStats alloc] initWithInterfaceStats:self.client->tun_stats()]; + return [[OpenVPNInterfaceStats alloc] initWithInterfaceStats:self.vpnClient->tun_stats()]; } - (OpenVPNSessionToken *)sessionToken { ClientAPI::SessionToken token; - return self.client->session_token(token) ? [[OpenVPNSessionToken alloc] initWithSessionToken:token] : nil; + return self.vpnClient->session_token(token) ? [[OpenVPNSessionToken alloc] initWithSessionToken:token] : nil; } - (OpenVPNTransportStats *)transportStatistics { - return [[OpenVPNTransportStats alloc] initWithTransportStats:self.client->transport_stats()]; -} - -#pragma mark - OpenVPNAdapterEvent Helpers - -- (OpenVPNAdapterEvent)eventByName:(NSString *)eventName { - NSDictionary *events = @{@"DISCONNECTED": @(OpenVPNAdapterEventDisconnected), - @"CONNECTED": @(OpenVPNAdapterEventConnected), - @"RECONNECTING": @(OpenVPNAdapterEventReconnecting), - @"RESOLVE": @(OpenVPNAdapterEventResolve), - @"WAIT": @(OpenVPNAdapterEventWait), - @"WAIT_PROXY": @(OpenVPNAdapterEventWaitProxy), - @"CONNECTING": @(OpenVPNAdapterEventConnecting), - @"GET_CONFIG": @(OpenVPNAdapterEventGetConfig), - @"ASSIGN_IP": @(OpenVPNAdapterEventAssignIP), - @"ADD_ROUTES": @(OpenVPNAdapterEventAddRoutes), - @"ECHO": @(OpenVPNAdapterEventEcho), - @"INFO": @(OpenVPNAdapterEventInfo), - @"PAUSE": @(OpenVPNAdapterEventPause), - @"RESUME": @(OpenVPNAdapterEventResume), - @"RELAY": @(OpenVPNAdapterEventRelay)}; - - OpenVPNAdapterEvent event = events[eventName] != nil ? (OpenVPNAdapterEvent)[events[eventName] integerValue] : OpenVPNAdapterEventUnknown; - return event; -} - -#pragma mark - OpenVPNAdapterError Helpers - -- (OpenVPNAdapterError)errorByName:(NSString *)errorName { - NSDictionary *errors = @{@"NETWORK_RECV_ERROR": @(OpenVPNAdapterErrorNetworkRecvError), - @"NETWORK_EOF_ERROR": @(OpenVPNAdapterErrorNetworkEOFError), - @"NETWORK_SEND_ERROR": @(OpenVPNAdapterErrorNetworkSendError), - @"NETWORK_UNAVAILABLE": @(OpenVPNAdapterErrorNetworkUnavailable), - @"DECRYPT_ERROR": @(OpenVPNAdapterErrorDecryptError), - @"HMAC_ERROR": @(OpenVPNAdapterErrorDecryptError), - @"REPLAY_ERROR": @(OpenVPNAdapterErrorReplayError), - @"BUFFER_ERROR": @(OpenVPNAdapterErrorBufferError), - @"CC_ERROR": @(OpenVPNAdapterErrorCCError), - @"BAD_SRC_ADDR": @(OpenVPNAdapterErrorBadSrcAddr), - @"COMPRESS_ERROR": @(OpenVPNAdapterErrorCompressError), - @"RESOLVE_ERROR": @(OpenVPNAdapterErrorResolveError), - @"SOCKET_PROTECT_ERROR": @(OpenVPNAdapterErrorSocketProtectError), - @"TUN_READ_ERROR": @(OpenVPNAdapterErrorTUNReadError), - @"TUN_WRITE_ERROR": @(OpenVPNAdapterErrorTUNWriteError), - @"TUN_FRAMING_ERROR": @(OpenVPNAdapterErrorTUNFramingError), - @"TUN_SETUP_FAILED": @(OpenVPNAdapterErrorTUNSetupFailed), - @"TUN_IFACE_CREATE": @(OpenVPNAdapterErrorTUNIfaceCreate), - @"TUN_IFACE_DISABLED": @(OpenVPNAdapterErrorTUNIfaceDisabled), - @"TUN_ERROR": @(OpenVPNAdapterErrorTUNError), - @"TAP_NOT_SUPPORTED": @(OpenVPNAdapterErrorTAPNotSupported), - @"REROUTE_GW_NO_DNS": @(OpenVPNAdapterErrorRerouteGatewayNoDns), - @"TRANSPORT_ERROR": @(OpenVPNAdapterErrorTransportError), - @"TCP_OVERFLOW": @(OpenVPNAdapterErrorTCPOverflow), - @"TCP_SIZE_ERROR": @(OpenVPNAdapterErrorTCPSizeError), - @"TCP_CONNECT_ERROR": @(OpenVPNAdapterErrorTCPConnectError), - @"UDP_CONNECT_ERROR": @(OpenVPNAdapterErrorUDPConnectError), - @"SSL_ERROR": @(OpenVPNAdapterErrorSSLError), - @"SSL_PARTIAL_WRITE": @(OpenVPNAdapterErrorSSLPartialWrite), - @"ENCAPSULATION_ERROR": @(OpenVPNAdapterErrorEncapsulationError), - @"EPKI_CERT_ERROR": @(OpenVPNAdapterErrorEPKICertError), - @"EPKI_SIGN_ERROR": @(OpenVPNAdapterErrorEPKISignError), - @"HANDSHAKE_TIMEOUT": @(OpenVPNAdapterErrorHandshakeTimeout), - @"KEEPALIVE_TIMEOUT": @(OpenVPNAdapterErrorKeepaliveTimeout), - @"INACTIVE_TIMEOUT": @(OpenVPNAdapterErrorInactiveTimeout), - @"CONNECTION_TIMEOUT": @(OpenVPNAdapterErrorConnectionTimeout), - @"PRIMARY_EXPIRE": @(OpenVPNAdapterErrorPrimaryExpire), - @"TLS_VERSION_MIN": @(OpenVPNAdapterErrorTLSVersionMin), - @"TLS_AUTH_FAIL": @(OpenVPNAdapterErrorTLSAuthFail), - @"CERT_VERIFY_FAIL": @(OpenVPNAdapterErrorCertVerifyFail), - @"PEM_PASSWORD_FAIL": @(OpenVPNAdapterErrorPEMPasswordFail), - @"AUTH_FAILED": @(OpenVPNAdapterErrorAuthFailed), - @"CLIENT_HALT": @(OpenVPNAdapterErrorClientHalt), - @"CLIENT_RESTART": @(OpenVPNAdapterErrorClientRestart), - @"RELAY": @(OpenVPNAdapterErrorRelay), - @"RELAY_ERROR": @(OpenVPNAdapterErrorRelayError), - @"N_PAUSE": @(OpenVPNAdapterErrorPauseNumber), - @"N_RECONNECT": @(OpenVPNAdapterErrorReconnectNumber), - @"N_KEY_LIMIT_RENEG": @(OpenVPNAdapterErrorKeyLimitRenegNumber), - @"KEY_STATE_ERROR": @(OpenVPNAdapterErrorKeyStateError), - @"PROXY_ERROR": @(OpenVPNAdapterErrorProxyError), - @"PROXY_NEED_CREDS": @(OpenVPNAdapterErrorProxyNeedCreds), - @"KEV_NEGOTIATE_ERROR": @(OpenVPNAdapterErrorKevNegotiateError), - @"KEV_PENDING_ERROR": @(OpenVPNAdapterErrorKevPendingError), - @"N_KEV_EXPIRE": @(OpenVPNAdapterErrorKevExpireNumber), - @"PKTID_INVALID": @(OpenVPNAdapterErrorPKTIDInvalid), - @"PKTID_BACKTRACK": @(OpenVPNAdapterErrorPKTIDBacktrack), - @"PKTID_EXPIRE": @(OpenVPNAdapterErrorPKTIDExpire), - @"PKTID_REPLAY": @(OpenVPNAdapterErrorPKTIDReplay), - @"PKTID_TIME_BACKTRACK": @(OpenVPNAdapterErrorPKTIDTimeBacktrack), - @"DYNAMIC_CHALLENGE": @(OpenVPNAdapterErrorDynamicChallenge), - @"EPKI_ERROR": @(OpenVPNAdapterErrorEPKIError), - @"EPKI_INVALID_ALIAS": @(OpenVPNAdapterErrorEPKIInvalidAlias)}; - - OpenVPNAdapterError error = errors[errorName] != nil ? (OpenVPNAdapterError)[errors[errorName] integerValue] : OpenVPNAdapterErrorUnknown; - return error; -} - -- (NSString *)reasonForError:(OpenVPNAdapterError)error { - // TODO: Add missing error reasons - switch (error) { - case OpenVPNAdapterErrorConfigurationFailure: return @"See OpenVPN error message for more details."; - case OpenVPNAdapterErrorCredentialsFailure: return @"See OpenVPN error message for more details."; - case OpenVPNAdapterErrorNetworkRecvError: return @"Errors receiving on network socket."; - case OpenVPNAdapterErrorNetworkEOFError: return @"EOF received on TCP network socket."; - case OpenVPNAdapterErrorNetworkSendError: return @"Errors sending on network socket"; - case OpenVPNAdapterErrorNetworkUnavailable: return @"Network unavailable."; - case OpenVPNAdapterErrorDecryptError: return @"Data channel encrypt/decrypt error."; - case OpenVPNAdapterErrorHMACError: return @"HMAC verification failure."; - case OpenVPNAdapterErrorReplayError: return @"Error from PacketIDReceive."; - case OpenVPNAdapterErrorBufferError: return @"Exception thrown in Buffer methods."; - case OpenVPNAdapterErrorCCError: return @"General control channel errors."; - case OpenVPNAdapterErrorBadSrcAddr: return @"Packet from unknown source address."; - case OpenVPNAdapterErrorCompressError: return @"Compress/Decompress errors on data channel."; - case OpenVPNAdapterErrorResolveError: return @"DNS resolution error."; - case OpenVPNAdapterErrorSocketProtectError: return @"Error calling protect() method on socket."; - case OpenVPNAdapterErrorTUNReadError: return @"Read errors on TUN/TAP interface."; - case OpenVPNAdapterErrorTUNWriteError: return @"Write errors on TUN/TAP interface."; - case OpenVPNAdapterErrorTUNFramingError: return @"Error with tun PF_INET/PF_INET6 prefix."; - case OpenVPNAdapterErrorTUNSetupFailed: return @"Error setting up TUN/TAP interface."; - case OpenVPNAdapterErrorTUNIfaceCreate: return @"Error creating TUN/TAP interface."; - case OpenVPNAdapterErrorTUNIfaceDisabled: return @"TUN/TAP interface is disabled."; - case OpenVPNAdapterErrorTUNError: return @"General tun error."; - case OpenVPNAdapterErrorTAPNotSupported: return @"Dev TAP is present in profile but not supported."; - case OpenVPNAdapterErrorRerouteGatewayNoDns: return @"redirect-gateway specified without alt DNS servers."; - case OpenVPNAdapterErrorTransportError: return @"General transport error"; - case OpenVPNAdapterErrorTCPOverflow: return @"TCP output queue overflow."; - case OpenVPNAdapterErrorTCPSizeError: return @"Bad embedded uint16_t TCP packet size."; - case OpenVPNAdapterErrorTCPConnectError: return @"Client error on TCP connect."; - case OpenVPNAdapterErrorUDPConnectError: return @"Client error on UDP connect."; - case OpenVPNAdapterErrorSSLError: return @"Errors resulting from read/write on SSL object."; - case OpenVPNAdapterErrorSSLPartialWrite: return @"SSL object did not process all written cleartext."; - case OpenVPNAdapterErrorEncapsulationError: return @"Exceptions thrown during packet encapsulation."; - case OpenVPNAdapterErrorEPKICertError: return @"Error obtaining certificate from External PKI provider."; - case OpenVPNAdapterErrorEPKISignError: return @"Error obtaining RSA signature from External PKI provider."; - case OpenVPNAdapterErrorHandshakeTimeout: return @"Handshake failed to complete within given time frame."; - case OpenVPNAdapterErrorKeepaliveTimeout: return @"Lost contact with peer."; - case OpenVPNAdapterErrorInactiveTimeout: return @"Disconnected due to inactive timer."; - case OpenVPNAdapterErrorConnectionTimeout: return @"Connection failed to establish within given time."; - case OpenVPNAdapterErrorPrimaryExpire: return @"Primary key context expired."; - case OpenVPNAdapterErrorTLSVersionMin: return @"Peer cannot handshake at our minimum required TLS version."; - case OpenVPNAdapterErrorTLSAuthFail: return @"tls-auth HMAC verification failed."; - case OpenVPNAdapterErrorCertVerifyFail: return @"Peer certificate verification failure."; - case OpenVPNAdapterErrorPEMPasswordFail: return @"Incorrect or missing PEM private key decryption password."; - case OpenVPNAdapterErrorAuthFailed: return @"General authentication failure"; - case OpenVPNAdapterErrorClientHalt: return @"HALT message from server received."; - case OpenVPNAdapterErrorClientRestart: return @"RESTART message from server received."; - case OpenVPNAdapterErrorRelay: return @"RELAY message from server received."; - case OpenVPNAdapterErrorRelayError: return @"RELAY error."; - case OpenVPNAdapterErrorPauseNumber: return @""; - case OpenVPNAdapterErrorReconnectNumber: return @""; - case OpenVPNAdapterErrorKeyLimitRenegNumber: return @""; - case OpenVPNAdapterErrorKeyStateError: return @"Received packet didn't match expected key state."; - case OpenVPNAdapterErrorProxyError: return @"HTTP proxy error."; - case OpenVPNAdapterErrorProxyNeedCreds: return @"HTTP proxy needs credentials."; - case OpenVPNAdapterErrorKevNegotiateError: return @""; - case OpenVPNAdapterErrorKevPendingError: return @""; - case OpenVPNAdapterErrorKevExpireNumber: return @""; - case OpenVPNAdapterErrorPKTIDInvalid: return @""; - case OpenVPNAdapterErrorPKTIDBacktrack: return @""; - case OpenVPNAdapterErrorPKTIDExpire: return @""; - case OpenVPNAdapterErrorPKTIDReplay: return @""; - case OpenVPNAdapterErrorPKTIDTimeBacktrack: return @""; - case OpenVPNAdapterErrorDynamicChallenge: return @""; - case OpenVPNAdapterErrorEPKIError: return @""; - case OpenVPNAdapterErrorEPKIInvalidAlias: return @""; - case OpenVPNAdapterErrorUnknown: return @"Unknown error."; - } + return [[OpenVPNTransportStats alloc] initWithTransportStats:self.vpnClient->transport_stats()]; } #pragma mark - Lazy Initialization - (OpenVPNNetworkSettingsBuilder *)networkSettingsBuilder { - if (!_networkSettingsBuilder) { - _networkSettingsBuilder = [[OpenVPNNetworkSettingsBuilder alloc] init]; - } + if (!_networkSettingsBuilder) { _networkSettingsBuilder = [[OpenVPNNetworkSettingsBuilder alloc] init]; } return _networkSettingsBuilder; } -#pragma mark - Dealloc +#pragma mark - OpenVPNClientDelegate + +- (BOOL)setRemoteAddress:(NSString *)address { + self.networkSettingsBuilder.remoteAddress = address; + return YES; +} + +- (BOOL)addIPV4Address:(NSString *)address subnetMask:(NSString *)subnetMask gateway:(NSString *)gateway { + self.networkSettingsBuilder.ipv4DefaultGateway = gateway; + [self.networkSettingsBuilder.ipv4LocalAddresses addObject:address]; + [self.networkSettingsBuilder.ipv4SubnetMasks addObject:subnetMask]; + + return YES; +} + +- (BOOL)addIPV6Address:(NSString *)address prefixLength:(NSNumber *)prefixLength gateway:(NSString *)gateway { + self.networkSettingsBuilder.ipv6DefaultGateway = gateway; + [self.networkSettingsBuilder.ipv6LocalAddresses addObject:address]; + [self.networkSettingsBuilder.ipv6NetworkPrefixLengths addObject:prefixLength]; + + return YES; +} + +- (BOOL)addIPV4Route:(NEIPv4Route *)route { + route.gatewayAddress = self.networkSettingsBuilder.ipv4DefaultGateway; + [self.networkSettingsBuilder.ipv4IncludedRoutes addObject:route]; + + return YES; +} + +- (BOOL)addIPV6Route:(NEIPv6Route *)route { + route.gatewayAddress = self.networkSettingsBuilder.ipv6DefaultGateway; + [self.networkSettingsBuilder.ipv6IncludedRoutes addObject:route]; + + return YES; +} + +- (BOOL)excludeIPV4Route:(NEIPv4Route *)route { + [self.networkSettingsBuilder.ipv4ExcludedRoutes addObject:route]; + return YES; +} + +- (BOOL)excludeIPV6Route:(NEIPv6Route *)route { + [self.networkSettingsBuilder.ipv6ExcludedRoutes addObject:route]; + return YES; +} + +- (BOOL)addDNS:(NSString *)dns { + [self.networkSettingsBuilder.dnsServers addObject:dns]; + return YES; +} + +- (BOOL)addSearchDomain:(NSString *)domain { + [self.networkSettingsBuilder.searchDomains addObject:domain]; + return YES; +} + +- (BOOL)setMTU:(NSNumber *)mtu { + self.networkSettingsBuilder.mtu = mtu; + return YES; +} + +- (BOOL)setSessionName:(NSString *)name { + _sessionName = name; + return YES; +} + +- (BOOL)addProxyBypassHost:(NSString *)bypassHost { + [self.networkSettingsBuilder.proxyExceptionList addObject:bypassHost]; + return YES; +} + +- (BOOL)setProxyAutoConfigurationURL:(NSURL *)url { + self.networkSettingsBuilder.autoProxyConfigurationEnabled = YES; + self.networkSettingsBuilder.proxyAutoConfigurationURL = url; + + return YES; +} + +- (BOOL)setProxyServer:(NEProxyServer *)server protocol:(OpenVPNProxyServerProtocol)protocol { + switch (protocol) { + case OpenVPNProxyServerProtocolHTTP: + self.networkSettingsBuilder.httpProxyServerEnabled = YES; + self.networkSettingsBuilder.httpProxyServer = server; + break; + + case OpenVPNProxyServerProtocolHTTPS: + self.networkSettingsBuilder.httpsProxyServerEnabled = YES; + self.networkSettingsBuilder.httpsProxyServer = server; + break; + } + + return YES; +} + +- (BOOL)establishTunnel { + NEPacketTunnelNetworkSettings *networkSettings = [self.networkSettingsBuilder networkSettings]; + if (!networkSettings) { return NO; } + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + __weak typeof(self) weakSelf = self; + void (^completionHandler)(id _Nullable) = ^(id flow) { + __strong typeof(self) self = weakSelf; + + if (flow) { + self.packetFlowBridge = [[OpenVPNPacketFlowBridge alloc] initWithPacketFlow:flow]; + } + + dispatch_semaphore_signal(semaphore); + }; + + [self.delegate openVPNAdapter:self configureTunnelWithNetworkSettings:networkSettings completionHandler:completionHandler]; + + dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC)); + + NSError *socketError; + if (self.packetFlowBridge && [self.packetFlowBridge configureSocketsWithError:&socketError]) { + [self.packetFlowBridge startReading]; + return YES; + } else { + if (socketError) { [self.delegate openVPNAdapter:self handleError:socketError]; } + return NO; + } +} + +- (CFSocketNativeHandle)socketHandle { + return CFSocketGetNative(self.packetFlowBridge.openVPNSocket); +} + +- (void)clientEventName:(NSString *)eventName message:(NSString *)message { + NSDictionary *events = @{ + @"DISCONNECTED": @(OpenVPNAdapterEventDisconnected), + @"CONNECTED": @(OpenVPNAdapterEventConnected), + @"RECONNECTING": @(OpenVPNAdapterEventReconnecting), + @"RESOLVE": @(OpenVPNAdapterEventResolve), + @"WAIT": @(OpenVPNAdapterEventWait), + @"WAIT_PROXY": @(OpenVPNAdapterEventWaitProxy), + @"CONNECTING": @(OpenVPNAdapterEventConnecting), + @"GET_CONFIG": @(OpenVPNAdapterEventGetConfig), + @"ASSIGN_IP": @(OpenVPNAdapterEventAssignIP), + @"ADD_ROUTES": @(OpenVPNAdapterEventAddRoutes), + @"ECHO": @(OpenVPNAdapterEventEcho), + @"INFO": @(OpenVPNAdapterEventInfo), + @"PAUSE": @(OpenVPNAdapterEventPause), + @"RESUME": @(OpenVPNAdapterEventResume), + @"RELAY": @(OpenVPNAdapterEventRelay) + }; + + OpenVPNAdapterEvent event = events[eventName] != nil ? + (OpenVPNAdapterEvent)[events[eventName] integerValue] : OpenVPNAdapterEventUnknown; + + [self.delegate openVPNAdapter:self handleEvent:event message:message]; +} + +- (void)clientErrorName:(NSString *)errorName fatal:(BOOL)fatal message:(NSString *)message { + OpenVPNAdapterError adapterError = [NSError ovpn_adapterErrorByName:errorName]; + NSString *description = fatal ? @"OpenVPN fatal error occured" : @"OpenVPN error occured"; + + NSError *error = [NSError ovpn_errorObjectForAdapterError:adapterError + description:description + message:message + fatal:YES]; + + [self.delegate openVPNAdapter:self handleError:error]; +} + +- (void)clientLogMessage:(NSString *)logMessage { + if ([self.delegate respondsToSelector:@selector(openVPNAdapter:handleLogMessage:)]) { + [self.delegate openVPNAdapter:self handleLogMessage:logMessage]; + } +} + +- (void)tick { + if ([self.delegate respondsToSelector:@selector(openVPNAdapterDidReceiveClockTick:)]) { + [self.delegate openVPNAdapterDidReceiveClockTick:self]; + } +} + +- (void)resetSettings { + _sessionName = nil; + _packetFlowBridge = nil; + _networkSettingsBuilder = nil; +} + +#pragma mark - - (void)dealloc { - delete _client; + delete _vpnClient; } @end diff --git a/OpenVPN Adapter/OpenVPNAdapterPacketFlow.h b/OpenVPN Adapter/OpenVPNAdapterPacketFlow.h new file mode 100644 index 0000000..3f8b8db --- /dev/null +++ b/OpenVPN Adapter/OpenVPNAdapterPacketFlow.h @@ -0,0 +1,39 @@ +// +// OpenVPNAdapterPacketFlow.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 15.01.2018. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@protocol OpenVPNAdapterPacketFlow + +/** + Read IP packets from the TUN interface. + + @param completionHandler A block that is executed when some packets are read from the TUN interface. The packets that were + read are passed to this block in the packets array. The protocol numbers of the packets that were read are passed to this + block in the protocols array. Each packet has a protocol number in the corresponding index in the protocols array. The + protocol numbers are given in host byte order. Valid protocol numbers include PF_INET and PF_INET6. See /usr/include/sys/socket.h. + */ +- (void)readPacketsWithCompletionHandler:(void (^)(NSArray *packets, NSArray *protocols))completionHandler; + +/** + Write IP packets to the TUN interface + + @param packets An array of NSData objects containing the IP packets to the written. + @param protocols An array of NSNumber objects containing the protocol numbers (e.g. PF_INET or PF_INET6) of the IP packets + in packets in host byte order. + + @discussion The number of NSData objects in packets must be exactly equal to the number of NSNumber objects in protocols. + + @return YES on success, otherwise NO. + */ +- (BOOL)writePackets:(NSArray *)packets withProtocols:(NSArray *)protocols; + +@end + +NS_ASSUME_NONNULL_END diff --git a/OpenVPN Adapter/OpenVPNCertificate.h b/OpenVPN Adapter/OpenVPNCertificate.h index 4cbb7bd..fb1c7f1 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.h +++ b/OpenVPN Adapter/OpenVPNCertificate.h @@ -11,14 +11,14 @@ @interface OpenVPNCertificate : NSObject + (nullable OpenVPNCertificate *)certificateWithPEM:(nonnull NSData *)pemData - error:(out NSError * __nullable * __nullable)error; + error:(out NSError * _Nullable * _Nullable)error; + (nullable OpenVPNCertificate *)certificateWithDER:(nonnull NSData *)derData - error:(out NSError * __nullable * __nullable)error; + error:(out NSError * _Nullable * _Nullable)error; -- (nonnull instancetype) __unavailable init; +- (nonnull instancetype) init NS_UNAVAILABLE; -- (nullable NSData *)pemData:(out NSError * __nullable * __nullable)error; -- (nullable NSData *)derData:(out NSError * __nullable * __nullable)error; +- (nullable NSData *)pemData:(out NSError * _Nullable * _Nullable)error; +- (nullable NSData *)derData:(out NSError * _Nullable * _Nullable)error; @end diff --git a/OpenVPN Adapter/OpenVPNCertificate.m b/OpenVPN Adapter/OpenVPNCertificate.m index d7412b2..826792e 100644 --- a/OpenVPN Adapter/OpenVPNCertificate.m +++ b/OpenVPN Adapter/OpenVPNCertificate.m @@ -5,14 +5,13 @@ // Created by Sergey Abramchuk on 06.09.17. // // - -#import -#import - -#import "NSError+Message.h" -#import "OpenVPNError.h" #import "OpenVPNCertificate.h" +#include +#include + +#import "NSError+OpenVPNError.h" + @interface OpenVPNCertificate () @property (nonatomic, assign) mbedtls_x509_crt *crt; @@ -21,16 +20,6 @@ @implementation OpenVPNCertificate -- (instancetype)init -{ - self = [super init]; - if (self) { - self.crt = malloc(sizeof(mbedtls_x509_crt)); - mbedtls_x509_crt_init(self.crt); - } - return self; -} - + (OpenVPNCertificate *)certificateWithPEM:(NSData *)pemData error:(out NSError **)error { OpenVPNCertificate *certificate = [OpenVPNCertificate new]; @@ -39,11 +28,7 @@ int result = mbedtls_x509_crt_parse(certificate.crt, (const unsigned char *)pemString.UTF8String, pemData.length + 1); if (result < 0) { if (error) { - NSString *reason = [NSError reasonFromResult:result]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to read PEM data.", - NSLocalizedFailureReasonErrorKey: reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:result description:@"Failed to read PEM data"]; } return nil; @@ -58,11 +43,7 @@ int result = mbedtls_x509_crt_parse_der(certificate.crt, derData.bytes, derData.length); if (result < 0) { if (error) { - NSString *reason = [NSError reasonFromResult:result]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to read DER data.", - NSLocalizedFailureReasonErrorKey: reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:result description:@"Failed to read DER data"]; } return nil; @@ -71,6 +52,15 @@ return certificate; } +- (instancetype)init +{ + if (self = [super init]) { + _crt = malloc(sizeof(mbedtls_x509_crt)); + mbedtls_x509_crt_init(_crt); + } + return self; +} + - (NSData *)pemData:(out NSError **)error { NSString *header = @"-----BEGIN CERTIFICATE-----\n"; NSString *footer = @"-----END CERTIFICATE-----\n"; @@ -80,14 +70,11 @@ size_t output_length = 0; - int result = mbedtls_pem_write_buffer(header.UTF8String, footer.UTF8String, self.crt->raw.p, self.crt->raw.len, pem_buffer, buffer_length, &output_length); + int result = mbedtls_pem_write_buffer(header.UTF8String, footer.UTF8String, self.crt->raw.p, + self.crt->raw.len, pem_buffer, buffer_length, &output_length); if (result < 0) { if (error) { - NSString *reason = [NSError reasonFromResult:result]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to write PEM data.", - NSLocalizedFailureReasonErrorKey: reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:result description: @"Failed to write PEM data"]; } free(pem_buffer); @@ -103,11 +90,8 @@ - (NSData *)derData:(out NSError **)error { if (self.crt->raw.p == NULL || self.crt->raw.len == 0) { if (error) { - NSString *reason = [NSError reasonFromResult:MBEDTLS_ERR_X509_BAD_INPUT_DATA]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:MBEDTLS_ERR_X509_BAD_INPUT_DATA userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to write DER data.", - NSLocalizedFailureReasonErrorKey:reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:MBEDTLS_ERR_X509_BAD_INPUT_DATA + description: @"Failed to write DER data"]; } return nil; @@ -117,8 +101,8 @@ } - (void)dealloc { - mbedtls_x509_crt_free(self.crt); - free(self.crt); + mbedtls_x509_crt_free(_crt); + free(_crt); } @end diff --git a/OpenVPN Adapter/OpenVPNClient.h b/OpenVPN Adapter/OpenVPNClient.h new file mode 100644 index 0000000..4ffad1e --- /dev/null +++ b/OpenVPN Adapter/OpenVPNClient.h @@ -0,0 +1,101 @@ +// +// OpenVPNClient.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 11.01.2018. +// + +#import + +#include + +@class NEIPv4Route; +@class NEIPv6Route; +@class NEProxyServer; + +typedef NS_ENUM(NSInteger, OpenVPNProxyServerProtocol) { + OpenVPNProxyServerProtocolHTTP, + OpenVPNProxyServerProtocolHTTPS +}; + +NS_ASSUME_NONNULL_BEGIN + +@protocol OpenVPNClientDelegate +- (BOOL)setRemoteAddress:(NSString *)address; + +- (BOOL)addIPV4Address:(NSString *)address subnetMask:(NSString *)subnetMask gateway:(nullable NSString *)gateway; +- (BOOL)addIPV6Address:(NSString *)address prefixLength:(NSNumber *)prefixLength gateway:(nullable NSString *)gateway; + +- (BOOL)addIPV4Route:(NEIPv4Route *)route; +- (BOOL)addIPV6Route:(NEIPv6Route *)route; +- (BOOL)excludeIPV4Route:(NEIPv4Route *)route; +- (BOOL)excludeIPV6Route:(NEIPv6Route *)route; + +- (BOOL)addDNS:(NSString *)dns; +- (BOOL)addSearchDomain:(NSString *)domain; + +- (BOOL)setMTU:(NSNumber *)mtu; +- (BOOL)setSessionName:(NSString *)name; + +- (BOOL)addProxyBypassHost:(NSString *)bypassHost; +- (BOOL)setProxyAutoConfigurationURL:(NSURL *)url; +- (BOOL)setProxyServer:(NEProxyServer *)server protocol:(OpenVPNProxyServerProtocol)protocol; + +- (BOOL)establishTunnel; +- (CFSocketNativeHandle)socketHandle; + +- (void)clientEventName:(NSString *)eventName message:(nullable NSString *)message; +- (void)clientErrorName:(NSString *)errorName fatal:(BOOL)fatal message:(nullable NSString *)message; +- (void)clientLogMessage:(NSString *)logMessage; + +- (void)tick; + +- (void)resetSettings; +@end + +NS_ASSUME_NONNULL_END + +using namespace openvpn; + +class OpenVPNClient : public ClientAPI::OpenVPNClient { +public: + OpenVPNClient(id _Nonnull delegate); + + bool tun_builder_new() override; + + bool tun_builder_set_remote_address(const std::string& address, bool ipv6) override; + bool tun_builder_add_address(const std::string& address, int prefix_length, const std::string& gateway, + bool ipv6, bool net30) override; + bool tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) override; + bool tun_builder_add_route(const std::string& address, int prefix_length, int metric, bool ipv6) override; + bool tun_builder_exclude_route(const std::string& address, int prefix_length, int metric, bool ipv6) override; + bool tun_builder_add_dns_server(const std::string& address, bool ipv6) override; + bool tun_builder_add_search_domain(const std::string& domain) override; + bool tun_builder_set_mtu(int mtu) override; + bool tun_builder_set_session_name(const std::string& name) override; + bool tun_builder_add_proxy_bypass(const std::string& bypass_host) override; + bool tun_builder_set_proxy_auto_config_url(const std::string& urlString) override; + bool tun_builder_set_proxy_http(const std::string& host, int port) override; + bool tun_builder_set_proxy_https(const std::string& host, int port) override; + bool tun_builder_set_block_ipv6(bool block_ipv6) override; + + int tun_builder_establish() override; + bool tun_builder_persist() override; + void tun_builder_teardown(bool disconnect) override; + + bool socket_protect(int socket) override; + bool pause_on_connection_timeout() override; + + void external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) override; + void external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) override; + + void event(const ClientAPI::Event& event) override; + void log(const ClientAPI::LogInfo& log) override; + + void clock_tick() override; + +private: + __weak id _Nonnull delegate; +}; + + diff --git a/OpenVPN Adapter/OpenVPNClient.mm b/OpenVPN Adapter/OpenVPNClient.mm new file mode 100644 index 0000000..f33c9bd --- /dev/null +++ b/OpenVPN Adapter/OpenVPNClient.mm @@ -0,0 +1,173 @@ +// +// OpenVPNClient.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 11.01.2018. +// + +#define INVALID_SOCKET -1 + +#import "OpenVPNClient.h" + +#import + +#include + +using ::IPv4::Addr; + +OpenVPNClient::OpenVPNClient(id delegate): ClientAPI::OpenVPNClient() { + this->delegate = delegate; +} + +bool OpenVPNClient::tun_builder_new() { + [this->delegate resetSettings]; + return true; +} + +bool OpenVPNClient::tun_builder_set_remote_address(const std::string &address, bool ipv6) { + NSString *remoteAddress = [NSString stringWithUTF8String:address.c_str()]; + return [this->delegate setRemoteAddress:remoteAddress]; +} + +bool OpenVPNClient::tun_builder_add_address(const std::string &address, int prefix_length, const std::string &gateway, bool ipv6, bool net30) { + NSString *localAddress = [NSString stringWithUTF8String:address.c_str()]; + NSString *gatewayAddress = gateway.length() == 0 || gateway.compare("UNSPEC") == 0 ? nil : + [NSString stringWithUTF8String:gateway.c_str()]; + + if (ipv6) { + return [this->delegate addIPV6Address:localAddress prefixLength:@(prefix_length) gateway:gatewayAddress]; + } else { + NSString *subnetMask = [NSString stringWithUTF8String:Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; + return [this->delegate addIPV4Address:localAddress subnetMask:subnetMask gateway:gatewayAddress]; + } +} + +bool OpenVPNClient::tun_builder_reroute_gw(bool ipv4, bool ipv6, unsigned int flags) { + if (ipv4 && ![this->delegate addIPV4Route:[NEIPv4Route defaultRoute]]) { + return false; + } + + if (ipv6 && ![this->delegate addIPV6Route:[NEIPv6Route defaultRoute]]) { + return false; + } + + return true; +} + +bool OpenVPNClient::tun_builder_add_route(const std::string& address, int prefix_length, int metric, bool ipv6) { + NSString *routeAddress = [NSString stringWithUTF8String:address.c_str()]; + + if (ipv6) { + NEIPv6Route *route = [[NEIPv6Route alloc] initWithDestinationAddress:routeAddress networkPrefixLength:@(prefix_length)]; + return [this->delegate addIPV6Route:route]; + } else { + NSString *subnetMask = [NSString stringWithUTF8String:Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; + NEIPv4Route *route = [[NEIPv4Route alloc] initWithDestinationAddress:routeAddress subnetMask:subnetMask]; + return [this->delegate addIPV4Route:route]; + } +} + +bool OpenVPNClient::tun_builder_exclude_route(const std::string& address, int prefix_length, int metric, bool ipv6) { + NSString *routeAddress = [NSString stringWithUTF8String:address.c_str()]; + + if (ipv6) { + NEIPv6Route *route = [[NEIPv6Route alloc] initWithDestinationAddress:routeAddress networkPrefixLength:@(prefix_length)]; + return [this->delegate excludeIPV6Route:route]; + } else { + NSString *subnetMask = [NSString stringWithUTF8String:Addr::netmask_from_prefix_len(prefix_length).to_string().c_str()]; + NEIPv4Route *route = [[NEIPv4Route alloc] initWithDestinationAddress:routeAddress subnetMask:subnetMask]; + return [this->delegate excludeIPV4Route:route]; + } +} + +bool OpenVPNClient::tun_builder_add_dns_server(const std::string& address, bool ipv6) { + NSString *dns = [NSString stringWithUTF8String:address.c_str()]; + return [this->delegate addDNS:dns]; +} + +bool OpenVPNClient::tun_builder_add_search_domain(const std::string& domain) { + NSString *searchDomain = [NSString stringWithUTF8String:domain.c_str()]; + return [this->delegate addSearchDomain:searchDomain]; +} + +bool OpenVPNClient::tun_builder_set_mtu(int mtu) { + return [this->delegate setMTU:@(mtu)]; +} + +bool OpenVPNClient::tun_builder_set_session_name(const std::string& name) { + NSString *sessionName = [NSString stringWithUTF8String:name.c_str()]; + return [this->delegate setSessionName:sessionName]; +} + +bool OpenVPNClient::tun_builder_add_proxy_bypass(const std::string& bypass_host) { + NSString *bypassHost = [NSString stringWithUTF8String:bypass_host.c_str()]; + return [this->delegate addProxyBypassHost:bypassHost]; +} + +bool OpenVPNClient::tun_builder_set_proxy_auto_config_url(const std::string& url) { + NSURL *configURL = [[NSURL alloc] initWithString:[NSString stringWithUTF8String:url.c_str()]]; + if (configURL) { + return [this->delegate setProxyAutoConfigurationURL:configURL]; + } else { + return false; + } +} + +bool OpenVPNClient::tun_builder_set_proxy_http(const std::string& host, int port) { + NSString *proxyHost = [NSString stringWithUTF8String:host.c_str()]; + NEProxyServer *proxyServer = [[NEProxyServer alloc] initWithAddress:proxyHost port:port]; + return [this->delegate setProxyServer:proxyServer protocol:OpenVPNProxyServerProtocolHTTP]; +} + +bool OpenVPNClient::tun_builder_set_proxy_https(const std::string& host, int port) { + NSString *proxyHost = [NSString stringWithUTF8String:host.c_str()]; + NEProxyServer *proxyServer = [[NEProxyServer alloc] initWithAddress:proxyHost port:port]; + return [this->delegate setProxyServer:proxyServer protocol:OpenVPNProxyServerProtocolHTTPS]; +} + +bool OpenVPNClient::tun_builder_set_block_ipv6(bool block_ipv6) { + return block_ipv6; +} + +int OpenVPNClient::tun_builder_establish() { + return [this->delegate establishTunnel] ? [this->delegate socketHandle] : INVALID_SOCKET; +} + +bool OpenVPNClient::tun_builder_persist() { + return true; +} + +void OpenVPNClient::tun_builder_teardown(bool disconnect) { + [this->delegate resetSettings]; +} + +bool OpenVPNClient::socket_protect(int socket) { + return true; +} + +bool OpenVPNClient::pause_on_connection_timeout() { + return false; +} + +void OpenVPNClient::external_pki_cert_request(ClientAPI::ExternalPKICertRequest& certreq) { } +void OpenVPNClient::external_pki_sign_request(ClientAPI::ExternalPKISignRequest& signreq) { } + +void OpenVPNClient::event(const ClientAPI::Event& ev) { + NSString *name = [NSString stringWithUTF8String:ev.name.c_str()]; + NSString *message = [NSString stringWithUTF8String:ev.info.c_str()]; + + if (ev.error) { + [this->delegate clientErrorName:name fatal:ev.fatal message:message.length ? message : nil]; + } else { + [this->delegate clientEventName:name message:message.length ? message : nil]; + } +} + +void OpenVPNClient::log(const ClientAPI::LogInfo& log) { + NSString *logMessage = [NSString stringWithUTF8String:log.text.c_str()]; + [this->delegate clientLogMessage:logMessage]; +} + +void OpenVPNClient::clock_tick() { + [this->delegate tick]; +} diff --git a/OpenVPN Adapter/OpenVPNConfiguration+Internal.h b/OpenVPN Adapter/OpenVPNConfiguration+Internal.h index 62d01cf..4bd4030 100644 --- a/OpenVPN Adapter/OpenVPNConfiguration+Internal.h +++ b/OpenVPN Adapter/OpenVPNConfiguration+Internal.h @@ -6,29 +6,33 @@ // // -#import - #import "OpenVPNConfiguration.h" +#include + using namespace openvpn; +NS_ASSUME_NONNULL_BEGIN + @interface OpenVPNConfiguration (Internal) @property (readonly) ClientAPI::Config config; + (OpenVPNTransportProtocol)getTransportProtocolFromValue:(nullable NSString *)value; -+ (nonnull NSString *)getValueFromTransportProtocol:(OpenVPNTransportProtocol)protocol; ++ (NSString *)getValueFromTransportProtocol:(OpenVPNTransportProtocol)protocol; + (OpenVPNIPv6Preference)getIPv6PreferenceFromValue:(nullable NSString *)value; -+ (nonnull NSString *)getValueFromIPv6Preference:(OpenVPNIPv6Preference)preference; ++ (NSString *)getValueFromIPv6Preference:(OpenVPNIPv6Preference)preference; + (OpenVPNCompressionMode)getCompressionModeFromValue:(nullable NSString *)value; -+ (nonnull NSString *)getValueFromCompressionMode:(OpenVPNCompressionMode)compressionMode; ++ (NSString *)getValueFromCompressionMode:(OpenVPNCompressionMode)compressionMode; + (OpenVPNMinTLSVersion)getMinTLSFromValue:(nullable NSString *)value; -+ (nonnull NSString *)getValueFromMinTLS:(OpenVPNMinTLSVersion)minTLS; ++ (NSString *)getValueFromMinTLS:(OpenVPNMinTLSVersion)minTLS; + (OpenVPNTLSCertProfile)getTLSCertProfileFromValue:(nullable NSString *)value; -+ (nonnull NSString *)getValueFromTLSCertProfile:(OpenVPNTLSCertProfile)tlsCertProfile; ++ (NSString *)getValueFromTLSCertProfile:(OpenVPNTLSCertProfile)tlsCertProfile; @end + +NS_ASSUME_NONNULL_END diff --git a/OpenVPN Adapter/OpenVPNConfiguration.h b/OpenVPN Adapter/OpenVPNConfiguration.h index 617593f..4ef4934 100644 --- a/OpenVPN Adapter/OpenVPNConfiguration.h +++ b/OpenVPN Adapter/OpenVPNConfiguration.h @@ -8,11 +8,11 @@ #import -#import "OpenVPNTransportProtocol.h" -#import "OpenVPNIPv6Preference.h" -#import "OpenVPNCompressionMode.h" -#import "OpenVPNMinTLSVersion.h" -#import "OpenVPNTLSCertProfile.h" +typedef NS_ENUM(NSInteger, OpenVPNTransportProtocol); +typedef NS_ENUM(NSInteger, OpenVPNIPv6Preference); +typedef NS_ENUM(NSInteger, OpenVPNCompressionMode); +typedef NS_ENUM(NSInteger, OpenVPNMinTLSVersion); +typedef NS_ENUM(NSInteger, OpenVPNTLSCertProfile); /** Class used to pass configuration diff --git a/OpenVPN Adapter/OpenVPNConfiguration.mm b/OpenVPN Adapter/OpenVPNConfiguration.mm index da8c049..3d5dc6b 100644 --- a/OpenVPN Adapter/OpenVPNConfiguration.mm +++ b/OpenVPN Adapter/OpenVPNConfiguration.mm @@ -6,8 +6,15 @@ // // +#import "OpenVPNConfiguration.h" #import "OpenVPNConfiguration+Internal.h" +#import "OpenVPNTransportProtocol.h" +#import "OpenVPNIPv6Preference.h" +#import "OpenVPNCompressionMode.h" +#import "OpenVPNMinTLSVersion.h" +#import "OpenVPNTLSCertProfile.h" + using namespace openvpn; NSString *const OpenVPNTransportProtocolUDPValue = @"udp"; @@ -212,7 +219,7 @@ NSString *const OpenVPNTLSCertProfileDefaultValue = @"default"; } - (void)setFileContent:(NSData *)fileContent { - _config.content = fileContent ? std::string((const char *)fileContent.bytes) : ""; + _config.content = fileContent.length ? std::string((const char *)fileContent.bytes) : ""; } - (NSDictionary *)settings { @@ -494,7 +501,7 @@ NSString *const OpenVPNTLSCertProfileDefaultValue = @"default"; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { - if ((self = [self init])) { + if (self = [self init]) { self.fileContent = [aDecoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(fileContent))]; self.settings = [aDecoder decodeObjectOfClass:[NSDictionary class] forKey:NSStringFromSelector(@selector(settings))]; self.guiVersion = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(guiVersion))]; diff --git a/OpenVPN Adapter/OpenVPNConnectionInfo+Internal.h b/OpenVPN Adapter/OpenVPNConnectionInfo+Internal.h index 829beea..c03fb21 100644 --- a/OpenVPN Adapter/OpenVPNConnectionInfo+Internal.h +++ b/OpenVPN Adapter/OpenVPNConnectionInfo+Internal.h @@ -6,10 +6,10 @@ // // -#import - #import "OpenVPNConnectionInfo.h" +#include + using namespace openvpn; @interface OpenVPNConnectionInfo (Internal) diff --git a/OpenVPN Adapter/OpenVPNConnectionInfo.mm b/OpenVPN Adapter/OpenVPNConnectionInfo.mm index e3eb83e..d4900a6 100644 --- a/OpenVPN Adapter/OpenVPNConnectionInfo.mm +++ b/OpenVPN Adapter/OpenVPNConnectionInfo.mm @@ -28,7 +28,7 @@ using namespace openvpn; @implementation OpenVPNConnectionInfo - (instancetype)initWithConnectionInfo:(ClientAPI::ConnectionInfo)info { - if ((self = [super init])) { + if (self = [super init]) { self.user = !info.user.empty() ? [NSString stringWithUTF8String:info.user.c_str()] : nil; self.serverHost = !info.serverHost.empty() ? [NSString stringWithUTF8String:info.serverHost.c_str()] : nil; self.serverPort = !info.serverPort.empty() ? [NSString stringWithUTF8String:info.serverPort.c_str()] : nil; @@ -75,7 +75,7 @@ using namespace openvpn; } - (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { - if ((self = [self init])) { + if (self = [self init]) { self.user = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(user))]; self.serverHost = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(serverHost))]; self.serverPort = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(serverPort))]; diff --git a/OpenVPN Adapter/OpenVPNCredentials+Internal.h b/OpenVPN Adapter/OpenVPNCredentials+Internal.h index bd6cb6f..8cb7831 100644 --- a/OpenVPN Adapter/OpenVPNCredentials+Internal.h +++ b/OpenVPN Adapter/OpenVPNCredentials+Internal.h @@ -5,11 +5,10 @@ // Created by Sergey Abramchuk on 24.04.17. // // - -#import - #import "OpenVPNCredentials.h" +#include + using namespace openvpn; @interface OpenVPNCredentials (Internal) diff --git a/OpenVPN Adapter/OpenVPNCredentials.mm b/OpenVPN Adapter/OpenVPNCredentials.mm index 5c7bbf6..4748785 100644 --- a/OpenVPN Adapter/OpenVPNCredentials.mm +++ b/OpenVPN Adapter/OpenVPNCredentials.mm @@ -52,7 +52,8 @@ using namespace openvpn; } - (NSString *)dynamicChallengeCookie { - return !_credentials.dynamicChallengeCookie.empty() ? [NSString stringWithUTF8String:_credentials.dynamicChallengeCookie.c_str()] : nil; + return !_credentials.dynamicChallengeCookie.empty() ? + [NSString stringWithUTF8String:_credentials.dynamicChallengeCookie.c_str()] : nil; } - (void)setDynamicChallengeCookie:(NSString *)dynamicChallengeCookie { diff --git a/OpenVPN Adapter/OpenVPNError.h b/OpenVPN Adapter/OpenVPNError.h index d054a0a..02a3331 100644 --- a/OpenVPN Adapter/OpenVPNError.h +++ b/OpenVPN Adapter/OpenVPNError.h @@ -8,11 +8,15 @@ #import -FOUNDATION_EXPORT NSString * __nonnull const OpenVPNAdapterErrorDomain; -FOUNDATION_EXPORT NSString * __nonnull const OpenVPNIdentityErrorDomain; +NS_ASSUME_NONNULL_BEGIN -FOUNDATION_EXPORT NSString * __nonnull const OpenVPNAdapterErrorFatalKey; -FOUNDATION_EXPORT NSString * __nonnull const OpenVPNAdapterErrorMessageKey; +FOUNDATION_EXPORT NSString *const OpenVPNAdapterErrorDomain; +FOUNDATION_EXPORT NSString *const OpenVPNIdentityErrorDomain; + +FOUNDATION_EXPORT NSString *const OpenVPNAdapterErrorFatalKey; +FOUNDATION_EXPORT NSString *const OpenVPNAdapterErrorMessageKey; + +NS_ASSUME_NONNULL_END /** OpenVPN error codes @@ -32,6 +36,7 @@ typedef NS_ERROR_ENUM(OpenVPNAdapterErrorDomain, OpenVPNAdapterError) { OpenVPNAdapterErrorBadSrcAddr, OpenVPNAdapterErrorCompressError, OpenVPNAdapterErrorResolveError, + OpenVPNAdapterErrorSocketSetupFailed, OpenVPNAdapterErrorSocketProtectError, OpenVPNAdapterErrorTUNReadError, OpenVPNAdapterErrorTUNWriteError, diff --git a/OpenVPN Adapter/OpenVPNError.m b/OpenVPN Adapter/OpenVPNError.m index b7785b8..447494e 100644 --- a/OpenVPN Adapter/OpenVPNError.m +++ b/OpenVPN Adapter/OpenVPNError.m @@ -8,8 +8,8 @@ #import -NSString * const OpenVPNAdapterErrorDomain = @"me.ss-abramchuk.openvpn-adapter.error-domain"; -NSString * const OpenVPNIdentityErrorDomain = @"me.ss-abramchuk.openvpn-identity.error-domain"; +NSString *const OpenVPNAdapterErrorDomain = @"me.ss-abramchuk.openvpn-adapter.error-domain"; +NSString *const OpenVPNIdentityErrorDomain = @"me.ss-abramchuk.openvpn-identity.error-domain"; -NSString * const OpenVPNAdapterErrorFatalKey = @"me.ss-abramchuk.openvpn-adapter.error-key.fatal"; -NSString * const OpenVPNAdapterErrorMessageKey = @"me.ss-abramchuk.openvpn-adapter.error-key.message"; +NSString *const OpenVPNAdapterErrorFatalKey = @"me.ss-abramchuk.openvpn-adapter.error-key.fatal"; +NSString *const OpenVPNAdapterErrorMessageKey = @"me.ss-abramchuk.openvpn-adapter.error-key.message"; diff --git a/OpenVPN Adapter/OpenVPNInterfaceStats+Internal.h b/OpenVPN Adapter/OpenVPNInterfaceStats+Internal.h index 9c58773..735e605 100644 --- a/OpenVPN Adapter/OpenVPNInterfaceStats+Internal.h +++ b/OpenVPN Adapter/OpenVPNInterfaceStats+Internal.h @@ -6,10 +6,10 @@ // // -#import - #import "OpenVPNInterfaceStats.h" +#include + using namespace openvpn; @interface OpenVPNInterfaceStats (Internal) diff --git a/OpenVPN Adapter/OpenVPNInterfaceStats.mm b/OpenVPN Adapter/OpenVPNInterfaceStats.mm index 003b2d9..2f9333a 100644 --- a/OpenVPN Adapter/OpenVPNInterfaceStats.mm +++ b/OpenVPN Adapter/OpenVPNInterfaceStats.mm @@ -21,7 +21,7 @@ @implementation OpenVPNInterfaceStats - (instancetype)initWithInterfaceStats:(ClientAPI::InterfaceStats)stats { - if ((self = [super init])) { + if (self = [super init]) { self.bytesIn = stats.bytesIn; self.bytesOut = stats.bytesOut; self.packetsIn = stats.packetsIn; @@ -53,7 +53,7 @@ } - (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { - if ((self = [self init])) { + if (self = [self init]) { self.bytesIn = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(bytesIn))]; self.bytesOut = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(bytesOut))]; self.packetsIn = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(packetsIn))]; diff --git a/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.h b/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.h index afe083d..63903d2 100644 --- a/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.h +++ b/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.h @@ -11,8 +11,8 @@ NS_ASSUME_NONNULL_BEGIN @class NEIPv4Route; @class NEIPv6Route; -@class NEPacketTunnelNetworkSettings; @class NEProxyServer; +@class NEPacketTunnelNetworkSettings; @interface OpenVPNNetworkSettingsBuilder : NSObject @@ -45,7 +45,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic) BOOL httpsProxyServerEnabled; @property (nonatomic, copy, nullable) NEProxyServer *httpsProxyServer; -@property (nonatomic, readonly, nullable) NEPacketTunnelNetworkSettings *networkSettings; +- (nullable NEPacketTunnelNetworkSettings *)networkSettings; @end diff --git a/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.m b/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.m index c9292d4..11a31f1 100644 --- a/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.m +++ b/OpenVPN Adapter/OpenVPNNetworkSettingsBuilder.m @@ -5,21 +5,27 @@ // Created by Jonathan Downing on 12/10/2017. // -#import #import "OpenVPNNetworkSettingsBuilder.h" +#import + @interface OpenVPNNetworkSettingsBuilder () + @property (nonatomic) NSMutableArray *ipv4LocalAddresses; @property (nonatomic) NSMutableArray *ipv4SubnetMasks; @property (nonatomic) NSMutableArray *ipv4IncludedRoutes; @property (nonatomic) NSMutableArray *ipv4ExcludedRoutes; + @property (nonatomic) NSMutableArray *ipv6LocalAddresses; @property (nonatomic) NSMutableArray *ipv6NetworkPrefixLengths; @property (nonatomic) NSMutableArray *ipv6IncludedRoutes; @property (nonatomic) NSMutableArray *ipv6ExcludedRoutes; + @property (nonatomic) NSMutableArray *dnsServers; @property (nonatomic) NSMutableArray *searchDomains; + @property (nonatomic) NSMutableArray *proxyExceptionList; + @end @implementation OpenVPNNetworkSettingsBuilder @@ -27,23 +33,27 @@ #pragma mark - NEPacketTunnelNetworkSettings Generation - (NEPacketTunnelNetworkSettings *)networkSettings { - if (!self.remoteAddress.length) { - return nil; - } + if (!self.remoteAddress.length) { return nil; } NEPacketTunnelNetworkSettings *networkSettings = [[NEPacketTunnelNetworkSettings alloc] initWithTunnelRemoteAddress:self.remoteAddress]; if (self.ipv4LocalAddresses.count && (self.ipv4LocalAddresses.count == self.ipv4SubnetMasks.count)) { - NEIPv4Settings *ipv4Settings = [[NEIPv4Settings alloc] initWithAddresses:self.ipv4LocalAddresses subnetMasks:self.ipv4SubnetMasks]; + NEIPv4Settings *ipv4Settings = [[NEIPv4Settings alloc] initWithAddresses:self.ipv4LocalAddresses + subnetMasks:self.ipv4SubnetMasks]; + ipv4Settings.includedRoutes = self.ipv4IncludedRoutes; ipv4Settings.excludedRoutes = self.ipv4ExcludedRoutes; + networkSettings.IPv4Settings = ipv4Settings; } if (self.ipv6LocalAddresses.count && (self.ipv6LocalAddresses.count == self.ipv6NetworkPrefixLengths.count)) { - NEIPv6Settings *ipv6Settings = [[NEIPv6Settings alloc] initWithAddresses:self.ipv6LocalAddresses networkPrefixLengths:self.ipv6NetworkPrefixLengths]; + NEIPv6Settings *ipv6Settings = [[NEIPv6Settings alloc] initWithAddresses:self.ipv6LocalAddresses + networkPrefixLengths:self.ipv6NetworkPrefixLengths]; + ipv6Settings.includedRoutes = self.ipv6IncludedRoutes; ipv6Settings.excludedRoutes = self.ipv6ExcludedRoutes; + networkSettings.IPv6Settings = ipv6Settings; } @@ -55,6 +65,7 @@ if (self.autoProxyConfigurationEnabled || self.httpProxyServerEnabled || self.httpsProxyServerEnabled) { NEProxySettings *proxySettings = [[NEProxySettings alloc] init]; + proxySettings.autoProxyConfigurationEnabled = self.autoProxyConfigurationEnabled; proxySettings.proxyAutoConfigurationURL = self.proxyAutoConfigurationURL; proxySettings.exceptionList = self.proxyExceptionList; @@ -62,6 +73,7 @@ proxySettings.HTTPEnabled = self.httpProxyServerEnabled; proxySettings.HTTPSServer = self.httpsProxyServer; proxySettings.HTTPSEnabled = self.httpsProxyServerEnabled; + networkSettings.proxySettings = proxySettings; } @@ -73,79 +85,57 @@ #pragma mark - Lazy Initializers - (NSMutableArray *)ipv4LocalAddresses { - if (!_ipv4LocalAddresses) { - _ipv4LocalAddresses = [[NSMutableArray alloc] init]; - } + if (!_ipv4LocalAddresses) { _ipv4LocalAddresses = [[NSMutableArray alloc] init]; } return _ipv4LocalAddresses; } - (NSMutableArray *)ipv4SubnetMasks { - if (!_ipv4SubnetMasks) { - _ipv4SubnetMasks = [[NSMutableArray alloc] init]; - } + if (!_ipv4SubnetMasks) { _ipv4SubnetMasks = [[NSMutableArray alloc] init]; } return _ipv4SubnetMasks; } - (NSMutableArray *)ipv4IncludedRoutes { - if (!_ipv4IncludedRoutes) { - _ipv4IncludedRoutes = [[NSMutableArray alloc] init]; - } + if (!_ipv4IncludedRoutes) { _ipv4IncludedRoutes = [[NSMutableArray alloc] init]; } return _ipv4IncludedRoutes; } - (NSMutableArray *)ipv4ExcludedRoutes { - if (!_ipv4ExcludedRoutes) { - _ipv4ExcludedRoutes = [[NSMutableArray alloc] init]; - } + if (!_ipv4ExcludedRoutes) { _ipv4ExcludedRoutes = [[NSMutableArray alloc] init]; } return _ipv4ExcludedRoutes; } - (NSMutableArray *)ipv6LocalAddresses { - if (!_ipv6LocalAddresses) { - _ipv6LocalAddresses = [[NSMutableArray alloc] init]; - } + if (!_ipv6LocalAddresses) { _ipv6LocalAddresses = [[NSMutableArray alloc] init]; } return _ipv6LocalAddresses; } - (NSMutableArray *)ipv6NetworkPrefixLengths { - if (!_ipv6NetworkPrefixLengths) { - _ipv6NetworkPrefixLengths = [[NSMutableArray alloc] init]; - } + if (!_ipv6NetworkPrefixLengths) { _ipv6NetworkPrefixLengths = [[NSMutableArray alloc] init]; } return _ipv6NetworkPrefixLengths; } - (NSMutableArray *)ipv6IncludedRoutes { - if (!_ipv6IncludedRoutes) { - _ipv6IncludedRoutes = [[NSMutableArray alloc] init]; - } + if (!_ipv6IncludedRoutes) { _ipv6IncludedRoutes = [[NSMutableArray alloc] init]; } return _ipv6IncludedRoutes; } - (NSMutableArray *)ipv6ExcludedRoutes { - if (!_ipv6ExcludedRoutes) { - _ipv6ExcludedRoutes = [[NSMutableArray alloc] init]; - } + if (!_ipv6ExcludedRoutes) { _ipv6ExcludedRoutes = [[NSMutableArray alloc] init]; } return _ipv6ExcludedRoutes; } - (NSMutableArray *)dnsServers { - if (!_dnsServers) { - _dnsServers = [[NSMutableArray alloc] init]; - } + if (!_dnsServers) { _dnsServers = [[NSMutableArray alloc] init]; } return _dnsServers; } - (NSMutableArray *)searchDomains { - if (!_searchDomains) { - _searchDomains = [[NSMutableArray alloc] init]; - } + if (!_searchDomains) { _searchDomains = [[NSMutableArray alloc] init]; } return _searchDomains; } - (NSMutableArray *)proxyExceptionList { - if (!_proxyExceptionList) { - _proxyExceptionList = [[NSMutableArray alloc] init]; - } + if (!_proxyExceptionList) { _proxyExceptionList = [[NSMutableArray alloc] init]; } return _proxyExceptionList; } diff --git a/OpenVPN Adapter/OpenVPNPacket.h b/OpenVPN Adapter/OpenVPNPacket.h new file mode 100644 index 0000000..5b0bacc --- /dev/null +++ b/OpenVPN Adapter/OpenVPNPacket.h @@ -0,0 +1,35 @@ +// +// OpenVPNPacket.h +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 15.01.2018. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface OpenVPNPacket : NSObject + +/** + Data that can be written to the VPN socket. + */ +@property (readonly, nonatomic) NSData *vpnData; + +/** + Data that can be written to the packet flow. + */ +@property (readonly, nonatomic) NSData *packetFlowData; + +/** + Protocol number (e.g. PF_INET or PF_INET6) of the packet. + */ +@property (readonly, nonatomic) NSNumber *protocolFamily; + +- (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithVPNData:(NSData *)data NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithPacketFlowData:(NSData *)data protocolFamily:(NSNumber *)protocolFamily NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/OpenVPN Adapter/OpenVPNPacket.mm b/OpenVPN Adapter/OpenVPNPacket.mm new file mode 100644 index 0000000..0846016 --- /dev/null +++ b/OpenVPN Adapter/OpenVPNPacket.mm @@ -0,0 +1,95 @@ +// +// OpenVPNPacket.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 15.01.2018. +// + +#import "OpenVPNPacket.h" + +#include + +#include + +@interface OpenVPNPacket () { + NSData *_data; + NSNumber *_protocolFamily; +} + +@end + +@implementation OpenVPNPacket + +- (instancetype)initWithVPNData:(NSData *)data { + if (self = [super init]) { +#if TARGET_OS_IPHONE + // Get network protocol family from data prefix + NSUInteger prefix_size = sizeof(uint32_t); + + uint32_t protocol = PF_UNSPEC; + [data getBytes:&protocol length:prefix_size]; + protocol = CFSwapInt32BigToHost(protocol); + + NSRange range = NSMakeRange(prefix_size, data.length - prefix_size); + NSData *packetData = [data subdataWithRange:range]; +#else + // Get network protocol family from packet header + uint8_t header = 0; + [data getBytes:&header length:1]; + + uint32_t protocol = PF_UNSPEC; + + uint32_t version = openvpn::IPHeader::version(header); + switch (version) { + case 4: + protocol = PF_INET; + break; + case 6: + protocol = PF_INET6; + break; + } + + NSData *packetData = data; +#endif + + _data = packetData; + _protocolFamily = @(protocol); + } + return self; +} + +- (instancetype)initWithPacketFlowData:(NSData *)data protocolFamily:(NSNumber *)protocolFamily { + if (self = [super init]) { + _data = data; + _protocolFamily = protocolFamily; + } + return self; +} + +- (NSData *)vpnData { +#if TARGET_OS_IPHONE + // Prepend data with network protocol. It should be done because OpenVPN on iOS uses uint32_t prefixes containing network + // protocol. + uint32_t prefix = CFSwapInt32HostToBig(_protocolFamily.unsignedIntegerValue); + NSUInteger prefix_size = sizeof(uint32_t); + + NSMutableData *data = [NSMutableData dataWithCapacity:prefix_size + _data.length]; + + [data appendBytes:&prefix length:prefix_size]; + [data appendData:_data]; + + return data; +#else + return _data; +#endif +} + +- (NSData *)packetFlowData { + return _data; +} + +- (NSNumber *)protocolFamily { + return _protocolFamily; +} + +@end diff --git a/OpenVPN Adapter/OpenVPNPacketFlowBridge.h b/OpenVPN Adapter/OpenVPNPacketFlowBridge.h index 438e881..7f77b42 100644 --- a/OpenVPN Adapter/OpenVPNPacketFlowBridge.h +++ b/OpenVPN Adapter/OpenVPNPacketFlowBridge.h @@ -3,21 +3,25 @@ // OpenVPN Adapter // // Created by Jonathan Downing on 12/10/2017. +// Modified by Sergey Abramchuk on 15/01/2018. // #import NS_ASSUME_NONNULL_BEGIN -@class NEPacketTunnelFlow; +@protocol OpenVPNAdapterPacketFlow; -@interface OpenVPNPacketFlowBridge : NSObject +@interface OpenVPNPacketFlowBridge: NSObject -@property (nonatomic, readonly) CFSocketNativeHandle socketHandle; +@property (nonatomic, readonly) CFSocketRef openVPNSocket; +@property (nonatomic, readonly) CFSocketRef packetFlowSocket; - (instancetype)init NS_UNAVAILABLE; +- (instancetype)initWithPacketFlow:(id)packetFlow NS_DESIGNATED_INITIALIZER; -- (nullable instancetype)initWithPacketFlow:(NEPacketTunnelFlow *)packetFlow NS_DESIGNATED_INITIALIZER; +- (BOOL)configureSocketsWithError:(NSError **)error; +- (void)startReading; @end diff --git a/OpenVPN Adapter/OpenVPNPacketFlowBridge.mm b/OpenVPN Adapter/OpenVPNPacketFlowBridge.mm index e4efd36..4c0cc9b 100644 --- a/OpenVPN Adapter/OpenVPNPacketFlowBridge.mm +++ b/OpenVPN Adapter/OpenVPNPacketFlowBridge.mm @@ -3,65 +3,85 @@ // OpenVPN Adapter // // Created by Jonathan Downing on 12/10/2017. +// Modified by Sergey Abramchuk on 15/01/2018. // -#import -#import #import "OpenVPNPacketFlowBridge.h" -@interface OpenVPNPacketFlowBridge () { - CFSocketRef _openVPNClientSocket; - CFSocketRef _packetFlowSocket; -} +#include +#include -@property (nonatomic) NEPacketTunnelFlow *packetFlow; +#import "OpenVPNError.h" +#import "OpenVPNPacket.h" +#import "OpenVPNAdapterPacketFlow.h" + +@interface OpenVPNPacketFlowBridge () + +@property (nonatomic) id packetFlow; @end @implementation OpenVPNPacketFlowBridge -- (CFSocketNativeHandle)socketHandle { - return CFSocketGetNative(_openVPNClientSocket); -} - -- (instancetype)initWithPacketFlow:(NEPacketTunnelFlow *)packetFlow { - if ((self = [super init])) { - self.packetFlow = packetFlow; - - if (![self configureSockets]) { - return nil; - } - - [self readPacketFlowPackets]; +- (instancetype)initWithPacketFlow:(id)packetFlow { + if (self = [super init]) { + _packetFlow = packetFlow; } return self; } -static inline void PacketFlowSocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *adapter) { - [(__bridge OpenVPNPacketFlowBridge *)adapter writeDataToPacketFlow:(__bridge NSData *)data]; +#pragma mark - Sockets Configuration + +static void SocketCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *obj) { + if (type != kCFSocketDataCallBack) { return; } + + OpenVPNPacket *packet = [[OpenVPNPacket alloc] initWithVPNData:(__bridge NSData *)data]; + + OpenVPNPacketFlowBridge *bridge = (__bridge OpenVPNPacketFlowBridge *)obj; + [bridge writePackets:@[packet] toPacketFlow:bridge.packetFlow]; } -- (BOOL)configureSockets { +- (BOOL)configureSocketsWithError:(NSError **)error { int sockets[2]; if (socketpair(PF_LOCAL, SOCK_DGRAM, IPPROTO_IP, sockets) == -1) { - NSLog(@"Failed to create a pair of connected sockets: %@", [NSString stringWithUTF8String:strerror(errno)]); + if (error) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: @"Failed to create a pair of connected sockets", + NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], + OpenVPNAdapterErrorFatalKey: @(YES) + }; + + *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain + code:OpenVPNAdapterErrorSocketSetupFailed + userInfo:userInfo]; + } + return NO; } CFSocketContext socketCtxt = {0, (__bridge void *)self, NULL, NULL, NULL}; - _packetFlowSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[0], kCFSocketDataCallBack, PacketFlowSocketCallback, &socketCtxt); - _openVPNClientSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[1], kCFSocketNoCallBack, NULL, NULL); + _packetFlowSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[0], kCFSocketDataCallBack, + SocketCallback, &socketCtxt); + _openVPNSocket = CFSocketCreateWithNative(kCFAllocatorDefault, sockets[1], kCFSocketNoCallBack, NULL, NULL); - if (!(_packetFlowSocket && _openVPNClientSocket)) { - NSLog(@"Failed to create core foundation sockets from native sockets"); + if (!(_packetFlowSocket && _openVPNSocket)) { + if (error) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: @"Failed to create core foundation sockets from native sockets", + OpenVPNAdapterErrorFatalKey: @(YES) + }; + + *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain + code:OpenVPNAdapterErrorSocketSetupFailed + userInfo:userInfo]; + } + return NO; } - if (!([self configureOptionsForSocket:_packetFlowSocket] && [self configureOptionsForSocket:_openVPNClientSocket])) { - NSLog(@"Failed to configure buffer size of the sockets"); - return NO; - } + if (!([self configureOptionsForSocket:_packetFlowSocket error:error] && + [self configureOptionsForSocket:_openVPNSocket error:error])) { return NO; } CFRunLoopSourceRef packetFlowSocketSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, _packetFlowSocket, 0); CFRunLoopAddSource(CFRunLoopGetMain(), packetFlowSocketSource, kCFRunLoopDefaultMode); @@ -70,104 +90,88 @@ static inline void PacketFlowSocketCallback(CFSocketRef socket, CFSocketCallBack return YES; } -- (BOOL)configureOptionsForSocket:(CFSocketRef)socket { +- (BOOL)configureOptionsForSocket:(CFSocketRef)socket error:(NSError **)error { CFSocketNativeHandle socketHandle = CFSocketGetNative(socket); int buf_value = 65536; socklen_t buf_len = sizeof(buf_value); if (setsockopt(socketHandle, SOL_SOCKET, SO_RCVBUF, &buf_value, buf_len) == -1) { - NSLog(@"Failed to setup buffer size for input: %@", [NSString stringWithUTF8String:strerror(errno)]); + if (error) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: @"Failed to setup buffer size for input", + NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], + OpenVPNAdapterErrorFatalKey: @(YES) + }; + + *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain + code:OpenVPNAdapterErrorSocketSetupFailed + userInfo:userInfo]; + } + return NO; } if (setsockopt(socketHandle, SOL_SOCKET, SO_SNDBUF, &buf_value, buf_len) == -1) { - NSLog(@"Failed to setup buffer size for output: %@", [NSString stringWithUTF8String:strerror(errno)]); + if (error) { + NSDictionary *userInfo = @{ + NSLocalizedDescriptionKey: @"Failed to setup buffer size for output", + NSLocalizedFailureReasonErrorKey: [NSString stringWithUTF8String:strerror(errno)], + OpenVPNAdapterErrorFatalKey: @(YES) + }; + + *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain + code:OpenVPNAdapterErrorSocketSetupFailed + userInfo:userInfo]; + } + return NO; } return YES; } -- (void)readPacketFlowPackets { +- (void)startReading { __weak typeof(self) weakSelf = self; - [self.packetFlow readPacketObjectsWithCompletionHandler:^(NSArray * _Nonnull packets) { + + [self.packetFlow readPacketsWithCompletionHandler:^(NSArray *packets, NSArray *protocols) { __strong typeof(self) self = weakSelf; - - [self writeVPNPacketObjects:packets]; - [self readPacketFlowPackets]; + + [self writePackets:packets protocols:protocols toSocket:self.packetFlowSocket]; + [self startReading]; }]; } -- (void)writeVPNPacketObjects:(NSArray *)packets { - for (NEPacket *packet in packets) { - CFSocketSendData(_packetFlowSocket, NULL, (CFDataRef)[self dataFromPacket:packet], 0.05); - } +#pragma mark - TUN -> VPN + +- (void)writePackets:(NSArray *)packets protocols:(NSArray *)protocols toSocket:(CFSocketRef)socket { + [packets enumerateObjectsUsingBlock:^(NSData *data, NSUInteger idx, BOOL *stop) { + NSNumber *protocolFamily = protocols[idx]; + OpenVPNPacket *packet = [[OpenVPNPacket alloc] initWithPacketFlowData:data protocolFamily:protocolFamily]; + + CFSocketSendData(socket, NULL, (CFDataRef)packet.vpnData, 0.05); + }]; } -- (NSData *)dataFromPacket:(NEPacket *)packet { -#if TARGET_OS_IPHONE - // Prepend data with network protocol. It should be done because OpenVPN on iOS uses uint32_t prefixes containing network protocol. - uint32_t prefix = CFSwapInt32HostToBig((uint32_t)packet.protocolFamily); - NSMutableData *data = [[NSMutableData alloc] initWithCapacity:sizeof(prefix) + packet.data.length]; - [data appendBytes:&prefix length:sizeof(prefix)]; - [data appendData:packet.data]; - return data; -#else - return packet.data; -#endif +#pragma mark - VPN -> TUN + +- (void)writePackets:(NSArray *)packets toPacketFlow:(id)packetFlow { + NSMutableArray *flowPackets = [[NSMutableArray alloc] init]; + NSMutableArray *protocols = [[NSMutableArray alloc] init]; + + [packets enumerateObjectsUsingBlock:^(OpenVPNPacket * _Nonnull packet, NSUInteger idx, BOOL * _Nonnull stop) { + [flowPackets addObject:packet.packetFlowData]; + [protocols addObject:packet.protocolFamily]; + }]; + + [packetFlow writePackets:flowPackets withProtocols:protocols]; } -- (NEPacket *)packetFromData:(NSData *)data { -#if TARGET_OS_IPHONE - // Get network protocol from prefix - NSUInteger prefixSize = sizeof(uint32_t); - - if (data.length < prefixSize) { - return nil; - } - - uint32_t protocol = PF_UNSPEC; - [data getBytes:&protocol length:prefixSize]; - protocol = CFSwapInt32BigToHost(protocol); - - NSRange range = NSMakeRange(prefixSize, data.length - prefixSize); - NSData *packetData = [data subdataWithRange:range]; -#else - // Get network protocol from header - uint8_t header = 0; - [data getBytes:&header length:1]; - - uint32_t version = openvpn::IPHeader::version(header); - sa_family_t protocol = [self protocolFamilyForVersion:version]; - - NSData *packetData = data; -#endif - - return [[NEPacket alloc] initWithData:packetData protocolFamily:protocol]; -} - -- (void)writeDataToPacketFlow:(NSData *)data { - NEPacket *packet = [self packetFromData:data]; - - if (!packet) { - return; - } - - [self.packetFlow writePacketObjects:@[packet]]; -} - -- (sa_family_t)protocolFamilyForVersion:(uint32_t)version { - switch (version) { - case 4: return PF_INET; - case 6: return PF_INET6; - default: return PF_UNSPEC; - } -} +#pragma mark - - (void)dealloc { - CFSocketInvalidate(_openVPNClientSocket); - CFRelease(_openVPNClientSocket); + CFSocketInvalidate(_openVPNSocket); + CFRelease(_openVPNSocket); CFSocketInvalidate(_packetFlowSocket); CFRelease(_packetFlowSocket); diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.h b/OpenVPN Adapter/OpenVPNPrivateKey.h index 81ca5f6..61f8727 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.h +++ b/OpenVPN Adapter/OpenVPNPrivateKey.h @@ -8,24 +8,24 @@ #import -#import "OpenVPNKeyType.h" +typedef NS_ENUM(NSInteger, OpenVPNKeyType); @interface OpenVPNPrivateKey : NSObject + (nullable OpenVPNPrivateKey *)keyWithPEM:(nonnull NSData *)pemData password:(nullable NSString *)password - error:(out NSError * __nullable * __nullable)error; + error:(out NSError * _Nullable * _Nullable)error; + (nullable OpenVPNPrivateKey *)keyWithDER:(nonnull NSData *)derData password:(nullable NSString *)password - error:(out NSError * __nullable * __nullable)error; + error:(out NSError * _Nullable * _Nullable)error; -- (nonnull instancetype) __unavailable init; +- (nonnull instancetype) init NS_UNAVAILABLE; @property (nonatomic, readonly) NSInteger size; @property (nonatomic, readonly) OpenVPNKeyType type; -- (nullable NSData *)pemData:(out NSError * __nullable * __nullable)error; -- (nullable NSData *)derData:(out NSError * __nullable * __nullable)error; +- (nullable NSData *)pemData:(out NSError * _Nullable * _Nullable)error; +- (nullable NSData *)derData:(out NSError * _Nullable * _Nullable)error; @end diff --git a/OpenVPN Adapter/OpenVPNPrivateKey.m b/OpenVPN Adapter/OpenVPNPrivateKey.m index 96100d8..a941878 100644 --- a/OpenVPN Adapter/OpenVPNPrivateKey.m +++ b/OpenVPN Adapter/OpenVPNPrivateKey.m @@ -6,12 +6,13 @@ // // -#import - -#import "NSError+Message.h" -#import "OpenVPNError.h" #import "OpenVPNPrivateKey.h" +#include + +#import "OpenVPNKeyType.h" +#import "NSError+OpenVPNError.h" + @interface OpenVPNPrivateKey () @property (nonatomic, assign) mbedtls_pk_context *ctx; @@ -20,23 +21,6 @@ @implementation OpenVPNPrivateKey -- (instancetype)init { - self = [super init]; - if (self) { - self.ctx = malloc(sizeof(mbedtls_pk_context)); - mbedtls_pk_init(self.ctx); - } - return self; -} - -- (NSInteger)size { - return mbedtls_pk_get_bitlen(self.ctx); -} - -- (OpenVPNKeyType)type { - return (OpenVPNKeyType)mbedtls_pk_get_type(self.ctx); -} - + (nullable OpenVPNPrivateKey *)keyWithPEM:(NSData *)pemData password:(NSString *)password error:(out NSError **)error { OpenVPNPrivateKey *key = [OpenVPNPrivateKey new]; @@ -45,14 +29,12 @@ size_t pem_length = strlen(pemString.UTF8String) + 1; size_t password_length = password != nil ? strlen(password.UTF8String) : 0; - int result = mbedtls_pk_parse_key(key.ctx, (const unsigned char *)pemString.UTF8String, pem_length, (const unsigned char *)password.UTF8String, password_length); + int result = mbedtls_pk_parse_key(key.ctx, (const unsigned char *)pemString.UTF8String, + pem_length, (const unsigned char *)password.UTF8String, password_length); + if (result < 0) { if (error) { - NSString *reason = [NSError reasonFromResult:result]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to read PEM data.", - NSLocalizedFailureReasonErrorKey: reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:result description:@"Failed to read PEM data"]; } return nil; @@ -66,14 +48,12 @@ size_t password_length = password != nil ? strlen(password.UTF8String) : 0; - int result = mbedtls_pk_parse_key(key.ctx, derData.bytes, derData.length, (const unsigned char *)password.UTF8String, password_length); + int result = mbedtls_pk_parse_key(key.ctx, derData.bytes, + derData.length, (const unsigned char *)password.UTF8String, password_length); + if (result < 0) { if (error) { - NSString *reason = [NSError reasonFromResult:result]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to read DER data.", - NSLocalizedFailureReasonErrorKey: reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:result description:@"Failed to read DER data"]; } return nil; @@ -82,6 +62,22 @@ return key; } +- (instancetype)init { + if (self = [super init]) { + _ctx = malloc(sizeof(mbedtls_pk_context)); + mbedtls_pk_init(_ctx); + } + return self; +} + +- (NSInteger)size { + return mbedtls_pk_get_bitlen(self.ctx); +} + +- (OpenVPNKeyType)type { + return (OpenVPNKeyType)mbedtls_pk_get_type(self.ctx); +} + - (NSData *)pemData:(out NSError **)error { size_t buffer_length = mbedtls_pk_get_len(self.ctx) * 10; unsigned char *pem_buffer = malloc(buffer_length); @@ -89,18 +85,15 @@ int result = mbedtls_pk_write_key_pem(self.ctx, pem_buffer, buffer_length); if (result < 0) { if (error) { - NSString *reason = [NSError reasonFromResult:result]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to write PEM data.", - NSLocalizedFailureReasonErrorKey: reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:result description:@"Failed to write PEM data"]; } free(pem_buffer); return nil; } - NSData *pemData = [[NSString stringWithCString:(const char *)pem_buffer encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]; + NSData *pemData = [[NSString stringWithCString:(const char *)pem_buffer + encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding]; free(pem_buffer); return pemData; @@ -113,11 +106,7 @@ int result = mbedtls_pk_write_key_der(self.ctx, der_buffer, buffer_length); if (result < 0) { if (error) { - NSString *reason = [NSError reasonFromResult:result]; - *error = [NSError errorWithDomain:OpenVPNIdentityErrorDomain code:result userInfo:@{ - NSLocalizedDescriptionKey: @"Failed to write DER data.", - NSLocalizedFailureReasonErrorKey: reason - }]; + *error = [NSError ovpn_errorObjectForMbedTLSError:result description:@"Failed to write DER data"]; } free(der_buffer); @@ -134,8 +123,8 @@ } - (void)dealloc { - mbedtls_pk_free(self.ctx); - free(self.ctx); + mbedtls_pk_free(_ctx); + free(_ctx); } @end diff --git a/OpenVPN Adapter/OpenVPNProperties+Internal.h b/OpenVPN Adapter/OpenVPNProperties+Internal.h index c4f0ea9..d6bee9a 100644 --- a/OpenVPN Adapter/OpenVPNProperties+Internal.h +++ b/OpenVPN Adapter/OpenVPNProperties+Internal.h @@ -6,10 +6,10 @@ // // -#import - #import "OpenVPNProperties.h" +#include + using namespace openvpn; @interface OpenVPNProperties (Internal) diff --git a/OpenVPN Adapter/OpenVPNProperties.h b/OpenVPN Adapter/OpenVPNProperties.h index 1182d2d..8a63975 100644 --- a/OpenVPN Adapter/OpenVPNProperties.h +++ b/OpenVPN Adapter/OpenVPNProperties.h @@ -8,8 +8,7 @@ #import -#import "OpenVPNTransportProtocol.h" - +typedef NS_ENUM(NSInteger, OpenVPNTransportProtocol); @class OpenVPNServerEntry; @interface OpenVPNProperties : NSObject @@ -47,7 +46,7 @@ /** YES if this profile requires a private key password */ -@property (readonly, nonatomic) BOOL privateKeyPasswordRequired; +@property (readonly, nonatomic, getter=isPrivateKeyPasswordRequired) BOOL privateKeyPasswordRequired; /** YES if user is allowed to save authentication password in UI @@ -74,6 +73,6 @@ */ @property (nullable, readonly, nonatomic) NSArray *servers; -- (nonnull instancetype) __unavailable init; +- (nonnull instancetype) init NS_UNAVAILABLE; @end diff --git a/OpenVPN Adapter/OpenVPNProperties.mm b/OpenVPN Adapter/OpenVPNProperties.mm index 2dca5e5..8a6cdf9 100644 --- a/OpenVPN Adapter/OpenVPNProperties.mm +++ b/OpenVPN Adapter/OpenVPNProperties.mm @@ -6,20 +6,20 @@ // // -#import +#import "OpenVPNProperties.h" +#import "OpenVPNProperties+Internal.h" + +#include #import "OpenVPNConfiguration+Internal.h" #import "OpenVPNServerEntry+Internal.h" -#import "OpenVPNProperties.h" -#import "OpenVPNProperties+Internal.h" using namespace openvpn; @implementation OpenVPNProperties - (instancetype)initWithEvalConfig:(ClientAPI::EvalConfig)eval { - self = [super init]; - if (self) { + if (self = [super init]) { _username = !eval.userlockedUsername.empty() ? [NSString stringWithUTF8String:eval.userlockedUsername.c_str()] : nil; _profileName = !eval.profileName.empty() ? [NSString stringWithUTF8String:eval.profileName.c_str()] : nil; @@ -44,6 +44,7 @@ using namespace openvpn; _remoteProto = [OpenVPNConfiguration getTransportProtocolFromValue:currentProto]; _servers = nil; + if (!eval.serverList.empty()) { NSMutableArray *servers = [NSMutableArray new]; diff --git a/OpenVPN Adapter/OpenVPNReachability+Internal.h b/OpenVPN Adapter/OpenVPNReachability+Internal.h index d38837a..a13c3bd 100644 --- a/OpenVPN Adapter/OpenVPNReachability+Internal.h +++ b/OpenVPN Adapter/OpenVPNReachability+Internal.h @@ -6,7 +6,6 @@ // // -#import "OpenVPNReachabilityTracker.h" #import "OpenVPNReachability.h" @interface OpenVPNReachability (Internal) diff --git a/OpenVPN Adapter/OpenVPNReachability.h b/OpenVPN Adapter/OpenVPNReachability.h index 8ba4632..bb56cad 100644 --- a/OpenVPN Adapter/OpenVPNReachability.h +++ b/OpenVPN Adapter/OpenVPNReachability.h @@ -7,11 +7,12 @@ // #import -#import "OpenVPNReachabilityStatus.h" + +typedef NS_ENUM(NSInteger, OpenVPNReachabilityStatus); @interface OpenVPNReachability : NSObject -@property (readonly, nonatomic) BOOL isTracking; +@property (readonly, nonatomic, getter=isTracking) BOOL tracking; @property (readonly, nonatomic) OpenVPNReachabilityStatus reachabilityStatus; - (nonnull instancetype)init; diff --git a/OpenVPN Adapter/OpenVPNReachability.mm b/OpenVPN Adapter/OpenVPNReachability.mm index 360da7b..02d8383 100644 --- a/OpenVPN Adapter/OpenVPNReachability.mm +++ b/OpenVPN Adapter/OpenVPNReachability.mm @@ -6,11 +6,14 @@ // // -#import - #import "OpenVPNReachability.h" #import "OpenVPNReachability+Internal.h" +#include + +#import "OpenVPNReachabilityTracker.h" +#import "OpenVPNReachabilityStatus.h" + @interface OpenVPNReachability () { BOOL _isTracking; } @@ -45,13 +48,12 @@ } } -- (nonnull instancetype)init { - self = [super init]; - if (self) { +- (instancetype)init { + if (self = [super init]) { _isTracking = NO; - self.tracker = new OpenVPNReachabilityTracker(true, false, (__bridge void *)self); - self.reachability = new Reachability(true, true); + _tracker = new OpenVPNReachabilityTracker(true, false, (__bridge void *)self); + _reachability = new Reachability(true, true); } return self; } @@ -77,8 +79,8 @@ } - (void)dealloc { - delete self.tracker; - delete self.reachability; + delete _tracker; + delete _reachability; } @end diff --git a/OpenVPN Adapter/OpenVPNReachabilityTracker.h b/OpenVPN Adapter/OpenVPNReachabilityTracker.h index 6ac0982..da61403 100644 --- a/OpenVPN Adapter/OpenVPNReachabilityTracker.h +++ b/OpenVPN Adapter/OpenVPNReachabilityTracker.h @@ -6,7 +6,7 @@ // // -#import +#include using namespace openvpn; diff --git a/OpenVPN Adapter/OpenVPNReachabilityTracker.mm b/OpenVPN Adapter/OpenVPNReachabilityTracker.mm index a84cb38..259bac4 100644 --- a/OpenVPN Adapter/OpenVPNReachabilityTracker.mm +++ b/OpenVPN Adapter/OpenVPNReachabilityTracker.mm @@ -6,10 +6,14 @@ // // -#import "OpenVPNReachability+Internal.h" #import "OpenVPNReachabilityTracker.h" -OpenVPNReachabilityTracker::OpenVPNReachabilityTracker(const bool enable_internet, const bool enable_wifi, void* handler) : ReachabilityTracker(enable_internet, enable_wifi) { +#import "OpenVPNReachability+Internal.h" +#import "OpenVPNReachabilityStatus.h" + +OpenVPNReachabilityTracker::OpenVPNReachabilityTracker(const bool enable_internet, const bool enable_wifi, void* handler) : + ReachabilityTracker(enable_internet, enable_wifi) +{ this->handler = handler; } diff --git a/OpenVPN Adapter/OpenVPNServerEntry+Internal.h b/OpenVPN Adapter/OpenVPNServerEntry+Internal.h index e8685f5..b4e44fe 100644 --- a/OpenVPN Adapter/OpenVPNServerEntry+Internal.h +++ b/OpenVPN Adapter/OpenVPNServerEntry+Internal.h @@ -6,10 +6,10 @@ // // -#import - #import "OpenVPNServerEntry.h" +#include + using namespace openvpn; @interface OpenVPNServerEntry (Internal) diff --git a/OpenVPN Adapter/OpenVPNServerEntry.h b/OpenVPN Adapter/OpenVPNServerEntry.h index 75ecb40..4898f52 100644 --- a/OpenVPN Adapter/OpenVPNServerEntry.h +++ b/OpenVPN Adapter/OpenVPNServerEntry.h @@ -13,6 +13,6 @@ @property (nullable, readonly, nonatomic) NSString *server; @property (nullable, readonly, nonatomic) NSString *friendlyName; -- (nonnull instancetype) __unavailable init; +- (nonnull instancetype) init NS_UNAVAILABLE; @end diff --git a/OpenVPN Adapter/OpenVPNServerEntry.mm b/OpenVPN Adapter/OpenVPNServerEntry.mm index b87e7d0..13f74d8 100644 --- a/OpenVPN Adapter/OpenVPNServerEntry.mm +++ b/OpenVPN Adapter/OpenVPNServerEntry.mm @@ -12,8 +12,7 @@ @implementation OpenVPNServerEntry - (instancetype)initWithServerEntry:(ClientAPI::ServerEntry)entry { - self = [super init]; - if (self) { + if (self = [super init]) { _server = !entry.server.empty() ? [NSString stringWithUTF8String:entry.server.c_str()] : nil; _friendlyName = !entry.friendlyName.empty() ? [NSString stringWithUTF8String:entry.friendlyName.c_str()] : nil; } diff --git a/OpenVPN Adapter/OpenVPNSessionToken+Internal.h b/OpenVPN Adapter/OpenVPNSessionToken+Internal.h index 667bf3b..b1c9026 100644 --- a/OpenVPN Adapter/OpenVPNSessionToken+Internal.h +++ b/OpenVPN Adapter/OpenVPNSessionToken+Internal.h @@ -6,10 +6,10 @@ // // -#import - #import "OpenVPNSessionToken.h" +#include + using namespace openvpn; @interface OpenVPNSessionToken (Internal) diff --git a/OpenVPN Adapter/OpenVPNSessionToken.mm b/OpenVPN Adapter/OpenVPNSessionToken.mm index 462ffb7..9d2f298 100644 --- a/OpenVPN Adapter/OpenVPNSessionToken.mm +++ b/OpenVPN Adapter/OpenVPNSessionToken.mm @@ -6,6 +6,7 @@ // // +#import "OpenVPNSessionToken.h" #import "OpenVPNSessionToken+Internal.h" using namespace openvpn; @@ -18,7 +19,7 @@ using namespace openvpn; @implementation OpenVPNSessionToken - (instancetype)initWithSessionToken:(ClientAPI::SessionToken)token { - if ((self = [super init])) { + if (self = [super init]) { self.username = !token.username.empty() ? [NSString stringWithUTF8String:token.username.c_str()] : nil; self.session = !token.session_id.empty() ? [NSString stringWithUTF8String:token.session_id.c_str()] : nil; } @@ -38,7 +39,7 @@ using namespace openvpn; } - (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { - if ((self = [self init])) { + if (self = [self init]) { self.username = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(username))]; self.session = [aDecoder decodeObjectOfClass:[NSString class] forKey:NSStringFromSelector(@selector(session))]; } diff --git a/OpenVPN Adapter/OpenVPNTransportStats+Internal.h b/OpenVPN Adapter/OpenVPNTransportStats+Internal.h index 974d694..df7e129 100644 --- a/OpenVPN Adapter/OpenVPNTransportStats+Internal.h +++ b/OpenVPN Adapter/OpenVPNTransportStats+Internal.h @@ -6,10 +6,10 @@ // // -#import - #import "OpenVPNTransportStats.h" +#include + using namespace openvpn; @interface OpenVPNTransportStats (Internal) diff --git a/OpenVPN Adapter/OpenVPNTransportStats.mm b/OpenVPN Adapter/OpenVPNTransportStats.mm index 4dc4ad7..2a7c554 100644 --- a/OpenVPN Adapter/OpenVPNTransportStats.mm +++ b/OpenVPN Adapter/OpenVPNTransportStats.mm @@ -6,6 +6,7 @@ // // +#import "OpenVPNTransportStats.h" #import "OpenVPNTransportStats+Internal.h" using namespace openvpn; @@ -21,12 +22,13 @@ using namespace openvpn; @implementation OpenVPNTransportStats - (instancetype)initWithTransportStats:(ClientAPI::TransportStats)stats { - if ((self = [self init])) { + if (self = [self init]) { self.bytesIn = stats.bytesIn; self.bytesOut = stats.bytesOut; self.packetsIn = stats.packetsIn; self.packetsOut = stats.packetsOut; - self.lastPacketReceived = stats.lastPacketReceived >= 0 ? [NSDate dateWithTimeIntervalSinceNow:stats.lastPacketReceived / -1024.0] : nil; + self.lastPacketReceived = stats.lastPacketReceived >= 0 ? + [NSDate dateWithTimeIntervalSinceNow:stats.lastPacketReceived / -1024.0] : nil; } return self; } @@ -50,12 +52,13 @@ using namespace openvpn; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { - if ((self = [super init])) { + if (self = [super init]) { self.bytesIn = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(bytesIn))]; self.bytesOut = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(bytesOut))]; self.packetsIn = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(packetsIn))]; self.packetsOut = [aDecoder decodeIntegerForKey:NSStringFromSelector(@selector(packetsOut))]; - self.lastPacketReceived = [aDecoder decodeObjectOfClass:[NSDate class] forKey:NSStringFromSelector(@selector(lastPacketReceived))]; + self.lastPacketReceived = [aDecoder decodeObjectOfClass:[NSDate class] + forKey:NSStringFromSelector(@selector(lastPacketReceived))]; } return self; } diff --git a/OpenVPN Adapter/Umbrella-Header.h b/OpenVPN Adapter/Umbrella-Header.h index 95b98cf..f195964 100644 --- a/OpenVPN Adapter/Umbrella-Header.h +++ b/OpenVPN Adapter/Umbrella-Header.h @@ -32,6 +32,7 @@ FOUNDATION_EXPORT const unsigned char OpenVPNAdapterVersionString[]; #import #import #import +#import #import #import #import diff --git a/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp b/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp index 3059d09..5aa4bf1 100644 --- a/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp +++ b/OpenVPN Adapter/Vendors/openvpn/client/ovpncli.hpp @@ -24,6 +24,9 @@ // The crux of the API is defined in OpenVPNClient (below) // and TunBuilderBase. +#ifndef OVPNCLI_HPP +#define OVPNCLI_HPP + #include #include #include @@ -600,3 +603,5 @@ namespace openvpn { } } + +#endif