1
0
mirror of https://github.com/danog/MadelineProto.git synced 2024-12-04 20:27:46 +01:00
MadelineProto/src/DoHWrapper.php

187 lines
7.6 KiB
PHP
Raw Normal View History

2023-01-08 16:06:50 +01:00
<?php
declare(strict_types=1);
/**
* DoH module.
*
* This file is part of MadelineProto.
* MadelineProto is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
* MadelineProto is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details.
* You should have received a copy of the GNU General Public License along with MadelineProto.
* If not, see <http://www.gnu.org/licenses/>.
*
* @author Daniil Gentili <daniil@daniil.it>
* @copyright 2016-2023 Daniil Gentili <daniil@daniil.it>
* @license https://opensource.org/licenses/AGPL-3.0 AGPLv3
* @link https://docs.madelineproto.xyz MadelineProto documentation
*/
namespace danog\MadelineProto;
use Amp\Dns\DnsConfig;
use Amp\Dns\DnsConfigLoader;
2023-01-12 14:12:52 +01:00
use Amp\Dns\DnsResolver;
use Amp\Dns\Rfc1035StubDnsResolver;
2023-01-08 16:06:50 +01:00
use Amp\Dns\UnixDnsConfigLoader;
use Amp\Dns\WindowsDnsConfigLoader;
use Amp\DoH\DoHConfig;
2023-01-13 14:36:10 +01:00
use Amp\DoH\DoHNameserver;
2023-01-12 16:26:30 +01:00
use Amp\DoH\Rfc8484StubDoHResolver;
2023-01-08 16:06:50 +01:00
use Amp\Http\Client\Connection\DefaultConnectionFactory;
use Amp\Http\Client\Connection\UnlimitedConnectionPool;
use Amp\Http\Client\Cookie\CookieInterceptor;
use Amp\Http\Client\Cookie\CookieJar;
use Amp\Http\Client\Cookie\LocalCookieJar;
use Amp\Http\Client\HttpClient;
use Amp\Http\Client\HttpClientBuilder;
use Amp\Socket\ConnectContext;
use Amp\Socket\DnsSocketConnector;
use Amp\Websocket\Client\Rfc6455ConnectionFactory;
use Amp\Websocket\Client\Rfc6455Connector;
use danog\MadelineProto\Settings\Connection;
2023-01-08 16:41:42 +01:00
use danog\MadelineProto\Stream\Common\BufferedRawStream;
2023-01-08 16:06:50 +01:00
use danog\MadelineProto\Stream\ConnectionContext;
2023-01-08 16:41:42 +01:00
use danog\MadelineProto\Stream\MTProtoTransport\ObfuscatedStream;
use danog\MadelineProto\Stream\Transport\DefaultStream;
use danog\MadelineProto\Stream\Transport\WssStream;
use danog\MadelineProto\Stream\Transport\WsStream;
2023-01-08 16:06:50 +01:00
use Throwable;
/**
* @psalm-import-type TDcList from DataCenter
*/
final class DoHWrapper
{
/**
* HTTP client.
*
*/
public readonly HttpClient $HTTPClient;
/**
* DNS over HTTPS client.
*
*/
2023-01-12 14:12:52 +01:00
public readonly DnsResolver $DoHClient;
2023-01-08 16:06:50 +01:00
/**
* Non-proxied DNS over HTTPS client.
*
*/
2023-01-12 14:12:52 +01:00
public readonly DnsResolver $nonProxiedDoHClient;
2023-01-08 16:06:50 +01:00
/**
* Cookie jar.
*
*/
public readonly CookieJar $CookieJar;
/**
* DNS connector.
*/
public readonly DnsSocketConnector $dnsConnector;
/**
* DoH connector.
*/
public readonly Rfc6455Connector $webSocketConnector;
public function __construct(
private Connection $settings,
private LoggerGetter $loggerGetter,
?CookieJar $jar = null
) {
$configProvider = new class implements DnsConfigLoader {
public function loadConfig(): DnsConfig
{
$loader = \stripos(PHP_OS, 'win') === 0 ? new WindowsDnsConfigLoader() : new UnixDnsConfigLoader();
try {
return $loader->loadConfig();
} catch (Throwable) {
return new DnsConfig([
'1.1.1.1',
'1.0.0.1',
'[2606:4700:4700::1111]',
'[2606:4700:4700::1001]',
]);
}
}
};
$this->CookieJar = $jar ?? new LocalCookieJar();
2023-01-11 18:47:27 +01:00
$this->HTTPClient = (new HttpClientBuilder())->interceptNetwork(new CookieInterceptor($this->CookieJar))->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this, $loggerGetter))))->build();
$DoHHTTPClient = (new HttpClientBuilder())->interceptNetwork(new CookieInterceptor($this->CookieJar))->usingPool(new UnlimitedConnectionPool(new DefaultConnectionFactory(new ContextConnector($this, $loggerGetter, true))))->build();
2023-01-13 14:36:10 +01:00
$DoHConfig = new DoHConfig([new DoHNameserver('https://mozilla.cloudflare-dns.com/dns-query'), new DoHNameserver('https://dns.google/resolve')], $DoHHTTPClient);
$nonProxiedDoHConfig = new DoHConfig([new DoHNameserver('https://mozilla.cloudflare-dns.com/dns-query'), new DoHNameserver('https://dns.google/resolve')]);
2023-01-08 16:06:50 +01:00
$this->DoHClient = Magic::$altervista || Magic::$zerowebhost || !$settings->getUseDoH()
2023-01-12 14:12:52 +01:00
? new Rfc1035StubDnsResolver(null, $configProvider)
2023-01-12 16:26:30 +01:00
: new Rfc8484StubDoHResolver($DoHConfig);
2023-01-08 16:06:50 +01:00
$this->nonProxiedDoHClient = Magic::$altervista || Magic::$zerowebhost || !$settings->getUseDoH()
2023-01-12 14:12:52 +01:00
? new Rfc1035StubDnsResolver(null, $configProvider)
2023-01-12 16:26:30 +01:00
: new Rfc8484StubDoHResolver($nonProxiedDoHConfig);
2023-01-08 16:06:50 +01:00
2023-01-12 14:12:52 +01:00
$this->dnsConnector = new DnsSocketConnector(new Rfc1035StubDnsResolver(null, $configProvider));
2023-01-08 16:06:50 +01:00
$this->webSocketConnector = new Rfc6455Connector(
new Rfc6455ConnectionFactory(),
$this->HTTPClient
);
}
/**
* Generate contexts.
*
* @return ConnectionContext[]
*/
2023-01-08 16:23:18 +01:00
public function generateContexts(string $uri, ConnectContext $context = null): array
2023-01-08 16:06:50 +01:00
{
$ctxs = [];
2023-01-08 16:23:18 +01:00
$combos = [
[[DefaultStream::class, []], [BufferedRawStream::class, []]]
];
2023-01-08 16:06:50 +01:00
if ($this->settings->getRetry()) {
$proxyCombos = [];
foreach ($this->settings->getProxies() as $proxy => $extras) {
2023-01-08 16:23:18 +01:00
if ($proxy === ObfuscatedStream::class) {
2023-01-08 16:06:50 +01:00
continue;
}
foreach ($extras as $extra) {
foreach ($combos as $orig) {
$combo = [];
2023-01-08 16:23:18 +01:00
if ($orig[1][0] === BufferedRawStream::class) {
[$first, $second] = [\array_slice($orig, 0, 2), \array_slice($orig, 2)];
$first[] = [$proxy, $extra];
$combo = \array_merge($first, $second);
2023-06-28 15:50:38 +02:00
} elseif (\in_array($orig[1][0], [WsStream::class, WssStream::class], true)) {
2023-01-08 16:23:18 +01:00
[$first, $second] = [\array_slice($orig, 0, 1), \array_slice($orig, 1)];
$first[] = [BufferedRawStream::class, []];
$first[] = [$proxy, $extra];
$combo = \array_merge($first, $second);
2023-01-08 16:06:50 +01:00
}
$proxyCombos []= $combo;
}
}
}
$combos = \array_merge($proxyCombos, $combos);
$combos = \array_unique($combos, SORT_REGULAR);
}
2023-01-08 16:23:18 +01:00
2023-01-26 19:57:50 +01:00
$context ??= (new ConnectContext())->withConnectTimeout($this->settings->getTimeout())->withBindTo($this->settings->getBindTo());
2023-01-08 16:06:50 +01:00
foreach ($combos as $combo) {
foreach ([true, false] as $useDoH) {
$ipv6Combos = [
2023-01-08 16:23:18 +01:00
$this->settings->getIpv6(),
!$this->settings->getIpv6(),
2023-01-08 16:06:50 +01:00
];
foreach ($ipv6Combos as $ipv6) {
2023-01-08 16:23:18 +01:00
$ctx = (new ConnectionContext())->setSocketContext($context)->setUri($uri)->setIpv6($ipv6);
foreach ($combo as $stream) {
if ($stream[0] === DefaultStream::class && $stream[1] === []) {
$stream[1] = $useDoH ? new DoHConnector($this, $ctx) : $this->dnsConnector;
2023-01-08 16:06:50 +01:00
}
2023-01-08 16:23:18 +01:00
$ctx->addStream(...$stream);
2023-01-08 16:06:50 +01:00
}
2023-01-08 16:23:18 +01:00
$ctxs[] = $ctx;
2023-01-08 16:06:50 +01:00
}
}
}
return $ctxs;
}
}