diff --git a/MTBackupAddressSignals.m b/MTBackupAddressSignals.m index 8d170e50fb..c8e55643d6 100644 --- a/MTBackupAddressSignals.m +++ b/MTBackupAddressSignals.m @@ -132,7 +132,7 @@ NSMutableDictionary *datacenterAddressOverrides = [[NSMutableDictionary alloc] init]; MTBackupDatacenterAddress *address = data.addressList[0]; - datacenterAddressOverrides[@(data.datacenterId)] = [[MTDatacenterAddress alloc] initWithIp:address.ip port:(uint16_t)address.port preferForMedia:false restrictToTcp:false cdn:false preferForProxy:false]; + datacenterAddressOverrides[@(data.datacenterId)] = [[MTDatacenterAddress alloc] initWithIp:address.ip port:(uint16_t)address.port preferForMedia:false restrictToTcp:false cdn:false preferForProxy:false secret:nil]; apiEnvironment.datacenterAddressOverrides = datacenterAddressOverrides; apiEnvironment.apiId = currentContext.apiEnvironment.apiId; diff --git a/MTDiscoverConnectionSignals.m b/MTDiscoverConnectionSignals.m index d53e63d830..3406740760 100644 --- a/MTDiscoverConnectionSignals.m +++ b/MTDiscoverConnectionSignals.m @@ -212,7 +212,7 @@ typedef struct { for (MTDatacenterAddress *address in bestAddressList) { MTTransportScheme *tcpTransportScheme = [[MTTransportScheme alloc] initWithTransportClass:[MTTcpTransport class] address:address media:media]; - MTTransportScheme *httpTransportScheme = [[MTTransportScheme alloc] initWithTransportClass:[MTHttpTransport class] address:address media:media]; + //MTTransportScheme *httpTransportScheme = [[MTTransportScheme alloc] initWithTransportClass:[MTHttpTransport class] address:address media:media]; if ([self isIpv6:address.ip]) { @@ -235,7 +235,7 @@ typedef struct { for (NSNumber *nPort in alternatePorts) { NSSet *ipsWithPort = tcpIpsByPort[nPort]; if (![ipsWithPort containsObject:address.ip]) { - MTDatacenterAddress *portAddress = [[MTDatacenterAddress alloc] initWithIp:address.ip port:[nPort intValue] preferForMedia:address.preferForMedia restrictToTcp:address.restrictToTcp cdn:address.cdn preferForProxy:address.preferForProxy]; + MTDatacenterAddress *portAddress = [[MTDatacenterAddress alloc] initWithIp:address.ip port:[nPort intValue] preferForMedia:address.preferForMedia restrictToTcp:address.restrictToTcp cdn:address.cdn preferForProxy:address.preferForProxy secret:address.secret]; MTTransportScheme *tcpPortTransportScheme = [[MTTransportScheme alloc] initWithTransportClass:[MTTcpTransport class] address:portAddress media:media]; MTSignal *tcpConnectionWithTimeout = [[[self tcpConnectionWithContext:context datacenterId:0 address:portAddress] then:[MTSignal single:tcpPortTransportScheme]] timeout:5.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[MTSignal fail:nil]]; MTSignal *signal = [tcpConnectionWithTimeout catch:^MTSignal *(__unused id error) { @@ -246,7 +246,7 @@ typedef struct { } } - if (!address.restrictToTcp && !isProxy) { + /*if (!address.restrictToTcp && !isProxy) { MTSignal *signal = [[[[self httpConnectionWithAddress:address] then:[MTSignal single:httpTransportScheme]] timeout:5.0 onQueue:[MTQueue concurrentDefaultQueue] orSignal:[MTSignal fail:nil]] catch:^MTSignal *(__unused id error) { return [MTSignal complete]; @@ -262,7 +262,7 @@ typedef struct { return [MTSignal complete]; }]]; } - } + }*/ } MTSignal *repeatDelaySignal = [[MTSignal complete] delay:1.0 onQueue:[MTQueue concurrentDefaultQueue]]; diff --git a/MTProtoKit/MTApiEnvironment.h b/MTProtoKit/MTApiEnvironment.h index aca13ed66d..3356d5d694 100644 --- a/MTProtoKit/MTApiEnvironment.h +++ b/MTProtoKit/MTApiEnvironment.h @@ -14,8 +14,9 @@ @property (nonatomic, readonly) uint16_t port; @property (nonatomic, strong, readonly) NSString *username; @property (nonatomic, strong, readonly) NSString *password; +@property (nonatomic, strong, readonly) NSData *secret; -- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port username:(NSString *)username password:(NSString *)password; +- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port username:(NSString *)username password:(NSString *)password secret:(NSData *)secret; @end diff --git a/MTProtoKit/MTApiEnvironment.m b/MTProtoKit/MTApiEnvironment.m index b2e5dce7bf..28f68d4bdc 100644 --- a/MTProtoKit/MTApiEnvironment.m +++ b/MTProtoKit/MTApiEnvironment.m @@ -132,13 +132,14 @@ typedef enum { @implementation MTSocksProxySettings -- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port username:(NSString *)username password:(NSString *)password { +- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port username:(NSString *)username password:(NSString *)password secret:(NSData *)secret { self = [super init]; if (self != nil) { _ip = ip; _port = port; _username = username; _password = password; + _secret = secret; } return self; } @@ -160,6 +161,9 @@ typedef enum { if ((other->_password != nil) != (_password != nil) || (_password != nil && ![_password isEqual:other->_password])) { return false; } + if ((other->_secret != nil) != (_secret != nil) || (_secret != nil && ![_secret isEqual:other->_secret])) { + return false; + } return true; } diff --git a/MTProtoKit/MTContext.m b/MTProtoKit/MTContext.m index 3ff592511a..9f9e6d8a8c 100644 --- a/MTProtoKit/MTContext.m +++ b/MTProtoKit/MTContext.m @@ -26,6 +26,7 @@ #import #import "MTDiscoverConnectionSignals.h" +#import "MTHttpTransport.h" #if defined(MtProtoKitDynamicFramework) # import @@ -753,6 +754,10 @@ } } + if (candidate.transportClass == [MTHttpTransport class]) { + candidate = nil; + } + if (candidate != nil) { result = candidate; } else { diff --git a/MTProtoKit/MTDatacenterAddress.h b/MTProtoKit/MTDatacenterAddress.h index bdf3a12a4e..a95da2c547 100644 --- a/MTProtoKit/MTDatacenterAddress.h +++ b/MTProtoKit/MTDatacenterAddress.h @@ -17,8 +17,9 @@ @property (nonatomic, readonly) bool restrictToTcp; @property (nonatomic, readonly) bool cdn; @property (nonatomic, readonly) bool preferForProxy; +@property (nonatomic, readonly) NSData *secret; -- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port preferForMedia:(bool)preferForMedia restrictToTcp:(bool)restrictToTcp cdn:(bool)cdn preferForProxy:(bool)preferForProxy; +- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port preferForMedia:(bool)preferForMedia restrictToTcp:(bool)restrictToTcp cdn:(bool)cdn preferForProxy:(bool)preferForProxy secret:(NSData *)secret; - (BOOL)isEqualToAddress:(MTDatacenterAddress *)other; - (BOOL)isIpv6; diff --git a/MTProtoKit/MTDatacenterAddress.m b/MTProtoKit/MTDatacenterAddress.m index adde8fa4f1..58cfe02719 100644 --- a/MTProtoKit/MTDatacenterAddress.m +++ b/MTProtoKit/MTDatacenterAddress.m @@ -13,7 +13,7 @@ @implementation MTDatacenterAddress -- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port preferForMedia:(bool)preferForMedia restrictToTcp:(bool)restrictToTcp cdn:(bool)cdn preferForProxy:(bool)preferForProxy +- (instancetype)initWithIp:(NSString *)ip port:(uint16_t)port preferForMedia:(bool)preferForMedia restrictToTcp:(bool)restrictToTcp cdn:(bool)cdn preferForProxy:(bool)preferForProxy secret:(NSData *)secret { self = [super init]; if (self != nil) @@ -24,6 +24,7 @@ _restrictToTcp = restrictToTcp; _cdn = cdn; _preferForProxy = preferForProxy; + _secret = secret; } return self; } @@ -40,6 +41,7 @@ _restrictToTcp = [aDecoder decodeBoolForKey:@"restrictToTcp"]; _cdn = [aDecoder decodeBoolForKey:@"cdn"]; _preferForProxy = [aDecoder decodeBoolForKey:@"preferForProxy"]; + _secret = [aDecoder decodeObjectForKey:@"secret"]; } return self; } @@ -53,6 +55,7 @@ [aCoder encodeBool:_restrictToTcp forKey:@"restrictToTcp"]; [aCoder encodeBool:_cdn forKey:@"cdn"]; [aCoder encodeBool:_preferForProxy forKey:@"preferForProxy"]; + [aCoder encodeObject:_secret forKey:@"secret"]; } - (BOOL)isEqual:(id)object @@ -89,6 +92,14 @@ return false; } + if ((_secret != nil) && (other->_secret != nil)) { + if (![_secret isEqualToData:other->_secret]) { + return false; + } + } else if ((_secret != nil) != (other->_secret != nil)) { + return false; + } + return true; } @@ -105,7 +116,7 @@ - (NSString *)description { - return [[NSString alloc] initWithFormat:@"%@:%d (media: %@, cdn: %@, static: %@)", _ip == nil ? _host : _ip, (int)_port, _preferForMedia ? @"yes" : @"no", _cdn ? @"yes" : @"no", _preferForProxy ? @"yes" : @"no"]; + return [[NSString alloc] initWithFormat:@"%@:%d (media: %@, cdn: %@, static: %@, secret: %@)", _ip == nil ? _host : _ip, (int)_port, _preferForMedia ? @"yes" : @"no", _cdn ? @"yes" : @"no", _preferForProxy ? @"yes" : @"no", _secret]; } @end diff --git a/MTProtoKit/MTHttpTransport.m b/MTProtoKit/MTHttpTransport.m index 14f900208d..efa0e93708 100644 --- a/MTProtoKit/MTHttpTransport.m +++ b/MTProtoKit/MTHttpTransport.m @@ -355,6 +355,9 @@ if (requestTransactionForLongPolling) [self setDelegateNeedsTransaction]; + + if ([delegate respondsToSelector:@selector(transportConnectionProblemsStatusChanged:hasConnectionProblems:isProbablyHttp:)]) + [delegate transportConnectionProblemsStatusChanged:self hasConnectionProblems:true isProbablyHttp:false]; }]; } diff --git a/MTProtoKit/MTTcpConnection.m b/MTProtoKit/MTTcpConnection.m index dacae30574..3e695ce166 100644 --- a/MTProtoKit/MTTcpConnection.m +++ b/MTProtoKit/MTTcpConnection.m @@ -24,10 +24,13 @@ #import "MTDatacenterAddress.h" #import "MTAes.h" +#import "MTEncryption.h" #import "MTDNS.h" #import "MTSignal.h" +#define MT_TCPO25 0 + MTInternalIdClass(MTTcpConnection) struct socks5_ident_req @@ -110,6 +113,8 @@ struct ctr_state { GCDAsyncSocket *_socket; bool _closed; + int32_t _datacenterTag; + uint8_t _quickAckByte; MTTimer *_responseTimeoutTimer; @@ -134,6 +139,10 @@ struct ctr_state { NSString *_socksUsername; NSString *_socksPassword; + NSString *_mtpIp; + int32_t _mtpPort; + NSData *_mtpSecret; + MTMetaDisposable *_resolveDisposable; } @@ -176,13 +185,25 @@ struct ctr_state { } if (context.apiEnvironment.socksProxySettings != nil) { - _socksIp = context.apiEnvironment.socksProxySettings.ip; - _socksPort = context.apiEnvironment.socksProxySettings.port; - _socksUsername = context.apiEnvironment.socksProxySettings.username; - _socksPassword = context.apiEnvironment.socksProxySettings.password; + if (context.apiEnvironment.socksProxySettings.secret != nil) { + _mtpIp = context.apiEnvironment.socksProxySettings.ip; + _mtpPort = context.apiEnvironment.socksProxySettings.port; + _mtpSecret = context.apiEnvironment.socksProxySettings.secret; + } else { + _socksIp = context.apiEnvironment.socksProxySettings.ip; + _socksPort = context.apiEnvironment.socksProxySettings.port; + _socksUsername = context.apiEnvironment.socksProxySettings.username; + _socksPassword = context.apiEnvironment.socksProxySettings.password; + } } _resolveDisposable = [[MTMetaDisposable alloc] init]; + + if (address.preferForMedia) { + _datacenterTag = -(int32_t)datacenterId; + } else { + _datacenterTag = (int32_t)datacenterId; + } } return self; } @@ -238,6 +259,8 @@ struct ctr_state { } else { MTLog(@"[MTTcpConnection#%x connecting to %@:%d via %@:%d using %@:%@]", (int)self, _address.ip, (int)_address.port, _socksIp, (int)_socksPort, _socksUsername, _socksPassword); } + } else if (_mtpIp != nil) { + MTLog(@"[MTTcpConnection#%x connecting to %@:%d via mtp://%@:%d:%@]", (int)self, _address.ip, (int)_address.port, _mtpIp, (int)_mtpPort, _mtpSecret); } else { MTLog(@"[MTTcpConnection#%x connecting to %@:%d]", (int)self, _address.ip, (int)_address.port); } @@ -263,6 +286,23 @@ struct ctr_state { } else { resolveSignal = [MTSignal single:_socksIp]; } + } else if (_mtpIp != nil) { + port = _mtpPort; + + bool isHostname = true; + struct in_addr ip4; + struct in6_addr ip6; + if (inet_aton(_mtpIp.UTF8String, &ip4) != 0) { + isHostname = false; + } else if (inet_pton(AF_INET6, _mtpIp.UTF8String, &ip6) != 0) { + isHostname = false; + } + + if (isHostname) { + resolveSignal = [MTDNS resolveHostname:_mtpIp]; + } else { + resolveSignal = [MTSignal single:_mtpIp]; + } } __weak MTTcpConnection *weakSelf = self; @@ -388,14 +428,35 @@ struct ctr_state { if (useEncryption) { int32_t controlVersion = 0xefefefef; memcpy(controlBytes + 56, &controlVersion, 4); + int32_t datacenterTag = _datacenterTag; + memcpy(controlBytes + 60, &datacenterTag, 4); uint8_t controlBytesReversed[64]; for (int i = 0; i < 64; i++) { controlBytesReversed[i] = controlBytes[64 - 1 - i]; } - _outgoingAesCtr = [[MTAesCtr alloc] initWithKey:controlBytes + 8 keyLength:32 iv:controlBytes + 8 + 32 decrypt:false]; - _incomingAesCtr = [[MTAesCtr alloc] initWithKey:controlBytesReversed + 8 keyLength:32 iv:controlBytesReversed + 8 + 32 decrypt:false]; + NSData *aesKey = [[NSData alloc] initWithBytes:controlBytes + 8 length:32]; + NSData *aesIv = [[NSData alloc] initWithBytes:controlBytes + 8 + 32 length:16]; + + NSData *incomingAesKey = [[NSData alloc] initWithBytes:controlBytesReversed + 8 length:32]; + NSData *incomingAesIv = [[NSData alloc] initWithBytes:controlBytesReversed + 8 + 32 length:16]; +#if MT_TCPO25 + if (_mtpSecret != nil || _address.secret != nil) { + NSMutableData *aesKeyData = [[NSMutableData alloc] init]; + [aesKeyData appendData:aesKey]; + if (_mtpSecret != nil) { + [aesKeyData appendData:_mtpSecret]; + } else if (_address.secret != nil) { + [aesKeyData appendData:_address.secret]; + } + NSData *aesKeyHash = MTSha256(aesKeyData); + aesKey = [aesKeyHash subdataWithRange:NSMakeRange(0, 32)]; + } +#endif + + _outgoingAesCtr = [[MTAesCtr alloc] initWithKey:aesKey.bytes keyLength:32 iv:aesIv.bytes decrypt:false]; + _incomingAesCtr = [[MTAesCtr alloc] initWithKey:incomingAesKey.bytes keyLength:32 iv:incomingAesIv.bytes decrypt:false]; uint8_t encryptedControlBytes[64]; [_outgoingAesCtr encryptIn:controlBytes out:encryptedControlBytes len:64];