check rr against possible existing CNAME entries, fixes #927

Signed-off-by: Michael Kaufmann <d00p@froxlor.org>
This commit is contained in:
Michael Kaufmann
2021-03-15 17:33:30 +01:00
parent c8914312aa
commit 91d4432108
4 changed files with 90 additions and 27 deletions

View File

@@ -136,8 +136,24 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
// types // types
if ($type == 'A' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) { if ($type == 'A' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) === false) {
$errors[] = $this->lng['error']['dns_arec_noipv4']; $errors[] = $this->lng['error']['dns_arec_noipv4'];
} elseif ($type == 'A') {
// check whether there is a CNAME-record for the same resource
foreach ($dom_entries as $existing_entries) {
if ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
}
} elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) { } elseif ($type == 'AAAA' && filter_var($content, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
$errors[] = $this->lng['error']['dns_aaaarec_noipv6']; $errors[] = $this->lng['error']['dns_aaaarec_noipv6'];
} elseif ($type == 'AAAA') {
// check whether there is a CNAME-record for the same resource
foreach ($dom_entries as $existing_entries) {
if ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
}
} elseif ($type == 'CAA' && ! empty($content)) { } elseif ($type == 'CAA' && ! empty($content)) {
$re = '/(?\'critical\'\d)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/'; $re = '/(?\'critical\'\d)\h*(?\'type\'iodef|issue|issuewild)\h*(?\'value\'(?\'issuevalue\'"(?\'domain\'(?=.{3,128}$)(?>(?>[a-zA-Z0-9]+[a-zA-Z0-9-]*[a-zA-Z0-9]+|[a-zA-Z0-9]+)\.)*(?>[a-zA-Z]{2,}|[a-zA-Z0-9]{2,}\.[a-zA-Z]{2,}))[;\h]*(?\'parameters\'(?>[a-zA-Z0-9]{1,60}=[a-zA-Z0-9]{1,60}\h*)+)?")|(?\'iodefvalue\'"(?\'url\'(mailto:.*|http:\/\/.*|https:\/\/.*))"))/';
preg_match($re, $content, $matches); preg_match($re, $content, $matches);
@@ -198,6 +214,10 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
$errors[] = $this->lng['error']['dns_mx_noalias']; $errors[] = $this->lng['error']['dns_mx_noalias'];
break; break;
} }
elseif ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
} }
} }
// append trailing dot (again) // append trailing dot (again)
@@ -210,6 +230,14 @@ class DomainZones extends \Froxlor\Api\ApiCommand implements \Froxlor\Api\Resour
} }
if (! \Froxlor\Validate\Validate::validateDomain($content)) { if (! \Froxlor\Validate\Validate::validateDomain($content)) {
$errors[] = $this->lng['error']['dns_ns_invaliddom']; $errors[] = $this->lng['error']['dns_ns_invaliddom'];
} else {
// check whether there is a CNAME-record for the same resource
foreach ($dom_entries as $existing_entries) {
if ($existing_entries['type'] == 'CNAME' && $existing_entries['record'] == $record) {
$errors[] = $this->lng['error']['dns_other_nomorerr'];
break;
}
}
} }
// append trailing dot (again) // append trailing dot (again)
$content .= '.'; $content .= '.';

View File

@@ -1908,6 +1908,7 @@ $lng['error']['dns_mx_needdom'] = 'The MX content value must be a valid domain-n
$lng['error']['dns_mx_noalias'] = 'The MX-content value cannot be an CNAME entry.'; $lng['error']['dns_mx_noalias'] = 'The MX-content value cannot be an CNAME entry.';
$lng['error']['dns_cname_invaliddom'] = 'Invalid domain-name for CNAME record'; $lng['error']['dns_cname_invaliddom'] = 'Invalid domain-name for CNAME record';
$lng['error']['dns_cname_nomorerr'] = 'There already exists a resource-record with the same record-name. It can not be used as CNAME.'; $lng['error']['dns_cname_nomorerr'] = 'There already exists a resource-record with the same record-name. It can not be used as CNAME.';
$lng['error']['dns_other_nomorerr'] = 'There already exists a CNAME record with the same record-name. It can not be used for another type.';
$lng['error']['dns_ns_invaliddom'] = 'Invalid domain-name for NS record'; $lng['error']['dns_ns_invaliddom'] = 'Invalid domain-name for NS record';
$lng['error']['dns_srv_prioempty'] = 'Invalid SRV priority given'; $lng['error']['dns_srv_prioempty'] = 'Invalid SRV priority given';
$lng['error']['dns_srv_invalidcontent'] = 'Invalid SRV content, must contain of fields weight, port and target, e.g.: 5 5060 sipserver.example.com.'; $lng['error']['dns_srv_invalidcontent'] = 'Invalid SRV content, must contain of fields weight, port and target, e.g.: 5 5060 sipserver.example.com.';

View File

@@ -1558,6 +1558,7 @@ $lng['error']['dns_mx_needdom'] = 'Der Wert des MX Eintrags muss ein gültiger D
$lng['error']['dns_mx_noalias'] = 'Der MX Eintrag darf kein CNAME Eintrag sein.'; $lng['error']['dns_mx_noalias'] = 'Der MX Eintrag darf kein CNAME Eintrag sein.';
$lng['error']['dns_cname_invaliddom'] = 'Ungültiger Domain-Name für CNAME Eintrag'; $lng['error']['dns_cname_invaliddom'] = 'Ungültiger Domain-Name für CNAME Eintrag';
$lng['error']['dns_cname_nomorerr'] = 'Es existiert bereits ein Eintrag mit dem gleichen Namen. Dieser Eintrag kann daher nicht für CNAME genutzt werden.'; $lng['error']['dns_cname_nomorerr'] = 'Es existiert bereits ein Eintrag mit dem gleichen Namen. Dieser Eintrag kann daher nicht für CNAME genutzt werden.';
$lng['error']['dns_other_nomorerr'] = 'Es existiert bereits ein CNAME Eintrag mit dem gleichen Namen. Dieser Eintrag kann daher nicht für einen anderen genutzt werden.';
$lng['error']['dns_ns_invaliddom'] = 'Ungültiger Domain-Name für NS Eintrag'; $lng['error']['dns_ns_invaliddom'] = 'Ungültiger Domain-Name für NS Eintrag';
$lng['error']['dns_srv_prioempty'] = 'Ungültige SRV Priorität angegeben'; $lng['error']['dns_srv_prioempty'] = 'Ungültige SRV Priorität angegeben';
$lng['error']['dns_srv_invalidcontent'] = 'Ungültiger Wert des SRV Eintrags, dieser muss aus den Feldern weight, port und target, bestehen. Bsp.: 5 5060 sipserver.example.com.'; $lng['error']['dns_srv_invalidcontent'] = 'Ungültiger Wert des SRV Eintrags, dieser muss aus den Feldern weight, port und target, bestehen. Bsp.: 5 5060 sipserver.example.com.';

View File

@@ -101,6 +101,7 @@ class DomainZonesTest extends TestCase
} }
/** /**
*
* @depends testCustomerDomainZonesAddA * @depends testCustomerDomainZonesAddA
*/ */
public function testAdminDomainZonesListing() public function testAdminDomainZonesListing()
@@ -303,14 +304,14 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
$this->assertTrue(count($result) > 1); $this->assertTrue(count($result) > 1);
$found = false; $found = false;
foreach ($result as $entry) { foreach ($result as $entry) {
if (substr($entry, -strlen($content)) == $content) { if (substr($entry, - strlen($content)) == $content) {
$found = true; $found = true;
break; break;
} }
@@ -328,7 +329,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -341,7 +342,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIssueWithTwoParameters() public function testAdminDomainZonesAddCAAIssueWithTwoParameters()
@@ -353,7 +354,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -366,7 +367,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAInvalidIssueValue() public function testAdminDomainZonesAddCAAInvalidIssueValue()
@@ -378,7 +379,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -393,7 +394,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -408,7 +409,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -423,7 +424,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -436,7 +437,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIssueWildWithParameters() public function testAdminDomainZonesAddCAAIssueWildWithParameters()
@@ -448,7 +449,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -461,7 +462,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIssueWildWithTwoParameters() public function testAdminDomainZonesAddCAAIssueWildWithTwoParameters()
@@ -473,7 +474,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -486,7 +487,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAInvalidIssueWildValue() public function testAdminDomainZonesAddCAAInvalidIssueWildValue()
@@ -498,7 +499,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -513,7 +514,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -528,7 +529,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -543,7 +544,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -556,7 +557,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIodefMailInvalid() public function testAdminDomainZonesAddCAAIodefMailInvalid()
@@ -568,7 +569,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -583,7 +584,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -596,7 +597,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIodefHttpInvalid() public function testAdminDomainZonesAddCAAIodefHttpInvalid()
@@ -608,7 +609,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -623,7 +624,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$json_result = DomainZones::getLocal($admin_userdata, $data)->add(); $json_result = DomainZones::getLocal($admin_userdata, $data)->add();
$result = json_decode($json_result, true)['data']; $result = json_decode($json_result, true)['data'];
@@ -636,7 +637,7 @@ class DomainZonesTest extends TestCase
} }
} }
$this->assertTrue($found); $this->assertTrue($found);
$this->assertEquals('@ 18000 IN CAA '.$content, $entry); $this->assertEquals('@ 18000 IN CAA ' . $content, $entry);
} }
public function testAdminDomainZonesAddCAAIodefHttpsInvalid() public function testAdminDomainZonesAddCAAIodefHttpsInvalid()
@@ -648,7 +649,7 @@ class DomainZonesTest extends TestCase
'domainname' => 'test2.local', 'domainname' => 'test2.local',
'record' => '@', 'record' => '@',
'type' => 'CAA', 'type' => 'CAA',
'content' => $content, 'content' => $content
]; ];
$this->expectExceptionMessage("DNS content invalid"); $this->expectExceptionMessage("DNS content invalid");
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
@@ -745,6 +746,38 @@ class DomainZonesTest extends TestCase
DomainZones::getLocal($admin_userdata, $data)->add(); DomainZones::getLocal($admin_userdata, $data)->add();
} }
/**
*
* @depends testAdminDomainZonesAddCname
*/
public function testAdminDomainZonesAddForExistingCname()
{
global $admin_userdata;
// set domain to www-alias
$data = [
'domainname' => 'test2.local',
'selectserveralias' => '1'
];
Domains::getLocal($admin_userdata, $data)->update();
foreach ([
'A' => '127.0.0.1',
'AAAA' => '::1',
'MX' => 'mail.example.com.',
'NS' => 'ns.example.com.'
] as $type => $val) {
$data = [
'domainname' => 'test2.local',
'record' => 'db',
'type' => $type,
'content' => $val
];
$this->expectExceptionMessage('There already exists a CNAME record with the same record-name. It can not be used for another type.');
DomainZones::getLocal($admin_userdata, $data)->add();
}
}
/** /**
* *
* @depends testAdminDomainZonesAddCname * @depends testAdminDomainZonesAddCname