Added host:create EPP command

This commit is contained in:
Pinga 2023-08-19 21:48:31 +03:00
parent 1d31db8e6c
commit 2bcba151f4
4 changed files with 217 additions and 1 deletions

View file

@ -842,7 +842,7 @@ class EppWriter {
$writer->writeAttribute('xmlns:host', 'urn:ietf:params:xml:ns:host-1.0'); $writer->writeAttribute('xmlns:host', 'urn:ietf:params:xml:ns:host-1.0');
$writer->writeAttribute('xsi:schemaLocation', 'urn:ietf:params:xml:ns:host-1.0 host-1.0.xsd'); $writer->writeAttribute('xsi:schemaLocation', 'urn:ietf:params:xml:ns:host-1.0 host-1.0.xsd');
$writer->writeElement('host:name', $resp['name']); $writer->writeElement('host:name', $resp['name']);
$writer->writeElement('host:crDate', $resp['crDate']); $writer->writeElement('host:crDate', gmdate('Y-m-d\TH:i:s\.0\Z', strtotime($resp['crDate'])));
$writer->endElement(); // End of 'host:creData' $writer->endElement(); // End of 'host:creData'
$writer->endElement(); // End of 'resData' $writer->endElement(); // End of 'resData'
} }

View file

@ -388,4 +388,172 @@ function processContactCreate($conn, $db, $xml, $clid, $database_type) {
$epp = new EPP\EppWriter(); $epp = new EPP\EppWriter();
$xml = $epp->epp_writer($response); $xml = $epp->epp_writer($response);
sendEppResponse($conn, $xml); sendEppResponse($conn, $xml);
}
function processHostCreate($conn, $db, $xml, $clid, $database_type) {
$hostName = $xml->command->create->children('urn:ietf:params:xml:ns:host-1.0')->create->name;
$clTRID = (string) $xml->command->clTRID;
$hostName = strtoupper($hostName);
if (preg_match('/^([A-Z0-9]([A-Z0-9-]{0,61}[A-Z0-9]){0,1}\.){1,125}[A-Z0-9]([A-Z0-9-]{0,61}[A-Z0-9])$/i', $hostName) && strlen($hostName) < 254) {
$host_id_already_exist = $db->query("SELECT id FROM host WHERE name = '$hostName' LIMIT 1")->fetchColumn();
if ($host_id_already_exist) {
sendEppError($conn, 2302, 'host:name already exists');
return;
}
} else {
sendEppError($conn, 2005, 'Invalid host:name');
return;
}
$host_addr_list = $xml->xpath('//addr');
if (count($host_addr_list) > 13) {
sendEppError($conn, 2306, 'Parameter value policy error');
return;
}
$stmt = $db->prepare("SELECT id FROM registrar WHERE clid = :clid LIMIT 1");
$stmt->bindParam(':clid', $clid, PDO::PARAM_STR);
$stmt->execute();
$clid = $stmt->fetch(PDO::FETCH_ASSOC);
$clid = $clid['id'];
$nsArr = [];
foreach ($host_addr_list as $node) {
$addr = (string)$node;
$addr_type = (string) $node['ip'] ?? 'v4';
if ($addr_type === 'v6') {
$addr = normalize_v6_address($addr);
} else {
$addr = normalize_v4_address($addr);
}
// v6 IP validation
if ($addr_type === 'v6' && !filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
sendEppError($conn, 2005, 'Invalid host:addr v6');
return;
}
// v4 IP validation
if ($addr_type !== 'v6' && !filter_var($addr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
sendEppError($conn, 2005, 'Invalid host:addr v4');
return;
}
// check for duplicate IPs
if (isset($nsArr[$addr_type][$addr])) {
sendEppError($conn, 2306, 'Duplicated host:addr');
return;
}
$nsArr[$addr_type][$addr] = $addr;
}
$internal_host = false;
$query = "SELECT tld FROM domain_tld";
foreach ($db->query($query) as $row) {
if (preg_match("/" . preg_quote(strtoupper($row['tld']), '/') . "$/i", $hostName)) {
$internal_host = true;
break;
}
}
if ($internal_host) {
$domain_exist = false;
$clid_domain = 0;
$superordinate_dom = 0;
$stmt = $db->prepare("SELECT id,clid,name FROM domain");
$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
if (strpos($hostName, $row['name']) !== false) {
$domain_exist = true;
$clid_domain = $row['clid'];
$superordinate_dom = $row['id'];
break;
}
}
if (!$domain_exist) {
sendEppError($conn, 2303, 'Object does not exist');
return;
}
if ($clid != $clid_domain) {
sendEppError($conn, 2201, 'Authorization error');
return;
}
$stmt = $db->prepare("INSERT INTO host (name,domain_id,clid,crid,crdate) VALUES(?,?,?,?,CURRENT_TIMESTAMP)");
$stmt->execute([$hostName, $superordinate_dom, $clid, $clid]);
$host_id = $db->lastInsertId();
$host_addr_list = $xml->xpath('host:addr');
foreach ($host_addr_list as $node) {
$addr = (string) $node;
$addr_type = isset($node['ip']) ? (string) $node['ip'] : 'v4';
if ($addr_type == 'v6') {
$addr = normalize_v6_address($addr);
} else {
$addr = normalize_v4_address($addr);
}
$addr_type = ($addr_type == 'v6') ? 6 : 4;
$stmt = $db->prepare("INSERT INTO host_addr (host_id,addr,ip) VALUES(?,?,?)");
$stmt->execute([$host_id, $addr, $addr_type]);
}
$stmt = $db->prepare("SELECT crdate FROM host WHERE name = ? LIMIT 1");
$stmt->execute([$hostName]);
$crdate = $stmt->fetchColumn();
$response = [
'command' => 'create_host',
'resultCode' => 1000,
'lang' => 'en-US',
'message' => 'Command completed successfully',
'name' => $hostName,
'crDate' => $crdate,
'clTRID' => $clTRID,
'svTRID' => generateSvTRID(),
];
$epp = new EPP\EppWriter();
$xml = $epp->epp_writer($response);
sendEppResponse($conn, $xml);
} else {
$stmt = $db->prepare("INSERT INTO host (name,clid,crid,crdate) VALUES(?,?,?,CURRENT_TIMESTAMP)");
$stmt->execute([$hostName, $clid, $clid]);
$host_id = $db->lastInsertId();
$stmt = $db->prepare("SELECT crdate FROM host WHERE name = ? LIMIT 1");
$stmt->execute([$hostName]);
$crdate = $stmt->fetchColumn();
$response = [
'command' => 'create_host',
'resultCode' => 1000,
'lang' => 'en-US',
'message' => 'Command completed successfully',
'name' => $hostName,
'crDate' => $crdate,
'clTRID' => $clTRID,
'svTRID' => generateSvTRID(),
];
$epp = new EPP\EppWriter();
$xml = $epp->epp_writer($response);
sendEppResponse($conn, $xml);
}
} }

View file

@ -212,6 +212,17 @@ $server->handle(function (Connection $conn) use ($table, $db, $c) {
break; break;
} }
case isset($xml->command->create) && isset($xml->command->create->children('urn:ietf:params:xml:ns:host-1.0')->create):
{
$data = $table->get($connId);
if (!$data || $data['logged_in'] !== 1) {
sendEppError($conn, 2202, 'Authorization error');
$conn->close();
}
processHostCreate($conn, $db, $xml, $data['clid'], $c['db_type']);
break;
}
case isset($xml->command->info) && isset($xml->command->info->children('urn:ietf:params:xml:ns:host-1.0')->info): case isset($xml->command->info) && isset($xml->command->info->children('urn:ietf:params:xml:ns:host-1.0')->info):
{ {
$data = $table->get($connId); $data = $table->get($connId);

View file

@ -164,4 +164,41 @@ function validate_label($label, $pdo) {
$server->send($fd, "Domain name invalid format"); $server->send($fd, "Domain name invalid format");
return 'Invalid domain name format, please review registry policy about accepted labels'; return 'Invalid domain name format, please review registry policy about accepted labels';
} }
}
function normalize_v4_address($v4) {
// Remove leading zeros from the first octet
$v4 = preg_replace('/^0+(\d)/', '$1', $v4);
// Remove leading zeros from successive octets
$v4 = preg_replace('/\.0+(\d)/', '.$1', $v4);
return $v4;
}
function normalize_v6_address($v6) {
// Upper case any alphabetics
$v6 = strtoupper($v6);
// Remove leading zeros from the first word
$v6 = preg_replace('/^0+([\dA-F])/', '$1', $v6);
// Remove leading zeros from successive words
$v6 = preg_replace('/:0+([\dA-F])/', ':$1', $v6);
// Introduce a :: if there isn't one already
if (strpos($v6, '::') === false) {
$v6 = preg_replace('/:0:0:/', '::', $v6);
}
// Remove initial zero word before a ::
$v6 = preg_replace('/^0+::/', '::', $v6);
// Remove other zero words before a ::
$v6 = preg_replace('/(:0)+::/', '::', $v6);
// Remove zero words following a ::
$v6 = preg_replace('/:(:0)+/', ':', $v6);
return $v6;
} }