diff --git a/CHANGELOG.md b/CHANGELOG.md index bc0b50b..7a379aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Shut down if server pushes a compressed data packet. + ## 1.4.1 (2019-02-25) ### Added diff --git a/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift b/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift index 4d11b5b..abe0f98 100644 --- a/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift +++ b/TunnelKit/Sources/AppExtension/TunnelKitProvider.swift @@ -586,6 +586,9 @@ extension TunnelKitProvider { case .dataPathOverflow, .dataPathPeerIdMismatch: return .unexpectedReply + + case .dataPathCompression: + return .serverCompression } } else if let se = error as? SessionError { switch se { diff --git a/TunnelKit/Sources/Core/CryptoAEAD.m b/TunnelKit/Sources/Core/CryptoAEAD.m index 8208d65..8bba503 100644 --- a/TunnelKit/Sources/Core/CryptoAEAD.m +++ b/TunnelKit/Sources/Core/CryptoAEAD.m @@ -346,7 +346,7 @@ static const NSInteger CryptoAEADTagLength = 16; return YES; } -- (const uint8_t *)parsePayloadWithBlock:(DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength +- (const uint8_t *)parsePayloadWithBlock:(DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError * _Nullable __autoreleasing * _Nullable)error { uint8_t *payload = packetBytes; *length = packetLength - (int)(payload - packetBytes); @@ -356,7 +356,9 @@ static const NSInteger CryptoAEADTagLength = 16; NSInteger payloadOffset; NSInteger payloadHeaderLength; - block(payload, &payloadOffset, &payloadHeaderLength, packetBytes, packetLength); + if (!block(payload, &payloadOffset, &payloadHeaderLength, packetBytes, packetLength, error)) { + return NULL; + } *length -= payloadHeaderLength; return payload + payloadOffset; } diff --git a/TunnelKit/Sources/Core/CryptoCBC.m b/TunnelKit/Sources/Core/CryptoCBC.m index d6e5acb..9e27c5f 100644 --- a/TunnelKit/Sources/Core/CryptoCBC.m +++ b/TunnelKit/Sources/Core/CryptoCBC.m @@ -368,7 +368,7 @@ const NSInteger CryptoCBCMaxHMACLength = 100; return YES; } -- (const uint8_t *)parsePayloadWithBlock:(DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength +- (const uint8_t *)parsePayloadWithBlock:(DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError * _Nullable __autoreleasing * _Nullable)error { uint8_t *payload = packetBytes; payload += sizeof(uint32_t); // packet id @@ -379,7 +379,9 @@ const NSInteger CryptoCBCMaxHMACLength = 100; NSInteger payloadOffset; NSInteger payloadHeaderLength; - block(payload, &payloadOffset, &payloadHeaderLength, packetBytes, packetLength); + if (!block(payload, &payloadOffset, &payloadHeaderLength, packetBytes, packetLength, error)) { + return NULL; + } *length -= payloadHeaderLength; return payload + payloadOffset; } diff --git a/TunnelKit/Sources/Core/DataPath.m b/TunnelKit/Sources/Core/DataPath.m index 176dd96..cc0182a 100644 --- a/TunnelKit/Sources/Core/DataPath.m +++ b/TunnelKit/Sources/Core/DataPath.m @@ -162,9 +162,10 @@ memcpy(packetDest, payload.bytes, payload.length); *packetLengthOffset = 0; }; - self.parsePayloadBlock = ^(uint8_t * payload, NSInteger *payloadOffset, NSInteger * headerLength, const uint8_t * packet, NSInteger packetLength) { + self.parsePayloadBlock = ^BOOL(uint8_t * _Nonnull payload, NSInteger * _Nonnull payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength, NSError * _Nullable __autoreleasing * _Nullable error) { *payloadOffset = 0; *headerLength = 0; + return YES; }; break; } @@ -175,11 +176,16 @@ packetDest[0] = DataPacketNoCompressSwap; *packetLengthOffset = 1; }; - self.parsePayloadBlock = ^(uint8_t * payload, NSInteger *payloadOffset, NSInteger * headerLength, const uint8_t * packet, NSInteger packetLength) { - NSCAssert(payload[0] == DataPacketNoCompressSwap, @"Expected NO_COMPRESS_SWAP (found %X != %X)", payload[0], DataPacketNoCompressSwap); + self.parsePayloadBlock = ^BOOL(uint8_t * _Nonnull payload, NSInteger * _Nonnull payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength, NSError * _Nullable __autoreleasing * _Nullable error) { + if (payload[0] != 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; }; break; } @@ -189,10 +195,17 @@ packetDest[0] = DataPacketNoCompress; *packetLengthOffset = 1; }; - self.parsePayloadBlock = ^(uint8_t * payload, NSInteger *payloadOffset, NSInteger * headerLength, const uint8_t * packet, NSInteger packetLength) { - NSCAssert(payload[0] == DataPacketNoCompress, @"Expected NO_COMPRESS (found %X != %X)", payload[0], DataPacketNoCompress); + self.parsePayloadBlock = ^BOOL(uint8_t * _Nonnull payload, NSInteger * _Nonnull payloadOffset, NSInteger * _Nonnull headerLength, const uint8_t * _Nonnull packet, NSInteger packetLength, NSError * _Nullable __autoreleasing * _Nullable error) { + if (payload[0] != DataPacketNoCompress) { + // @"Expected NO_COMPRESS (found %X != %X)", payload[0], DataPacketNoCompress); + if (error) { + *error = TunnelKitErrorWithCode(TunnelKitErrorCodeDataPathCompression); + } + return NO; + } *payloadOffset = 1; *headerLength = 1; + return YES; }; break; } @@ -280,7 +293,11 @@ const uint8_t *payloadBytes = [self.decrypter parsePayloadWithBlock:self.parsePayloadBlock length:&payloadLength packetBytes:dataPacketBytes - packetLength:dataPacketLength]; + packetLength:dataPacketLength + error:error]; + if (!payloadBytes) { + return nil; + } if ((payloadLength == sizeof(DataPacketPingData)) && !memcmp(payloadBytes, DataPacketPingData, payloadLength)) { if (keepAlive) { diff --git a/TunnelKit/Sources/Core/DataPathCrypto.h b/TunnelKit/Sources/Core/DataPathCrypto.h index d00dc4e..fb7340f 100644 --- a/TunnelKit/Sources/Core/DataPathCrypto.h +++ b/TunnelKit/Sources/Core/DataPathCrypto.h @@ -57,7 +57,12 @@ NS_ASSUME_NONNULL_BEGIN } typedef void (^DataPathAssembleBlock)(uint8_t *packetDest, NSInteger *packetLengthOffset, NSData *payload); -typedef void (^DataPathParseBlock)(uint8_t *payload, NSInteger *payloadOffset, NSInteger *headerLength, const uint8_t *packet, NSInteger packetLength); +typedef BOOL (^DataPathParseBlock)(uint8_t *payload, + NSInteger *payloadOffset, + NSInteger *headerLength, + const uint8_t *packet, + NSInteger packetLength, + NSError **error); @protocol DataPathChannel @@ -77,7 +82,7 @@ typedef void (^DataPathParseBlock)(uint8_t *payload, NSInteger *payloadOffset, N @protocol DataPathDecrypter - (BOOL)decryptDataPacket:(NSData *)packet into:(uint8_t *)packetBytes length:(NSInteger *)packetLength packetId:(uint32_t *)packetId error:(NSError **)error; -- (const uint8_t *)parsePayloadWithBlock:(nullable DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength; +- (const uint8_t * _Nullable)parsePayloadWithBlock:(nullable DataPathParseBlock)block length:(NSInteger *)length packetBytes:(uint8_t *)packetBytes packetLength:(NSInteger)packetLength error:(NSError **)error; @end diff --git a/TunnelKit/Sources/Core/Errors.h b/TunnelKit/Sources/Core/Errors.h index 130a229..4dc201d 100644 --- a/TunnelKit/Sources/Core/Errors.h +++ b/TunnelKit/Sources/Core/Errors.h @@ -51,7 +51,8 @@ typedef NS_ENUM(NSInteger, TunnelKitErrorCode) { TunnelKitErrorCodeTLSBoxServerCertificate = 206, TunnelKitErrorCodeTLSBoxServerEKU = 207, TunnelKitErrorCodeDataPathOverflow = 301, - TunnelKitErrorCodeDataPathPeerIdMismatch = 302 + TunnelKitErrorCodeDataPathPeerIdMismatch = 302, + TunnelKitErrorCodeDataPathCompression = 303 }; static inline NSError *TunnelKitErrorWithCode(TunnelKitErrorCode code) {