' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,16}[\t ]+SOA[\t ]+.+)$/Dm', $current_zone_content, $matches) !== 1) output(500, 'Unable to get current SOA record from zone file.'); // Generate new content $new_zone_content = $matches['soa'] . LF; if (strlen($_POST['records']) > NS_TEXTAREA_MAX_CHARACTERS) output(403, sprintf(_('The zone is limited to %s characters.'), NS_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'], NS_ALLOWED_TYPES, true) !== true) output(403, sprintf(_('The %s type is not allowed.'), '' . $matches['type'] . '')); if ($matches['ttl'] !== '' AND $matches['ttl'] < NS_MIN_TTL) output(403, sprintf(_('TTLs shorter than %s seconds are forbidden.'), NS_MIN_TTL)); if ($matches['ttl'] !== '' AND $matches['ttl'] > NS_MAX_TTL) output(403, sprintf(_('TTLs longer than %s seconds are forbidden.'), NS_MAX_TTL)); $new_zone_content .= $matches['domain'] . ' ' . (($matches['ttl'] === '') ? NS_DEFAULT_TTL : $matches['ttl']) . ' ' . $matches['type'] . ' ' . $matches['value'] . LF; } // Send the zone content to kzonecheck's stdin $process = proc_open(CONF['ns']['kzonecheck_path'] . ' --origin ' . escapeshellarg($_POST['domain']) . ' --dnssec off -', [0 => ['pipe', 'r']], $pipes); if (is_resource($process) !== true) output(500, 'Can\'t spawn kzonecheck.'); fwrite($pipes[0], $new_zone_content); fclose($pipes[0]); if (proc_close($process) !== 0) output(403, _('Sent content is not correct (according to kzonecheck).')); ratelimit(); knotc(['zone-freeze', $_POST['domain']], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to freeze zone file.', $output); knotc(['zone-flush', $_POST['domain']], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to flush zone file.', $output); if (file_put_contents($path, $new_zone_content) === false) output(500, 'Failed to write zone file.'); knotc(['zone-reload', $_POST['domain']], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to reload zone file.', $output); knotc(['zone-thaw', $_POST['domain']], $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'], NS_ALLOWED_TYPES, true) !== true) continue; $data['records'] .= $zone_line . LF; } } $data['records'] .= LF;