From 98e56ba62fdf9be6dd6815eb80f67e8ccda5aef4 Mon Sep 17 00:00:00 2001 From: Daniil Gentili Date: Fri, 28 Feb 2020 14:14:02 +0100 Subject: [PATCH] ipv6 fixes --- composer.json | 4 +- src/danog/MadelineProto/DataCenter.php | 11 ++++- .../MadelineProto/DataCenterConnection.php | 2 +- .../Stream/ConnectionContext.php | 15 ++++--- .../Stream/MTProtoTransport/HttpStream.php | 5 +-- .../Stream/Transport/WsStream.php | 6 ++- tests/danog/MadelineProto/DataCenterTest.php | 43 +++++++++---------- 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/composer.json b/composer.json index 2ae17352..7cb7ec59 100644 --- a/composer.json +++ b/composer.json @@ -29,9 +29,9 @@ "amphp/byte-stream": "^1", "danog/dns-over-https": "^0.2", "amphp/http-client-cookies": "^1", - "amphp/uri": "^0.1", "danog/tg-file-decoder": "^0.1", - "danog/magicalserializer": "^1.0" + "danog/magicalserializer": "^1.0", + "league/uri": "^6" }, "require-dev": { "vlucas/phpdotenv": "^3", diff --git a/src/danog/MadelineProto/DataCenter.php b/src/danog/MadelineProto/DataCenter.php index 96ae8648..51b584e2 100644 --- a/src/danog/MadelineProto/DataCenter.php +++ b/src/danog/MadelineProto/DataCenter.php @@ -120,6 +120,11 @@ class DataCenter * @var DNSConnector */ private $dnsConnector; + /** + * DoH connector. + */ + private Rfc6455Connector $webSocketConnnector; + public function __sleep() { return ['sockets', 'curdc', 'dclist', 'settings']; @@ -228,6 +233,7 @@ class DataCenter $this->nonProxiedDoHClient = Magic::$altervista || Magic::$zerowebhost ? new Rfc1035StubResolver() : new Rfc8484StubResolver($nonProxiedDoHConfig); $this->dnsConnector = new DnsConnector(new Rfc1035StubResolver()); + $this->webSocketConnnector = new Rfc6455Connector($this->HTTPClient); } } public function dcConnect(string $dc_number, int $id = -1): \Generator @@ -421,6 +427,9 @@ class DataCenter continue; } $address = $this->dclist[$test][$ipv6][$dc_number]['ip_address']; + if ($ipv6 === 'ipv6') { + $address = "[$address]"; + } $port = $this->dclist[$test][$ipv6][$dc_number]['port']; foreach (\array_unique([$port, 443, 80, 88, 5222]) as $port) { $stream = \end($combo)[0]; @@ -459,7 +468,7 @@ class DataCenter $stream[1] = $useDoH ? new DoHConnector($this, $ctx) : $this->dnsConnector; } if (\in_array($stream[0], [WsStream::class, WssStream::class]) && $stream[1] === []) { - $stream[1] = new Rfc6455Connector($this->HTTPClient); + $stream[1] = $this->webSocketConnnector; } $ctx->addStream(...$stream); } diff --git a/src/danog/MadelineProto/DataCenterConnection.php b/src/danog/MadelineProto/DataCenterConnection.php index c0b82bf7..e25b5e7f 100644 --- a/src/danog/MadelineProto/DataCenterConnection.php +++ b/src/danog/MadelineProto/DataCenterConnection.php @@ -438,7 +438,7 @@ class DataCenterConnection implements JsonSerializable * * @return void */ - public function disconnect() + public function disconnect(): void { $this->connectionsDeferred = new Deferred(); $this->connectionsPromise = $this->connectionsDeferred->promise(); diff --git a/src/danog/MadelineProto/Stream/ConnectionContext.php b/src/danog/MadelineProto/Stream/ConnectionContext.php index e475c8ce..1d5157f2 100644 --- a/src/danog/MadelineProto/Stream/ConnectionContext.php +++ b/src/danog/MadelineProto/Stream/ConnectionContext.php @@ -21,10 +21,11 @@ namespace danog\MadelineProto\Stream; use Amp\CancellationToken; use Amp\Socket\ConnectContext; -use Amp\Uri\Uri; use danog\MadelineProto\Exception; use danog\MadelineProto\Stream\MTProtoTransport\ObfuscatedStream; use danog\MadelineProto\Stream\Transport\DefaultStream; +use League\Uri\Http; +use Psr\Http\Message\UriInterface; /** * Connection context class. @@ -63,7 +64,7 @@ class ConnectionContext /** * The connection URI. * - * @var \Amp\Uri\Uri + * @var UriInterface */ private $uri; /** @@ -138,13 +139,13 @@ class ConnectionContext /** * Set the connection URI. * - * @param string|\Amp\Uri\Uri $uri + * @param string|UriInterface $uri * * @return self */ public function setUri($uri): self { - $this->uri = $uri instanceof Uri ? $uri : new Uri($uri); + $this->uri = $uri instanceof UriInterface ? $uri : Http::createFromString($uri); return $this; } /** @@ -159,9 +160,9 @@ class ConnectionContext /** * Get the URI. * - * @return \Amp\Uri\Uri + * @return UriInterface */ - public function getUri(): Uri + public function getUri(): UriInterface { return $this->uri; } @@ -463,7 +464,7 @@ class ConnectionContext } $string .= \preg_replace('/.*\\\\/', '', $stream[0]); if ($stream[1] && $stream[0] !== DefaultStream::getName()) { - $string .= ' (' . \json_encode($stream[1]) . ')'; + $string .= ' ('.\json_encode($stream[1]).')'; } } return $string; diff --git a/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php b/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php index 6d3a51db..d0840ad5 100644 --- a/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php +++ b/src/danog/MadelineProto/Stream/MTProtoTransport/HttpStream.php @@ -27,6 +27,7 @@ use danog\MadelineProto\Stream\BufferedProxyStreamInterface; use danog\MadelineProto\Stream\ConnectionContext; use danog\MadelineProto\Stream\MTProtoBufferInterface; use danog\MadelineProto\Stream\RawStreamInterface; +use Psr\Http\Message\UriInterface; /** * HTTP stream wrapper. @@ -42,10 +43,8 @@ class HttpStream implements MTProtoBufferInterface, BufferedProxyStreamInterface private $header = ''; /** * URI of the HTTP API. - * - * @var \Amp\Uri\Uri */ - private $uri; + private UriInterface $uri; /** * Connect to stream. * diff --git a/src/danog/MadelineProto/Stream/Transport/WsStream.php b/src/danog/MadelineProto/Stream/Transport/WsStream.php index 073568b6..f075106e 100644 --- a/src/danog/MadelineProto/Stream/Transport/WsStream.php +++ b/src/danog/MadelineProto/Stream/Transport/WsStream.php @@ -68,8 +68,10 @@ class WsStream implements RawStreamInterface, ProxyStreamInterface throw new \danog\MadelineProto\Exception('Please install amphp/websocket-client by running "composer require amphp/websocket-client:dev-master"'); } $this->dc = $ctx->getIntDc(); - $handshake = new Handshake(\str_replace('tcp://', $ctx->isSecure() ? 'wss://' : 'ws://', $ctx->getStringUri())); - $this->stream = (yield ($this->connector ?? connector())->connect($handshake, $ctx->getCancellationToken())); + $uri = $ctx->getStringUri(); + $uri = \str_replace('tcp://', $ctx->isSecure() ? 'wss://' : 'ws://', $uri); + $handshake = new Handshake($uri); + $this->stream = yield ($this->connector ?? connector())->connect($handshake, $ctx->getCancellationToken()); if (\strlen($header)) { yield $this->write($header); } diff --git a/tests/danog/MadelineProto/DataCenterTest.php b/tests/danog/MadelineProto/DataCenterTest.php index 535c8c44..3e2b91df 100644 --- a/tests/danog/MadelineProto/DataCenterTest.php +++ b/tests/danog/MadelineProto/DataCenterTest.php @@ -20,15 +20,14 @@ final class DataCenterTest extends TestCase * @param string $protocol Protocol name * @param boolean $test_mode Test mode * @param boolean $ipv6 IPv6 - * @param boolean $doh DNS over HTTPS? * * @dataProvider protocolProvider * * @return void */ - public function testCanUseProtocol(string $transport, bool $obfuscated, string $protocol, bool $test_mode, bool $ipv6, bool $doh): void + public function testCanUseProtocol(string $transport, bool $obfuscated, string $protocol, bool $test_mode, bool $ipv6): void { - $settings = MTProto::getSettings( + $settings = MTProto::parseSettings( [ 'connection_settings' => [ 'all' => [ @@ -36,7 +35,8 @@ final class DataCenterTest extends TestCase 'test_mode' => $test_mode, 'protocol' => $protocol, 'obfuscated' => $obfuscated, - 'transport' => $transport + 'transport' => $transport, + 'do_not_retry' => true ], ], 'logger' => [ @@ -73,45 +73,44 @@ final class DataCenterTest extends TestCase ); $API->datacenter = $datacenter; - $API->getLogger()->logger("Testing protocol $protocol using transport $transport, ".($obfuscated ? 'obfuscated ' : 'not obfuscated ').($test_mode ? 'test DC ' : 'main DC ').($ipv6 ? 'IPv6 ' : 'IPv4 ').($doh ? "DNS over HTTPS" : "DNS")); + $API->getLogger()->logger("Testing protocol $protocol using transport $transport, ".($obfuscated ? 'obfuscated ' : 'not obfuscated ').($test_mode ? 'test DC ' : 'main DC ').($ipv6 ? 'IPv6 ' : 'IPv4 ')); \sleep(1); try { Tools::wait($datacenter->dcConnect(2)); + } catch (\Throwable $e) { + if (!$test_mode) { + throw $e; + } } finally { - Tools::wait($datacenter->getDataCenterConnection(2)->disconnect()); + $datacenter->getDataCenterConnection(2)->disconnect(); } $this->assertTrue(true); } public function protocolProvider(): \Generator { - return yield; $ipv6Pair = [false]; if (@\file_get_contents('https://ipv6.google.com')) { $ipv6Pair []= true; } foreach ([false, true] as $test_mode) { - foreach ([false, true] as $doh) { - foreach ($ipv6Pair as $ipv6) { - foreach (['tcp', 'ws', 'wss'] as $transport) { - foreach ([true, false] as $obfuscated) { - if ($transport !== 'tcp' && !$obfuscated) { + foreach ($ipv6Pair as $ipv6) { + foreach (['tcp', 'ws', 'wss'] as $transport) { + foreach ([true, false] as $obfuscated) { + if ($transport !== 'tcp' && !$obfuscated) { + continue; + } + foreach (['abridged', 'intermediate', 'intermediate_padded', 'full'] as $protocol) { + if ($protocol === 'full' && $obfuscated) { continue; } - foreach (['abridged', 'intermediate', 'intermediate_padded', 'full'] as $protocol) { - if ($protocol === 'full' && $obfuscated) { - continue; - } - yield [$transport, $obfuscated, $protocol, $test_mode, $ipv6, $doh]; - } + yield [$transport, $obfuscated, $protocol, $test_mode, $ipv6]; } } - yield ['tcp', false, 'http', $test_mode, $ipv6, true]; - yield ['tcp', false, 'https', $test_mode, $ipv6, true]; - yield ['tcp', false, 'http', $test_mode, $ipv6, false]; - yield ['tcp', false, 'https', $test_mode, $ipv6, false]; } + yield ['tcp', false, 'http', $test_mode, $ipv6]; + yield ['tcp', false, 'https', $test_mode, $ipv6]; } } }