Skip to content

Commit 917901e

Browse files
authored
Fix: Zone SOA answer (#42)
* Fix soa zone answer * Fix tests
1 parent 574327f commit 917901e

File tree

3 files changed

+76
-8
lines changed

3 files changed

+76
-8
lines changed

src/DNS/Zone/Resolver.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ public static function lookup(Message $query, Zone $zone): Message
4242
$records = self::selectBestRecords($query, $zone);
4343

4444
if (empty($records)) {
45+
// SOA is stored separately; if querying SOA at the zone apex, return it
46+
if ($question->type === Record::TYPE_SOA && $question->name === $zone->name) {
47+
return self::soaApexResponse($query, $zone);
48+
}
49+
4550
return Message::response(
4651
header: $query->header,
4752
responseCode: Message::RCODE_NXDOMAIN,
@@ -157,6 +162,11 @@ private static function handleExactMatch(array $records, Message $query, Zone $z
157162
$isAuthoritative = $zone->isAuthoritative($question->name);
158163

159164
if ($isAuthoritative) {
165+
// SOA is stored separately in Zone; handle SOA queries at the zone apex
166+
if ($question->type === Record::TYPE_SOA && $question->name === $zone->name) {
167+
return self::soaApexResponse($query, $zone);
168+
}
169+
160170
// Path E1: Exact match of type
161171
$exactTypeRecords = array_filter(
162172
$records,
@@ -215,6 +225,21 @@ private static function handleExactMatch(array $records, Message $query, Zone $z
215225
}
216226
}
217227

228+
/**
229+
* Build an authoritative SOA answer for the zone apex.
230+
*/
231+
private static function soaApexResponse(Message $query, Zone $zone): Message
232+
{
233+
return Message::response(
234+
header: $query->header,
235+
responseCode: Message::RCODE_NOERROR,
236+
questions: $query->questions,
237+
answers: [$zone->soa],
238+
authoritative: true,
239+
recursionAvailable: false
240+
);
241+
}
242+
218243
/**
219244
* Randomize RRSet order for load balancing.
220245
*

tests/e2e/DNS/ClientTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -213,16 +213,16 @@ public function testSoaRecords(): void
213213
$response = $client->query(Message::query(
214214
new Question('appwrite.io', Record::TYPE_SOA)
215215
));
216-
$this->assertCount(0, $response->answers);
216+
$this->assertCount(0, $response->authority);
217217

218-
$authority = $response->authority;
219-
$this->assertCount(1, $authority);
220-
$this->assertSame('appwrite.io', $authority[0]->name);
221-
$this->assertSame(Record::CLASS_IN, $authority[0]->class);
222-
$this->assertSame(30, $authority[0]->ttl);
223-
$this->assertSame(Record::TYPE_SOA, $authority[0]->type);
218+
$answers = $response->answers;
219+
$this->assertCount(1, $answers);
220+
$this->assertSame('appwrite.io', $answers[0]->name);
221+
$this->assertSame(Record::CLASS_IN, $answers[0]->class);
222+
$this->assertSame(30, $answers[0]->ttl);
223+
$this->assertSame(Record::TYPE_SOA, $answers[0]->type);
224224

225-
$rdata = $authority[0]->rdata;
225+
$rdata = $answers[0]->rdata;
226226
$this->assertStringContainsString('ns1.appwrite.zone', $rdata);
227227
$this->assertStringContainsString('team.appwrite.io', $rdata);
228228
$this->assertStringContainsString('1 7200 1800 1209600 3600', $rdata);

tests/unit/DNS/Zone/ResolverTest.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,49 @@ public function testLookupReturnsApexAAAARecord(): void
465465
$this->assertSame($aaaaRecord, $response->answers[0]);
466466
}
467467

468+
public function testLookupReturnsSoaAnswerForApexSoaQueryWithRecords(): void
469+
{
470+
$soa = new Record(
471+
'example.com',
472+
Record::TYPE_SOA,
473+
ttl: 300,
474+
rdata: 'ns1.appwrite.zone. team@appwrite.io. 1761705275 3600 600 86400 300'
475+
);
476+
$aRecord = new Record('example.com', Record::TYPE_A, ttl: 3600, rdata: '1.1.1.1');
477+
$zone = new Zone('example.com', [$aRecord], $soa);
478+
479+
$question = new Question('example.com', Record::TYPE_SOA);
480+
$query = Message::query($question);
481+
$response = Resolver::lookup($query, $zone);
482+
483+
$this->assertSame(Message::RCODE_NOERROR, $response->header->responseCode);
484+
$this->assertCount(1, $response->answers);
485+
$this->assertSame($soa, $response->answers[0]);
486+
$this->assertTrue($response->header->authoritative);
487+
$this->assertFalse($response->header->recursionAvailable);
488+
}
489+
490+
public function testLookupReturnsSoaAnswerForApexSoaQueryWithNoRecords(): void
491+
{
492+
$soa = new Record(
493+
'example.com',
494+
Record::TYPE_SOA,
495+
ttl: 300,
496+
rdata: 'ns1.appwrite.zone. team@appwrite.io. 1761705275 3600 600 86400 300'
497+
);
498+
$zone = new Zone('example.com', [], $soa);
499+
500+
$question = new Question('example.com', Record::TYPE_SOA);
501+
$query = Message::query($question);
502+
$response = Resolver::lookup($query, $zone);
503+
504+
$this->assertSame(Message::RCODE_NOERROR, $response->header->responseCode);
505+
$this->assertCount(1, $response->answers);
506+
$this->assertSame($soa, $response->answers[0]);
507+
$this->assertTrue($response->header->authoritative);
508+
$this->assertFalse($response->header->recursionAvailable);
509+
}
510+
468511
public function testLookupReturnsSoaInAuthorityForApexNonNSQuery(): void
469512
{
470513
$soa = new Record(

0 commit comments

Comments
 (0)