REG_TEXTAREA_MAX_CHARACTERS) output(403, sprintf(_('The zone is limited to %s characters.'), REG_TEXTAREA_MAX_CHARACTERS)); foreach (explode("\r\n", $_POST['records']) as $record) { if ($record === '') continue; if (preg_match('/^(?[a-z0-9@._-]{1,256})(?:[\t ]+(?[0-9]{1,16}))?(?:[\t ]+IN)?[\t ]+(?[A-Z]{1,16})[\t ]+(?.+)$/D', $record, $matches) !== 1) output(403, _('The following line does not match the expected format: ') . '' . htmlspecialchars($record) . ''); if (in_array($matches['type'], REG_ALLOWED_TYPES, true) !== true) output(403, sprintf(_('The %s type is not allowed.'), '' . $matches['type'] . '')); if ($matches['type'] === 'DS' AND count($record_values = explode(' ', $matches['value'])) !== 4) output(403, _('A DS record expects 4 arguments.')); $new_records .= implode(' ', regParseRecord($_POST['domain'], [ 'domain' => $matches['domain'], 'type' => match ($matches['type']) { 'NS', 'DS' => $matches['type'], 'AAAA', 'A' => 'ip', default => output(403, sprintf(_('The %s type is not allowed.'), '' . $matches['type'] . '')), }, ...match ($matches['type']) { 'NS' => ['ns' => $matches['value']], 'AAAA', 'A' => ['ip' => $matches['value']], 'DS' => array_combine([ 'keytag', 'algo', 'dt', 'key', ], $record_values), }, ])) . LF; } // Send the zone content to kzonecheck's stdin $process = proc_open(CONF['ns']['kzonecheck_path'] . ' --origin ' . escapeshellarg($suffix) . ' --dnssec off -', [0 => ['pipe', 'r']], $pipes); if (is_resource($process) !== true) output(500, 'Can\'t spawn kzonecheck.'); $new = $suffix . ' 10800 SOA invalid. invalid. 0 21600 7200 3628800 3600' . LF . $suffix . ' 10800 NS invalid.' . LF . $new_records; fwrite($pipes[0], $new); fclose($pipes[0]); if (proc_close($process) !== 0) output(403, _('Sent content is not correct (according to kzonecheck).')); ratelimit(); knotc(['zone-freeze', $suffix], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to freeze zone file.', $output); knotc(['zone-flush', $suffix], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to flush zone file.', $output); if (($zone_content = file_get_contents($path)) === false) output(500, 'Unable to read zone file.'); $zone_content = regStripDomain($_POST['domain'], $zone_content); if (file_put_contents($path, $zone_content . LF . $new_records) === false) output(500, 'Failed to write zone file.'); knotc(['zone-reload', $suffix], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to reload zone file.', $output); knotc(['zone-thaw', $suffix], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to thaw zone file.', $output); usleep(1000000); } // Display zone if (($records = file_get_contents($path)) === false) output(500, 'Unable to read zone file.'); $data['records'] = ''; foreach (explode(LF, $records) as $zone_line) { if (empty($zone_line) OR str_starts_with($zone_line, ';')) continue; if (preg_match('/^(?:(?:[a-z0-9_-]{1,63}\.){1,127})?' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+(?[A-Z]{1,16})[\t ]+.+$/D', $zone_line, $matches)) { if (in_array($matches['type'], REG_ALLOWED_TYPES, true) !== true) continue; $data['records'] .= $zone_line . LF; } } $data['records'] .= LF;