Skip to content

Commit 1bc2f40

Browse files
committed
Add HostsFileExecutor to explicitly take hosts file into account
1 parent 1712012 commit 1bc2f40

3 files changed

Lines changed: 111 additions & 0 deletions

File tree

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ easily be used to create a DNS server.
1414
* [Caching](#caching)
1515
* [Custom cache adapter](#custom-cache-adapter)
1616
* [Advanced usage](#advanced-usage)
17+
* [HostsFileExecutor](#hostsfileexecutor)
1718
* [Install](#install)
1819
* [Tests](#tests)
1920
* [License](#license)
@@ -118,6 +119,24 @@ $loop->run();
118119

119120
See also the [fourth example](examples).
120121

122+
### HostsFileExecutor
123+
124+
Note that the above `Executor` class always performs an actual DNS query.
125+
If you also want to take entries from your hosts file into account, you may
126+
use this code:
127+
128+
```php
129+
$hosts = \React\Dns\Config\HostsFile::loadFromPathBlocking();
130+
131+
$executor = new Executor($loop, new Parser(), new BinaryDumper(), null);
132+
$executor = new HostsFileExecutor($hosts, $executor);
133+
134+
$executor->query(
135+
'8.8.8.8:53',
136+
new Query('localhost', Message::TYPE_A, Message::CLASS_IN, time())
137+
);
138+
```
139+
121140
## Install
122141

123142
The recommended way to install this library is [through Composer](http://getcomposer.org).

src/Query/HostsFileExecutor.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace React\Dns\Query;
4+
5+
use React\Dns\Config\HostsFile;
6+
use React\Dns\Model\Message;
7+
use React\Dns\Model\Record;
8+
use React\Promise;
9+
10+
/**
11+
* Resolves hosts from the givne HostsFile or falls back to another executor
12+
*
13+
* If the host is found in the hosts file, it will not be passed to the actual
14+
* DNS executor. If the host is not found in the hosts file, it will be passed
15+
* to the DNS executor as a fallback.
16+
*/
17+
class HostsFileExecutor implements ExecutorInterface
18+
{
19+
private $hosts;
20+
private $fallback;
21+
22+
public function __construct(HostsFile $hosts, ExecutorInterface $fallback)
23+
{
24+
$this->hosts = $hosts;
25+
$this->fallback = $fallback;
26+
}
27+
28+
public function query($nameserver, Query $query)
29+
{
30+
if ($query->class === Message::CLASS_IN && $query->type === Message::TYPE_A) {
31+
$ips = $this->hosts->getIpsForHost($query->name);
32+
if ($ips) {
33+
$records = array();
34+
foreach ($ips as $ip) {
35+
$records[] = new Record($query->name, $query->type, $query->class, 0, $ip);
36+
}
37+
38+
return Promise\resolve(
39+
Message::createResponseWithAnswersForQuery($query, $records)
40+
);
41+
}
42+
}
43+
44+
return $this->fallback->query($nameserver, $query);
45+
}
46+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace React\Tests\Dns\Query;
4+
5+
use React\Tests\Dns\TestCase;
6+
use React\Dns\Query\HostsFileExecutor;
7+
use React\Dns\Query\Query;
8+
use React\Dns\Model\Message;
9+
10+
class HostsFileExecutorTest extends TestCase
11+
{
12+
private $hosts;
13+
private $fallback;
14+
private $executor;
15+
16+
public function setUp()
17+
{
18+
$this->hosts = $this->getMockBuilder('React\Dns\Config\HostsFile')->disableOriginalConstructor()->getMock();
19+
$this->fallback = $this->getMockBuilder('React\Dns\Query\ExecutorInterface')->getMock();
20+
$this->executor = new HostsFileExecutor($this->hosts, $this->fallback);
21+
}
22+
23+
public function testDoesNotTryToGetIpsForMxQuery()
24+
{
25+
$this->hosts->expects($this->never())->method('getIpsForHost');
26+
$this->fallback->expects($this->once())->method('query');
27+
28+
$this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_MX, Message::CLASS_IN, 0));
29+
}
30+
31+
public function testFallsBackIfNoIpsWereFound()
32+
{
33+
$this->hosts->expects($this->once())->method('getIpsForHost')->willReturn(array());
34+
$this->fallback->expects($this->once())->method('query');
35+
36+
$this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_A, Message::CLASS_IN, 0));
37+
}
38+
39+
public function testReturnsResponseMessageIfIpsWereFound()
40+
{
41+
$this->hosts->expects($this->once())->method('getIpsForHost')->willReturn(array('127.0.0.1'));
42+
$this->fallback->expects($this->never())->method('query');
43+
44+
$ret = $this->executor->query('8.8.8.8', new Query('google.com', Message::TYPE_A, Message::CLASS_IN, 0));
45+
}
46+
}

0 commit comments

Comments
 (0)