diff --git a/CHANGELOG.md b/CHANGELOG.md index d7d84e4..e9c66c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Support for `--compress stub-v2`. + ### Fixed - Return error in install completion handler. [#206](https://github.com/passepartoutvpn/tunnelkit/issues/206) diff --git a/TunnelKit/Sources/Protocols/OpenVPN/CompressionFraming.swift b/TunnelKit/Sources/Protocols/OpenVPN/CompressionFraming.swift index c21fa5a..85af696 100644 --- a/TunnelKit/Sources/Protocols/OpenVPN/CompressionFraming.swift +++ b/TunnelKit/Sources/Protocols/OpenVPN/CompressionFraming.swift @@ -39,6 +39,9 @@ extension OpenVPN { /// Framing compatible with 2.4 `compress`. case compress + + /// Framing compatible with 2.4 `compress` (version 2, e.g. stub-v2). + case compressV2 var native: CompressionFramingNative { guard let val = CompressionFramingNative(rawValue: rawValue) else { @@ -58,6 +61,9 @@ extension OpenVPN { case .compress: return "compress" + case .compressV2: + return "compress" + case .compLZO: return "comp-lzo" } diff --git a/TunnelKit/Sources/Protocols/OpenVPN/CompressionFramingNative.h b/TunnelKit/Sources/Protocols/OpenVPN/CompressionFramingNative.h index 04ad808..72cf10f 100644 --- a/TunnelKit/Sources/Protocols/OpenVPN/CompressionFramingNative.h +++ b/TunnelKit/Sources/Protocols/OpenVPN/CompressionFramingNative.h @@ -28,5 +28,6 @@ typedef NS_ENUM(NSInteger, CompressionFramingNative) { CompressionFramingNativeDisabled, CompressionFramingNativeCompLZO, - CompressionFramingNativeCompress + CompressionFramingNativeCompress, + CompressionFramingNativeCompressV2 }; diff --git a/TunnelKit/Sources/Protocols/OpenVPN/ConfigurationParser.swift b/TunnelKit/Sources/Protocols/OpenVPN/ConfigurationParser.swift index 5b5a748..fbf4293 100644 --- a/TunnelKit/Sources/Protocols/OpenVPN/ConfigurationParser.swift +++ b/TunnelKit/Sources/Protocols/OpenVPN/ConfigurationParser.swift @@ -412,7 +412,20 @@ extension OpenVPN { } } else { if let arg = $0.first { - optCompressionAlgorithm = (arg == "lzo") ? .LZO : .other + switch arg { + case "lzo": + optCompressionAlgorithm = .LZO + + case "stub": + optCompressionAlgorithm = .disabled + + case "stub-v2": + optCompressionFraming = .compressV2 + optCompressionAlgorithm = .disabled + + default: + optCompressionAlgorithm = .other + } } else { optCompressionAlgorithm = .disabled } diff --git a/TunnelKit/Sources/Protocols/OpenVPN/DataPath.m b/TunnelKit/Sources/Protocols/OpenVPN/DataPath.m index fdacbec..f797c41 100644 --- a/TunnelKit/Sources/Protocols/OpenVPN/DataPath.m +++ b/TunnelKit/Sources/Protocols/OpenVPN/DataPath.m @@ -195,12 +195,30 @@ *payloadOffset = 1; break; + case DataPacketV2Indicator: + if (compressionFraming == CompressionFramingNativeCompressV2) { + if (payload[1] != DataPacketV2Uncompressed) { + if (error) { + *error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression); + } + return NO; + } + *payloadOffset = 2; + } else { + *payloadOffset = 0; + *headerLength = 0; + } + break; + default: // @"Expected NO_COMPRESS (found %X != %X)", payload[0], DataPacketNoCompress); - if (error) { - *error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression); - } - return NO; +// if (error) { +// *error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression); +// } +// return NO; + *payloadOffset = 0; + *headerLength = 0; + break; } return YES; }; @@ -244,6 +262,25 @@ self.parsePayloadBlock = parseCompressedBlock; break; } + case CompressionFramingNativeCompressV2: { + self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) { + + // assume no compression (v2 algorithms unsupported) + + // prepend headers only in case of byte ambiguity + const uint8_t first = *(uint8_t *)payload.bytes; + if (first == DataPacketV2Indicator) { + *packetLengthOffset = 2; + packetDest[0] = DataPacketV2Indicator; + packetDest[1] = DataPacketV2Uncompressed; + } else { + *packetLengthOffset = 0; + } + memcpy(packetDest + *packetLengthOffset, payload.bytes, payload.length); + }; + self.parsePayloadBlock = parseCompressedBlock; + break; + } case CompressionFramingNativeCompLZO: { self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) { NSData *compressedPayload = [weakSelf.lzo compressedDataWithData:payload error:NULL]; diff --git a/TunnelKit/Sources/Protocols/OpenVPN/PacketMacros.h b/TunnelKit/Sources/Protocols/OpenVPN/PacketMacros.h index edcc5db..ebe552e 100644 --- a/TunnelKit/Sources/Protocols/OpenVPN/PacketMacros.h +++ b/TunnelKit/Sources/Protocols/OpenVPN/PacketMacros.h @@ -62,6 +62,9 @@ typedef NS_ENUM(uint8_t, PacketCode) { #define DataPacketNoCompressSwap 0xfb #define DataPacketLZOCompress 0x66 +#define DataPacketV2Indicator 0x50 +#define DataPacketV2Uncompressed 0x00 + extern const uint8_t DataPacketPingData[16]; static inline void PacketOpcodeGet(const uint8_t *from, PacketCode *_Nullable code, uint8_t *_Nullable key)