Merge pull request #70 from keeshux/support-compress-lzo
Support --compress lzo
This commit is contained in:
commit
76631a00fc
|
@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
### Added
|
||||
|
||||
- Support for legacy `--comp-lzo` compression. [#69](https://github.com/keeshux/tunnelkit/pull/69)
|
||||
- Support for newer `--compress lzo` option. [#70](https://github.com/keeshux/tunnelkit/pull/70)
|
||||
|
||||
## 1.4.3 (2019-03-18)
|
||||
|
||||
|
|
10
README.md
10
README.md
|
@ -29,11 +29,10 @@ The client is known to work with [OpenVPN®][openvpn] 2.3+ servers.
|
|||
- Authentication (`--tls-auth`)
|
||||
- Encryption (`--tls-crypt`)
|
||||
- [x] Compression framing
|
||||
- Disabled
|
||||
- Compress (2.4)
|
||||
- LZO (deprecated in 2.4)
|
||||
- Via `--comp-lzo` (deprecated in 2.4)
|
||||
- Via `--compress`
|
||||
- [x] Compression algorithms
|
||||
- LZO (`--comp-lzo` only)
|
||||
- LZO (via `--comp-lzo` or `--compress lzo`)
|
||||
- [x] Key renegotiation
|
||||
- [x] Replay protection (hardcoded window)
|
||||
|
||||
|
@ -46,8 +45,7 @@ TunnelKit can parse .ovpn configuration files. Below are a few limitations worth
|
|||
Unsupported:
|
||||
|
||||
- UDP fragmentation, i.e. `--fragment`
|
||||
- Compression
|
||||
- `--compress` other than empty
|
||||
- Compression via `--compress` other than empty or `lzo`
|
||||
- Proxy
|
||||
- External file references (inline `<block>` only)
|
||||
- Encrypted client certificate keys
|
||||
|
|
|
@ -37,9 +37,9 @@ Pod::Spec.new do |s|
|
|||
s.subspec "LZO" do |p|
|
||||
p.source_files = "TunnelKit/Sources/Core/LZO.h",
|
||||
"TunnelKit/Sources/Core/Errors.{h,m}",
|
||||
"TunnelKit/Sources/LZO/**/*.{h,m,c}"
|
||||
"TunnelKit/Sources/LZO/**/*lzo*.{h,m,c}"
|
||||
p.private_header_files = "TunnelKit/Sources/Core/LZO.h",
|
||||
"TunnelKit/Sources/LZO/lib/*.h"
|
||||
"TunnelKit/Sources/LZO/lib/*lzo*.h"
|
||||
p.pod_target_xcconfig = { "APPLICATION_EXTENSION_API_ONLY" => "YES" }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -315,11 +315,18 @@ public class ConfigurationParser {
|
|||
isHandled = true
|
||||
compressionFraming = .compress
|
||||
|
||||
if !LZOIsSupported() {
|
||||
guard $0.isEmpty else {
|
||||
compressionAlgorithm = .other
|
||||
unsupportedError = .unsupportedConfiguration(option: line)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if let arg = $0.first {
|
||||
compressionAlgorithm = (arg == "lzo") ? .LZO : .other
|
||||
} else {
|
||||
compressionAlgorithm = .disabled
|
||||
}
|
||||
}
|
||||
}
|
||||
Regex.keyDirection.enumerateArguments(in: line) {
|
||||
isHandled = true
|
||||
|
|
|
@ -117,7 +117,7 @@
|
|||
[self.decrypter setPeerId:peerId];
|
||||
[self setCompressionFraming:compressionFraming];
|
||||
|
||||
if (LZOIsSupported() && (compressionFraming == CompressionFramingNativeCompLZO) && (compressionAlgorithm == CompressionAlgorithmNativeLZO)) {
|
||||
if (LZOIsSupported() && (compressionAlgorithm == CompressionAlgorithmNativeLZO)) {
|
||||
self.lzo = LZOCreate();
|
||||
}
|
||||
}
|
||||
|
@ -168,6 +168,42 @@
|
|||
|
||||
- (void)setCompressionFraming:(CompressionFramingNative)compressionFraming
|
||||
{
|
||||
__weak DataPath *weakSelf = self;
|
||||
|
||||
DataPathParseBlock parseCompressedBlock = ^BOOL(uint8_t * _Nonnull payload, NSInteger * _Nonnull payloadOffset, uint8_t * _Nonnull compressionHeader, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength, NSError * _Nullable __autoreleasing * _Nullable error) {
|
||||
*compressionHeader = payload[0];
|
||||
*headerLength = 1;
|
||||
|
||||
switch (*compressionHeader) {
|
||||
case DataPacketNoCompress:
|
||||
*payloadOffset = 1;
|
||||
break;
|
||||
|
||||
case DataPacketNoCompressSwap:
|
||||
payload[0] = packet[packetLength - 1];
|
||||
*payloadOffset = 0;
|
||||
break;
|
||||
|
||||
case DataPacketLZOCompress:
|
||||
if (!weakSelf.lzo) { // compressed packet unexpected
|
||||
if (error) {
|
||||
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
*payloadOffset = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
// @"Expected NO_COMPRESS (found %X != %X)", payload[0], DataPacketNoCompress);
|
||||
if (error) {
|
||||
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
};
|
||||
|
||||
switch (compressionFraming) {
|
||||
case CompressionFramingNativeDisabled: {
|
||||
self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) {
|
||||
|
@ -184,27 +220,30 @@
|
|||
}
|
||||
case CompressionFramingNativeCompress: {
|
||||
self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) {
|
||||
NSData *compressedPayload = [weakSelf.lzo compressedDataWithData:payload error:NULL];
|
||||
if (compressedPayload) {
|
||||
packetDest[0] = DataPacketLZOCompress;
|
||||
*packetLengthOffset = 1 - (payload.length - compressedPayload.length);
|
||||
payload = compressedPayload;
|
||||
memcpy(packetDest + 1, payload.bytes, payload.length);
|
||||
} else {
|
||||
*packetLengthOffset = 1;
|
||||
|
||||
// do not byte swap if compression enabled
|
||||
if (weakSelf.lzo) {
|
||||
packetDest[0] = DataPacketNoCompress;
|
||||
memcpy(packetDest + 1, payload.bytes, payload.length);
|
||||
} else {
|
||||
memcpy(packetDest, payload.bytes, payload.length);
|
||||
packetDest[payload.length] = packetDest[0];
|
||||
packetDest[0] = DataPacketNoCompressSwap;
|
||||
*packetLengthOffset = 1;
|
||||
};
|
||||
self.parsePayloadBlock = ^BOOL(uint8_t * _Nonnull payload, NSInteger * _Nonnull payloadOffset, uint8_t * _Nonnull compressionHeader, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength, NSError * _Nullable __autoreleasing * _Nullable error) {
|
||||
*compressionHeader = payload[0];
|
||||
if (*compressionHeader != DataPacketNoCompressSwap) {
|
||||
// @"Expected NO_COMPRESS_SWAP (found %X != %X)", payload[0], DataPacketNoCompressSwap);
|
||||
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression);
|
||||
return NO;
|
||||
}
|
||||
payload[0] = packet[packetLength - 1];
|
||||
*payloadOffset = 0;
|
||||
*headerLength = 1;
|
||||
return YES;
|
||||
}
|
||||
};
|
||||
self.parsePayloadBlock = parseCompressedBlock;
|
||||
break;
|
||||
}
|
||||
case CompressionFramingNativeCompLZO: {
|
||||
__weak DataPath *weakSelf = self;
|
||||
self.assemblePayloadBlock = ^(uint8_t * packetDest, NSInteger * packetLengthOffset, NSData * payload) {
|
||||
NSData *compressedPayload = [weakSelf.lzo compressedDataWithData:payload error:NULL];
|
||||
if (compressedPayload) {
|
||||
|
@ -217,32 +256,7 @@
|
|||
}
|
||||
memcpy(packetDest + 1, payload.bytes, payload.length);
|
||||
};
|
||||
self.parsePayloadBlock = ^BOOL(uint8_t * _Nonnull payload, NSInteger * _Nonnull payloadOffset, uint8_t * _Nonnull compressionHeader, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength, NSError * _Nullable __autoreleasing * _Nullable error) {
|
||||
*compressionHeader = payload[0];
|
||||
switch (*compressionHeader) {
|
||||
case DataPacketNoCompress:
|
||||
break;
|
||||
|
||||
case DataPacketLZOCompress:
|
||||
if (!LZOIsSupported() || !weakSelf.lzo) { // compressed packet unexpected
|
||||
if (error) {
|
||||
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// @"Expected NO_COMPRESS (found %X != %X)", payload[0], DataPacketNoCompress);
|
||||
if (error) {
|
||||
*error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression);
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
*payloadOffset = 1;
|
||||
*headerLength = 1;
|
||||
return YES;
|
||||
};
|
||||
self.parsePayloadBlock = parseCompressedBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -395,18 +395,20 @@ extension SessionProxy {
|
|||
switch $0[0] {
|
||||
case "comp-lzo":
|
||||
compressionFraming = .compLZO
|
||||
if !(($0.count == 2) && ($0[1] == "no")) {
|
||||
compressionAlgorithm = .LZO
|
||||
} else {
|
||||
if ($0.count == 2) && ($0[1] == "no") {
|
||||
compressionAlgorithm = .disabled
|
||||
} else {
|
||||
compressionAlgorithm = .LZO
|
||||
}
|
||||
|
||||
case "compress":
|
||||
compressionFraming = .compress
|
||||
if $0.count > 1 {
|
||||
compressionAlgorithm = .other
|
||||
} else {
|
||||
if $0.count == 1 {
|
||||
compressionAlgorithm = .disabled
|
||||
} else if ($0.count == 2) && ($0[1] == "lzo") {
|
||||
compressionAlgorithm = .LZO
|
||||
} else {
|
||||
compressionAlgorithm = .other
|
||||
}
|
||||
|
||||
default:
|
||||
|
|
|
@ -912,20 +912,20 @@ public class SessionProxy {
|
|||
reply = optionalReply
|
||||
log.debug("Received PUSH_REPLY: \"\(reply.maskedDescription)\"")
|
||||
|
||||
if let framing = reply.compressionFraming, let compression = reply.compressionAlgorithm, compression != .disabled {
|
||||
switch framing {
|
||||
case .compress:
|
||||
log.error("Server has new compression enabled and this is currently unsupported (\(framing))")
|
||||
throw SessionError.serverCompression
|
||||
if let framing = reply.compressionFraming, let compression = reply.compressionAlgorithm {
|
||||
switch compression {
|
||||
case .disabled:
|
||||
break
|
||||
|
||||
case .compLZO:
|
||||
case .LZO:
|
||||
if !LZOIsSupported() {
|
||||
log.error("Server has legacy LZO compression enabled and this was not built into the library (\(framing))")
|
||||
log.error("Server has LZO compression enabled and this was not built into the library (framing=\(framing))")
|
||||
throw SessionError.serverCompression
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
case .other:
|
||||
log.error("Server has non-LZO compression enabled and this is currently unsupported (framing=\(framing))")
|
||||
throw SessionError.serverCompression
|
||||
}
|
||||
}
|
||||
} catch let e {
|
||||
|
|
Loading…
Reference in New Issue