mirror of
https://github.com/danog/dns.git
synced 2024-11-26 20:14:51 +01:00
Merge
This commit is contained in:
commit
acf6e83e3c
@ -4,10 +4,20 @@ namespace Amp\Dns;
|
||||
|
||||
final class Config
|
||||
{
|
||||
/** @var array */
|
||||
private $nameservers;
|
||||
/** @var array */
|
||||
private $knownHosts;
|
||||
/** @var int */
|
||||
private $timeout;
|
||||
/** @var int */
|
||||
private $attempts;
|
||||
/** @var array */
|
||||
private $searchList = [];
|
||||
/** @var int */
|
||||
private $ndots = 1;
|
||||
/** @var bool */
|
||||
private $rotation = false;
|
||||
|
||||
public function __construct(array $nameservers, array $knownHosts = [], int $timeout = 3000, int $attempts = 2)
|
||||
{
|
||||
@ -44,6 +54,39 @@ final class Config
|
||||
$this->attempts = $attempts;
|
||||
}
|
||||
|
||||
public function withSearchList(array $searchList): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->searchList = $searchList;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ConfigException
|
||||
*/
|
||||
public function withNdots(int $ndots): self
|
||||
{
|
||||
if ($ndots < 0) {
|
||||
throw new ConfigException("Invalid ndots ({$ndots}), must be greater or equal to 0");
|
||||
}
|
||||
if ($ndots > 15) {
|
||||
$ndots = 15;
|
||||
}
|
||||
$self = clone $this;
|
||||
$self->ndots = $ndots;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
public function withRotationEnabled(bool $enabled = true): self
|
||||
{
|
||||
$self = clone $this;
|
||||
$self->rotation = $enabled;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
private function validateNameserver($nameserver)
|
||||
{
|
||||
if (!$nameserver || !\is_string($nameserver)) {
|
||||
@ -101,4 +144,19 @@ final class Config
|
||||
{
|
||||
return $this->attempts;
|
||||
}
|
||||
|
||||
public function getSearchList(): array
|
||||
{
|
||||
return $this->searchList;
|
||||
}
|
||||
|
||||
public function getNdots(): int
|
||||
{
|
||||
return $this->ndots;
|
||||
}
|
||||
|
||||
public function isRotationEnabled(): bool
|
||||
{
|
||||
return $this->rotation;
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,8 @@ final class Rfc1035StubResolver implements Resolver
|
||||
|
||||
/** @var BlockingFallbackResolver */
|
||||
private $blockingFallbackResolver;
|
||||
/** @var int */
|
||||
private $nextNameserver = 0;
|
||||
|
||||
public function __construct(Cache $cache = null, ConfigLoader $configLoader = null)
|
||||
{
|
||||
@ -135,7 +137,9 @@ final class Rfc1035StubResolver implements Resolver
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
$dots = \substr_count($name, ".");
|
||||
// Should be replaced with $name[-1] from 7.1
|
||||
$trailingDot = \substr($name, -1, 1) === ".";
|
||||
$name = normalizeName($name);
|
||||
|
||||
if ($records = $this->queryHosts($name, $typeRestriction)) {
|
||||
@ -150,52 +154,69 @@ final class Rfc1035StubResolver implements Resolver
|
||||
: [new Record('127.0.0.1', Record::A, null)];
|
||||
}
|
||||
|
||||
for ($redirects = 0; $redirects < 5; $redirects++) {
|
||||
try {
|
||||
if ($typeRestriction) {
|
||||
return yield $this->query($name, $typeRestriction);
|
||||
if (!$dots && \count($this->config->getSearchList()) === 0) {
|
||||
throw new DnsException("Giving up resolution of '{$name}', unknown host");
|
||||
}
|
||||
|
||||
$searchList = [null];
|
||||
if (!$trailingDot && $dots < $this->config->getNdots()) {
|
||||
$searchList = \array_merge($this->config->getSearchList(), $searchList);
|
||||
}
|
||||
|
||||
foreach ($searchList as $search) {
|
||||
for ($redirects = 0; $redirects < 5; $redirects++) {
|
||||
$searchName = $name;
|
||||
|
||||
if ($search !== null) {
|
||||
$searchName = $name . "." . $search;
|
||||
}
|
||||
|
||||
try {
|
||||
list(, $records) = yield Promise\some([
|
||||
$this->query($name, Record::A),
|
||||
$this->query($name, Record::AAAA),
|
||||
]);
|
||||
|
||||
return \array_merge(...$records);
|
||||
} catch (MultiReasonException $e) {
|
||||
$errors = [];
|
||||
|
||||
foreach ($e->getReasons() as $reason) {
|
||||
if ($reason instanceof NoRecordException) {
|
||||
throw $reason;
|
||||
}
|
||||
|
||||
$errors[] = $reason->getMessage();
|
||||
if ($typeRestriction) {
|
||||
return yield $this->query($searchName, $typeRestriction);
|
||||
}
|
||||
|
||||
throw new DnsException(
|
||||
"All query attempts failed for {$name}: " . \implode(", ", $errors),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
} catch (NoRecordException $e) {
|
||||
try {
|
||||
/** @var Record[] $cnameRecords */
|
||||
$cnameRecords = yield $this->query($name, Record::CNAME);
|
||||
$name = $cnameRecords[0]->getValue();
|
||||
continue;
|
||||
try {
|
||||
list(, $records) = yield Promise\some([
|
||||
$this->query($searchName, Record::A),
|
||||
$this->query($searchName, Record::AAAA),
|
||||
]);
|
||||
|
||||
return \array_merge(...$records);
|
||||
} catch (MultiReasonException $e) {
|
||||
$errors = [];
|
||||
|
||||
foreach ($e->getReasons() as $reason) {
|
||||
if ($reason instanceof NoRecordException) {
|
||||
throw $reason;
|
||||
}
|
||||
|
||||
$errors[] = $reason->getMessage();
|
||||
}
|
||||
|
||||
throw new DnsException(
|
||||
"All query attempts failed for {$searchName}: " . \implode(", ", $errors),
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
} catch (NoRecordException $e) {
|
||||
/** @var Record[] $dnameRecords */
|
||||
$dnameRecords = yield $this->query($name, Record::DNAME);
|
||||
$name = $dnameRecords[0]->getValue();
|
||||
continue;
|
||||
try {
|
||||
/** @var Record[] $cnameRecords */
|
||||
$cnameRecords = yield $this->query($searchName, Record::CNAME);
|
||||
$name = $cnameRecords[0]->getValue();
|
||||
continue;
|
||||
} catch (NoRecordException $e) {
|
||||
/** @var Record[] $dnameRecords */
|
||||
$dnameRecords = yield $this->query($searchName, Record::DNAME);
|
||||
$name = $dnameRecords[0]->getValue();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new DnsException("Giving up resolution of '{$name}', too many redirects");
|
||||
throw new DnsException("Giving up resolution of '{$searchName}', too many redirects");
|
||||
});
|
||||
}
|
||||
|
||||
@ -268,7 +289,8 @@ final class Rfc1035StubResolver implements Resolver
|
||||
return $this->decodeCachedResult($name, $type, $cachedValue);
|
||||
}
|
||||
|
||||
$nameservers = $this->config->getNameservers();
|
||||
$nameservers = $this->selectNameservers();
|
||||
$nameserversCount = \count($nameservers);
|
||||
$attempts = $this->config->getAttempts();
|
||||
$protocol = "udp";
|
||||
$attempt = 0;
|
||||
@ -285,9 +307,7 @@ final class Rfc1035StubResolver implements Resolver
|
||||
unset($this->sockets[$uri]);
|
||||
$socket->close();
|
||||
|
||||
/** @var Socket $server */
|
||||
$i = $attempt % \count($nameservers);
|
||||
$uri = $protocol . "://" . $nameservers[$i];
|
||||
$uri = $protocol . "://" . $nameservers[$attempt % $nameserversCount];
|
||||
$socket = yield $this->getSocket($uri);
|
||||
}
|
||||
|
||||
@ -309,8 +329,7 @@ final class Rfc1035StubResolver implements Resolver
|
||||
if ($protocol !== "tcp") {
|
||||
// Retry with TCP, don't count attempt
|
||||
$protocol = "tcp";
|
||||
$i = $attempt % \count($nameservers);
|
||||
$uri = $protocol . "://" . $nameservers[$i];
|
||||
$uri = $protocol . "://" . $nameservers[$attempt % $nameserversCount];
|
||||
$socket = yield $this->getSocket($uri);
|
||||
continue;
|
||||
}
|
||||
@ -356,8 +375,7 @@ final class Rfc1035StubResolver implements Resolver
|
||||
$socket->close();
|
||||
});
|
||||
|
||||
$i = ++$attempt % \count($nameservers);
|
||||
$uri = $protocol . "://" . $nameservers[$i];
|
||||
$uri = $protocol . "://" . $nameservers[++$attempt % $nameserversCount];
|
||||
$socket = yield $this->getSocket($uri);
|
||||
|
||||
continue;
|
||||
@ -488,10 +506,28 @@ final class Rfc1035StubResolver implements Resolver
|
||||
return $server;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DnsException
|
||||
*/
|
||||
private function assertAcceptableResponse(Message $response)
|
||||
{
|
||||
if ($response->getResponseCode() !== 0) {
|
||||
throw new DnsException(\sprintf("Server returned error code: %d", $response->getResponseCode()));
|
||||
}
|
||||
}
|
||||
|
||||
private function selectNameservers(): array
|
||||
{
|
||||
$nameservers = $this->config->getNameservers();
|
||||
|
||||
if ($this->config->isRotationEnabled() && ($nameserversCount = \count($nameservers)) > 1) {
|
||||
$nameservers = \array_merge(
|
||||
\array_slice($nameservers, $this->nextNameserver),
|
||||
\array_slice($nameservers, 0, $this->nextNameserver)
|
||||
);
|
||||
$this->nextNameserver = ++$this->nextNameserver % $nameserversCount;
|
||||
}
|
||||
|
||||
return $nameservers;
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,23 @@ use function Amp\call;
|
||||
|
||||
class UnixConfigLoader implements ConfigLoader
|
||||
{
|
||||
const MAX_NAMESERVERS = 3;
|
||||
const MAX_DNS_SEARCH = 6;
|
||||
|
||||
const MAX_TIMEOUT = 30 * 1000;
|
||||
const MAX_ATTEMPTS = 5;
|
||||
const MAX_NDOTS = 15;
|
||||
|
||||
const DEFAULT_TIMEOUT = 5 * 1000;
|
||||
const DEFAULT_ATTEMPTS = 2;
|
||||
const DEFAULT_NDOTS = 1;
|
||||
|
||||
const DEFAULT_OPTIONS = [
|
||||
"timeout" => self::DEFAULT_TIMEOUT,
|
||||
"attempts" => self::DEFAULT_ATTEMPTS,
|
||||
"ndots" => self::DEFAULT_NDOTS,
|
||||
"rotate" => false,
|
||||
];
|
||||
private $path;
|
||||
private $hostLoader;
|
||||
|
||||
@ -40,8 +57,20 @@ class UnixConfigLoader implements ConfigLoader
|
||||
{
|
||||
return call(function () {
|
||||
$nameservers = [];
|
||||
$timeout = 3000;
|
||||
$attempts = 2;
|
||||
$searchList = [];
|
||||
$options = self::DEFAULT_OPTIONS;
|
||||
$haveLocaldomainEnv = false;
|
||||
|
||||
/* Allow user to override the local domain definition. */
|
||||
if ($localdomain = \getenv("LOCALDOMAIN")) {
|
||||
/* Set search list to be blank-separated strings from rest of
|
||||
env value. Permits users of LOCALDOMAIN to still have a
|
||||
search list, and anyone to set the one that they want to use
|
||||
as an individual (even more important now that the rfc1535
|
||||
stuff restricts searches). */
|
||||
$searchList = $this->splitOnWhitespace($localdomain);
|
||||
$haveLocaldomainEnv = true;
|
||||
}
|
||||
|
||||
$fileContent = yield $this->readFile($this->path);
|
||||
|
||||
@ -57,6 +86,9 @@ class UnixConfigLoader implements ConfigLoader
|
||||
list($type, $value) = $line;
|
||||
|
||||
if ($type === "nameserver") {
|
||||
if (\count($nameservers) === self::MAX_NAMESERVERS) {
|
||||
continue;
|
||||
}
|
||||
$value = \trim($value);
|
||||
$ip = @\inet_pton($value);
|
||||
|
||||
@ -69,29 +101,90 @@ class UnixConfigLoader implements ConfigLoader
|
||||
} else { // IPv4
|
||||
$nameservers[] = $value . ":53";
|
||||
}
|
||||
} elseif ($type === "domain" && !$haveLocaldomainEnv) { // LOCALDOMAIN env overrides config
|
||||
$searchList = $this->splitOnWhitespace($value);
|
||||
} elseif ($type === "search" && !$haveLocaldomainEnv) { // LOCALDOMAIN env overrides config
|
||||
$searchList = $this->splitOnWhitespace($value);
|
||||
} elseif ($type === "options") {
|
||||
$optline = \preg_split('#\s+#', $value, 2);
|
||||
|
||||
if (\count($optline) !== 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list($option, $value) = $optline;
|
||||
|
||||
switch ($option) {
|
||||
case "timeout":
|
||||
$timeout = (int) $value;
|
||||
break;
|
||||
|
||||
case "attempts":
|
||||
$attempts = (int) $value;
|
||||
$option = $this->parseOption($value);
|
||||
if (\count($option) === 2) {
|
||||
$options[$option[0]] = $option[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$hosts = yield $this->hostLoader->loadHosts();
|
||||
|
||||
return new Config($nameservers, $hosts, $timeout, $attempts);
|
||||
if (\count($searchList) === 0) {
|
||||
$hostname = \gethostname();
|
||||
$dot = \strpos(".", $hostname);
|
||||
if ($dot !== false && $dot < \strlen($hostname)) {
|
||||
$searchList = [
|
||||
\substr($hostname, $dot),
|
||||
];
|
||||
}
|
||||
}
|
||||
if (\count($searchList) > self::MAX_DNS_SEARCH) {
|
||||
$searchList = \array_slice($searchList, 0, self::MAX_DNS_SEARCH);
|
||||
}
|
||||
|
||||
$resOptions = \getenv("RES_OPTIONS");
|
||||
if ($resOptions) {
|
||||
foreach ($this->splitOnWhitespace($resOptions) as $option) {
|
||||
$option = $this->parseOption($option);
|
||||
if (\count($option) === 2) {
|
||||
$options[$option[0]] = $option[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config = new Config($nameservers, $hosts, $options["timeout"], $options["attempts"]);
|
||||
|
||||
return $config->withSearchList($searchList)
|
||||
->withNdots($options["ndots"])
|
||||
->withRotationEnabled($options["rotate"]);
|
||||
});
|
||||
}
|
||||
|
||||
private function splitOnWhitespace(string $names): array
|
||||
{
|
||||
return \preg_split("#\s+#", \trim($names));
|
||||
}
|
||||
|
||||
private function parseOption(string $option): array
|
||||
{
|
||||
$optline = \explode(':', $option, 2);
|
||||
list($name, $value) = $optline + [1 => null];
|
||||
|
||||
switch ($name) {
|
||||
case "timeout":
|
||||
$value = (int) $value;
|
||||
if ($value < 0) {
|
||||
return []; // don't overwrite option value
|
||||
}
|
||||
// The value for this option is silently capped to 30s
|
||||
return ["timeout", (int) \min($value * 1000, self::MAX_TIMEOUT)];
|
||||
|
||||
case "attempts":
|
||||
$value = (int) $value;
|
||||
if ($value < 0) {
|
||||
return []; // don't overwrite option value
|
||||
}
|
||||
// The value for this option is silently capped to 5
|
||||
return ["attempts", (int) \min($value, self::MAX_ATTEMPTS)];
|
||||
|
||||
case "ndots":
|
||||
$value = (int) $value;
|
||||
if ($value < 0) {
|
||||
return []; // don't overwrite option value
|
||||
}
|
||||
// The value for this option is silently capped to 15
|
||||
return ["ndots", (int) \min($value, self::MAX_NDOTS)];
|
||||
|
||||
case "rotate":
|
||||
return ["rotate", true];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
@ -74,4 +74,38 @@ class ConfigTest extends TestCase
|
||||
$this->expectException(ConfigException::class);
|
||||
new Config(["127.0.0.1"], [], 500, 0);
|
||||
}
|
||||
|
||||
public function testInvalidNtods()
|
||||
{
|
||||
$this->expectException(ConfigException::class);
|
||||
$config = new Config(["127.0.0.1"]);
|
||||
$config->withNdots(-1);
|
||||
}
|
||||
|
||||
public function testNdots()
|
||||
{
|
||||
$config = new Config(["127.0.0.1"]);
|
||||
$config = $config->withNdots(1);
|
||||
$this->assertSame(1, $config->getNdots());
|
||||
}
|
||||
|
||||
public function testSearchList()
|
||||
{
|
||||
$config = new Config(["127.0.0.1"]);
|
||||
$config = $config->withSearchList(['local']);
|
||||
$this->assertSame(['local'], $config->getSearchList());
|
||||
}
|
||||
|
||||
public function testRotationEnabled()
|
||||
{
|
||||
$config = new Config(["127.0.0.1"]);
|
||||
$config = $config->withRotationEnabled(true);
|
||||
$this->assertTrue($config->isRotationEnabled());
|
||||
}
|
||||
|
||||
public function testRotationDisabled()
|
||||
{
|
||||
$config = new Config(["127.0.0.1"]);
|
||||
$this->assertFalse($config->isRotationEnabled());
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,17 @@
|
||||
|
||||
namespace Amp\Dns\Test;
|
||||
|
||||
use Amp\Cache\NullCache;
|
||||
use Amp\Dns;
|
||||
use Amp\Dns\BlockingFallbackResolver;
|
||||
use Amp\Dns\DnsException;
|
||||
use Amp\Dns\Record;
|
||||
use Amp\Dns\UnixConfigLoader;
|
||||
use Amp\Dns\WindowsConfigLoader;
|
||||
use Amp\Loop;
|
||||
use Amp\PHPUnit\TestCase;
|
||||
use Amp\Success;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class IntegrationTest extends TestCase
|
||||
{
|
||||
@ -25,7 +31,7 @@ class IntegrationTest extends TestCase
|
||||
$inAddr = @\inet_pton($record->getValue());
|
||||
$this->assertNotFalse(
|
||||
$inAddr,
|
||||
"Server name $hostname did not resolve to a valid IP address"
|
||||
"Server name {$hostname} did not resolve to a valid IP address"
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -95,6 +101,87 @@ class IntegrationTest extends TestCase
|
||||
});
|
||||
}
|
||||
|
||||
public function testResolveUsingSearchList()
|
||||
{
|
||||
Loop::run(function () {
|
||||
$configLoader = \stripos(PHP_OS, "win") === 0
|
||||
? new WindowsConfigLoader()
|
||||
: new UnixConfigLoader();
|
||||
/** @var Dns\Config $config */
|
||||
$config = yield $configLoader->loadConfig();
|
||||
$config = $config->withSearchList(['kelunik.com']);
|
||||
$config = $config->withNdots(1);
|
||||
/** @var Dns\ConfigLoader|MockObject $configLoader */
|
||||
$configLoader = $this->createMock(Dns\ConfigLoader::class);
|
||||
$configLoader->expects($this->once())
|
||||
->method('loadConfig')
|
||||
->willReturn(new Success($config));
|
||||
|
||||
Dns\resolver(new Dns\Rfc1035StubResolver(null, $configLoader));
|
||||
$result = yield Dns\resolve('blog');
|
||||
|
||||
/** @var Record $record */
|
||||
$record = $result[0];
|
||||
$inAddr = @\inet_pton($record->getValue());
|
||||
$this->assertNotFalse(
|
||||
$inAddr,
|
||||
"Server name blog.kelunik.com did not resolve to a valid IP address"
|
||||
);
|
||||
|
||||
$result = yield Dns\query('blog.kelunik.com', Dns\Record::A);
|
||||
/** @var Record $record */
|
||||
$record = $result[0];
|
||||
$this->assertSame($inAddr, @\inet_pton($record->getValue()));
|
||||
});
|
||||
}
|
||||
|
||||
public function testFailResolveRootedDomainWhenSearchListDefined()
|
||||
{
|
||||
Loop::run(function () {
|
||||
$configLoader = \stripos(PHP_OS, "win") === 0
|
||||
? new WindowsConfigLoader()
|
||||
: new UnixConfigLoader();
|
||||
/** @var Dns\Config $config */
|
||||
$config = yield $configLoader->loadConfig();
|
||||
$config = $config->withSearchList(['kelunik.com']);
|
||||
$config = $config->withNdots(1);
|
||||
/** @var Dns\ConfigLoader|MockObject $configLoader */
|
||||
$configLoader = $this->createMock(Dns\ConfigLoader::class);
|
||||
$configLoader->expects($this->once())
|
||||
->method('loadConfig')
|
||||
->willReturn(new Success($config));
|
||||
|
||||
Dns\resolver(new Dns\Rfc1035StubResolver(null, $configLoader));
|
||||
$this->expectException(DnsException::class);
|
||||
yield Dns\resolve('blog.');
|
||||
});
|
||||
}
|
||||
|
||||
public function testResolveWithRotateList()
|
||||
{
|
||||
Loop::run(function () {
|
||||
/** @var Dns\ConfigLoader|MockObject $configLoader */
|
||||
$configLoader = $this->createMock(Dns\ConfigLoader::class);
|
||||
$config = new Dns\Config([
|
||||
'208.67.222.220:53', // Opendns, US
|
||||
'195.243.214.4:53', // Deutche Telecom AG, DE
|
||||
]);
|
||||
$config = $config->withRotationEnabled(true);
|
||||
$configLoader->expects($this->once())
|
||||
->method('loadConfig')
|
||||
->willReturn(new Success($config));
|
||||
|
||||
$resolver = new Dns\Rfc1035StubResolver(new NullCache(), $configLoader);
|
||||
|
||||
/** @var Record $record1 */
|
||||
list($record1) = yield $resolver->query('facebook.com', Dns\Record::A);
|
||||
/** @var Record $record2 */
|
||||
list($record2) = yield $resolver->query('facebook.com', Dns\Record::A);
|
||||
|
||||
$this->assertNotSame($record1->getValue(), $record2->getValue());
|
||||
});
|
||||
}
|
||||
|
||||
public function testPtrLookup()
|
||||
{
|
||||
Loop::run(function () {
|
||||
@ -179,6 +266,7 @@ class IntegrationTest extends TestCase
|
||||
["localhost"],
|
||||
["192.168.0.1"],
|
||||
["::1"],
|
||||
["dns.google."], /* that's rooted domain name - cannot use searchList */
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -22,8 +22,87 @@ class UnixConfigLoaderTest extends TestCase
|
||||
"[2001:4860:4860::8888]:53",
|
||||
], $result->getNameservers());
|
||||
|
||||
$this->assertSame(5000, $result->getTimeout());
|
||||
$this->assertSame(30000, $result->getTimeout());
|
||||
$this->assertSame(3, $result->getAttempts());
|
||||
$this->assertEmpty($result->getSearchList());
|
||||
$this->assertSame(1, $result->getNdots());
|
||||
$this->assertFalse($result->isRotationEnabled());
|
||||
}
|
||||
|
||||
public function testWithSearchList()
|
||||
{
|
||||
$loader = new UnixConfigLoader(__DIR__ . "/data/resolv-search.conf");
|
||||
|
||||
/** @var Config $result */
|
||||
$result = wait($loader->loadConfig());
|
||||
|
||||
$this->assertSame([
|
||||
"127.0.0.1:53",
|
||||
"[2001:4860:4860::8888]:53",
|
||||
], $result->getNameservers());
|
||||
|
||||
$this->assertSame(30000, $result->getTimeout());
|
||||
$this->assertSame(3, $result->getAttempts());
|
||||
$this->assertSame(['local', 'local1', 'local2', 'local3', 'local4', 'local5'], $result->getSearchList());
|
||||
$this->assertSame(15, $result->getNdots());
|
||||
$this->assertFalse($result->isRotationEnabled());
|
||||
}
|
||||
|
||||
public function testWithRotateOption()
|
||||
{
|
||||
$loader = new UnixConfigLoader(__DIR__ . "/data/resolv-rotate.conf");
|
||||
|
||||
/** @var Config $result */
|
||||
$result = wait($loader->loadConfig());
|
||||
|
||||
$this->assertSame([
|
||||
"127.0.0.1:53",
|
||||
"[2001:4860:4860::8888]:53",
|
||||
], $result->getNameservers());
|
||||
|
||||
$this->assertSame(5000, $result->getTimeout());
|
||||
$this->assertSame(2, $result->getAttempts());
|
||||
$this->assertTrue($result->isRotationEnabled());
|
||||
}
|
||||
|
||||
public function testWithNegativeOption()
|
||||
{
|
||||
$loader = new UnixConfigLoader(__DIR__ . "/data/resolv-negative-option-values.conf");
|
||||
|
||||
/** @var Config $result */
|
||||
$result = wait($loader->loadConfig());
|
||||
|
||||
$this->assertSame([
|
||||
"127.0.0.1:53",
|
||||
"[2001:4860:4860::8888]:53",
|
||||
], $result->getNameservers());
|
||||
|
||||
$this->assertSame(5000, $result->getTimeout());
|
||||
$this->assertSame(2, $result->getAttempts());
|
||||
$this->assertSame(1, $result->getNdots());
|
||||
}
|
||||
|
||||
public function testWithEnvironmentOverride()
|
||||
{
|
||||
\putenv("LOCALDOMAIN=local");
|
||||
\putenv("RES_OPTIONS=timeout:1 attempts:10 ndots:10 rotate");
|
||||
|
||||
$loader = new UnixConfigLoader(__DIR__ . "/data/resolv.conf");
|
||||
|
||||
/** @var Config $result */
|
||||
$result = wait($loader->loadConfig());
|
||||
|
||||
$this->assertSame([
|
||||
"127.0.0.1:53",
|
||||
"[2001:4860:4860::8888]:53",
|
||||
], $result->getNameservers());
|
||||
|
||||
$this->assertSame(['local'], $result->getSearchList());
|
||||
|
||||
$this->assertSame(1000, $result->getTimeout());
|
||||
$this->assertSame(5, $result->getAttempts());
|
||||
$this->assertSame(10, $result->getNdots());
|
||||
$this->assertTrue($result->isRotationEnabled());
|
||||
}
|
||||
|
||||
public function testNoDefaultsOnConfNotFound()
|
||||
|
9
test/data/resolv-negative-option-values.conf
Normal file
9
test/data/resolv-negative-option-values.conf
Normal file
@ -0,0 +1,9 @@
|
||||
# Default
|
||||
nameserver 127.0.0.1
|
||||
|
||||
# Google Fallback
|
||||
nameserver 2001:4860:4860::8888
|
||||
|
||||
options timeout:-1
|
||||
options attempts:-1
|
||||
options ndots:-1
|
10
test/data/resolv-rotate.conf
Normal file
10
test/data/resolv-rotate.conf
Normal file
@ -0,0 +1,10 @@
|
||||
# Default
|
||||
nameserver 127.0.0.1
|
||||
|
||||
# Google Fallback
|
||||
nameserver 2001:4860:4860::8888
|
||||
|
||||
# Invalid server gets ignored
|
||||
nameserver foobar
|
||||
|
||||
options rotate
|
17
test/data/resolv-search.conf
Normal file
17
test/data/resolv-search.conf
Normal file
@ -0,0 +1,17 @@
|
||||
# Default
|
||||
nameserver 127.0.0.1
|
||||
|
||||
# Google Fallback
|
||||
nameserver 2001:4860:4860::8888
|
||||
|
||||
# Invalid server gets ignored
|
||||
nameserver foobar
|
||||
|
||||
search local local1 local2 local3 local4 local5 local6
|
||||
|
||||
options timeout:5000
|
||||
options attempts:3
|
||||
options ndots:20
|
||||
|
||||
# Unknown option gets ignored
|
||||
options foo
|
@ -7,8 +7,8 @@ nameserver 2001:4860:4860::8888
|
||||
# Invalid server gets ignored
|
||||
nameserver foobar
|
||||
|
||||
options timeout 5000
|
||||
options attempts 3
|
||||
options timeout:5000
|
||||
options attempts:3
|
||||
|
||||
# Unknown option gets ignored
|
||||
options foo
|
||||
options foo
|
||||
|
Loading…
Reference in New Issue
Block a user