From e4f7152cbab1d4391c3fa244400b3048f91ff2fa Mon Sep 17 00:00:00 2001 From: Sergey Abramchuk Date: Wed, 17 Jan 2018 16:49:44 +0300 Subject: [PATCH] Refactor generation of OpenVPN adapter errors --- OpenVPN Adapter.xcodeproj/project.pbxproj | 20 ++ OpenVPN Adapter/NSError+OpenVPNError.h | 27 ++ OpenVPN Adapter/NSError+OpenVPNError.m | 181 +++++++++++++ OpenVPN Adapter/OpenVPNAdapter.mm | 308 ++++------------------ 4 files changed, 283 insertions(+), 253 deletions(-) create mode 100644 OpenVPN Adapter/NSError+OpenVPNError.h create mode 100644 OpenVPN Adapter/NSError+OpenVPNError.m diff --git a/OpenVPN Adapter.xcodeproj/project.pbxproj b/OpenVPN Adapter.xcodeproj/project.pbxproj index 3dddfa9..1dffb4a 100644 --- a/OpenVPN Adapter.xcodeproj/project.pbxproj +++ b/OpenVPN Adapter.xcodeproj/project.pbxproj @@ -150,6 +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 */; }; + 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 */; }; 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 */; }; @@ -257,6 +261,8 @@ 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; }; + 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 = ""; }; 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 = ""; }; C9FD92181E9A667600374FC4 /* ovpncli.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ovpncli.hpp; path = Vendors/openvpn/client/ovpncli.hpp; sourceTree = ""; }; @@ -559,6 +565,15 @@ name = "Certificates and Keys"; sourceTree = ""; }; + C9E350C5200F70CA000820D9 /* Extensions */ = { + isa = PBXGroup; + children = ( + C9E350BF200F6EC0000820D9 /* NSError+OpenVPNError.h */, + C9E350C0200F6EC0000820D9 /* NSError+OpenVPNError.m */, + ); + name = Extensions; + sourceTree = ""; + }; C9E4401A1F6081FF001D7C41 /* Utils */ = { isa = PBXGroup; children = ( @@ -571,6 +586,7 @@ C9FF73B71EB7421600E995AC /* Helpers */ = { isa = PBXGroup; children = ( + C9E350C5200F70CA000820D9 /* Extensions */, C9E4401A1F6081FF001D7C41 /* Utils */, ); name = Helpers; @@ -618,6 +634,7 @@ 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 */, @@ -664,6 +681,7 @@ 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 */, @@ -878,6 +896,7 @@ 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 */, @@ -919,6 +938,7 @@ 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 */, diff --git a/OpenVPN Adapter/NSError+OpenVPNError.h b/OpenVPN Adapter/NSError+OpenVPNError.h new file mode 100644 index 0000000..d10acd7 --- /dev/null +++ b/OpenVPN Adapter/NSError+OpenVPNError.h @@ -0,0 +1,27 @@ +// +// 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 + +NS_ASSUME_NONNULL_END diff --git a/OpenVPN Adapter/NSError+OpenVPNError.m b/OpenVPN Adapter/NSError+OpenVPNError.m new file mode 100644 index 0000000..7281c36 --- /dev/null +++ b/OpenVPN Adapter/NSError+OpenVPNError.m @@ -0,0 +1,181 @@ +// +// NSError+OpenVPNError.m +// OpenVPN Adapter +// +// Created by Sergey Abramchuk on 17.01.2018. +// + +#import "NSError+OpenVPNError.h" + +#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 diff --git a/OpenVPN Adapter/OpenVPNAdapter.mm b/OpenVPN Adapter/OpenVPNAdapter.mm index b4a367b..951d505 100644 --- a/OpenVPN Adapter/OpenVPNAdapter.mm +++ b/OpenVPN Adapter/OpenVPNAdapter.mm @@ -15,16 +15,17 @@ #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 "OpenVPNInterfaceStats+Internal.h" -#import "OpenVPNNetworkSettingsBuilder.h" -#import "OpenVPNPacketFlowBridge.h" #import "OpenVPNProperties+Internal.h" #import "OpenVPNSessionToken+Internal.h" #import "OpenVPNTransportStats+Internal.h" -#import "OpenVPNAdapterPacketFlow.h" +#import "NSError+OpenVPNError.h" @interface OpenVPNAdapter () @@ -33,10 +34,6 @@ @property (nonatomic) OpenVPNPacketFlowBridge *packetFlowBridge; @property (nonatomic) OpenVPNNetworkSettingsBuilder *networkSettingsBuilder; -- (OpenVPNAdapterEvent)eventByName:(NSString *)eventName; -- (OpenVPNAdapterError)errorByName:(NSString *)errorName; -- (NSString *)reasonForError:(OpenVPNAdapterError)error; - @end @implementation OpenVPNAdapter @@ -55,23 +52,13 @@ if (eval.error) { if (error) { - NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ - NSLocalizedDescriptionKey: @"Failed to apply OpenVPN configuration", - OpenVPNAdapterErrorFatalKey: @YES - }]; - - NSString *errorReason = [self reasonForError:OpenVPNAdapterErrorConfigurationFailure]; - if (errorReason) { - userInfo[NSLocalizedFailureReasonErrorKey] = errorReason; - } - - NSString *message = [[NSString alloc] initWithUTF8String:eval.message.c_str()]; - if (message.length) { - userInfo[OpenVPNAdapterErrorMessageKey] = message; - } - - *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; } @@ -83,26 +70,11 @@ if (status.error) { if (error) { - OpenVPNAdapterError errorCode = !status.status.empty() ? - [self errorByName:[[NSString alloc] initWithUTF8String:status.status.c_str()]] : - OpenVPNAdapterErrorCredentialsFailure; - - NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ - NSLocalizedDescriptionKey: @"Failed to provide OpenVPN credentials", - OpenVPNAdapterErrorFatalKey: @YES - }]; - - NSString *errorReason = [self reasonForError:errorCode]; - if (errorReason) { - userInfo[NSLocalizedFailureReasonErrorKey] = errorReason; - } - - NSString *message = [[NSString alloc] initWithUTF8String:status.message.c_str()]; - if (message.length) { - userInfo[OpenVPNAdapterErrorMessageKey] = message; - } - - *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; @@ -143,36 +115,27 @@ - (void)handleConnectionStatus:(ClientAPI::Status)status { if (!status.error) { return; } - OpenVPNAdapterError errorCode = !status.status.empty() ? - [self errorByName:[[NSString alloc] initWithUTF8String:status.status.c_str()]] : OpenVPNAdapterErrorUnknown; + OpenVPNAdapterError adapterError = !status.status.empty() ? + [NSError ovpn_adapterErrorByName:[NSString stringWithUTF8String:status.status.c_str()]] : + OpenVPNAdapterErrorUnknown; - NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ - NSLocalizedDescriptionKey: @"Failed to establish connection with OpenVPN server", - OpenVPNAdapterErrorFatalKey: @YES - }]; - - NSString *errorReason = [self reasonForError:errorCode]; - if (errorReason) { - userInfo[NSLocalizedFailureReasonErrorKey] = errorReason; - } - - NSString *message = [[NSString alloc] initWithUTF8String:status.message.c_str()]; - if (message.length) { - userInfo[OpenVPNAdapterErrorMessageKey] = message; - } - - 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:OpenVPNClient::copyright().c_str()]; + return [NSString stringWithUTF8String:OpenVPNClient::copyright().c_str()]; } + (NSString *)platform { - return [[NSString alloc] initWithUTF8String:OpenVPNClient::platform().c_str()]; + return [NSString stringWithUTF8String:OpenVPNClient::platform().c_str()]; } - (OpenVPNConnectionInfo *)connectionInformation { @@ -193,178 +156,6 @@ return [[OpenVPNTransportStats alloc] initWithTransportStats:self.vpnClient->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 { - 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."; - } -} - #pragma mark - Lazy Initialization - (OpenVPNNetworkSettingsBuilder *)networkSettingsBuilder { @@ -503,28 +294,39 @@ } - (void)clientEventName:(NSString *)eventName message:(NSString *)message { - OpenVPNAdapterEvent eventIdentifier = [self eventByName:eventName]; - [self.delegate openVPNAdapter:self handleEvent:eventIdentifier message: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 errorCode = [self errorByName:errorName]; + OpenVPNAdapterError adapterError = [NSError ovpn_adapterErrorByName:errorName]; + NSString *description = fatal ? @"OpenVPN fatal error occured" : @"OpenVPN error occured"; - NSMutableDictionary *userInfo = [[NSMutableDictionary alloc] initWithDictionary:@{ - NSLocalizedDescriptionKey: fatal ? @"OpenVPN fatal error occured" : @"OpenVPN error occured", - OpenVPNAdapterErrorFatalKey: @(fatal) - }]; - - NSString *errorReason = [self reasonForError:errorCode]; - if (errorReason) { - userInfo[NSLocalizedFailureReasonErrorKey] = errorReason; - } - - if (message) { - userInfo[OpenVPNAdapterErrorMessageKey] = message; - } - - NSError *error = [NSError errorWithDomain:OpenVPNAdapterErrorDomain code:errorCode userInfo:userInfo]; + NSError *error = [NSError ovpn_errorObjectForAdapterError:adapterError + description:description + message:message + fatal:YES]; + [self.delegate openVPNAdapter:self handleError:error]; }