' . preg_quote($_POST['zone'], '/') . '[\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 zone content $new_zone_content = $matches['soa'] . LF; if (strlen($_POST['zone-content']) > ZONE_MAX_CHARACTERS) output(403, sprintf(_('The zone is limited to %s characters.'), ZONE_MAX_CHARACTERS)); foreach (explode("\r\n", $_POST['zone-content']) as $line) { if ($line === '') continue; if (preg_match('/^(?[a-z0-9@._-]{1,256})(?:[\t ]+(?[0-9]{1,16}))?(?:[\t ]+IN)?[\t ]+(?[A-Z]{1,16})[\t ]+(?.+)$/D', $line, $matches) !== 1) output(403, _('The following line does not match the expected format: ') . '' . htmlspecialchars($line) . ''); if (in_array($matches['type'], ALLOWED_TYPES, true) !== true) output(403, sprintf(_('The %s type is not allowed.'), '' . $matches['type'] . '')); if ($matches['ttl'] !== '' AND $matches['ttl'] < MIN_TTL) output(403, sprintf(_('TTLs shorter than %s seconds are forbidden.'), MIN_TTL)); if ($matches['ttl'] !== '' AND $matches['ttl'] > MAX_TTL) output(403, sprintf(_('TTLs longer than %s seconds are forbidden.'), MAX_TTL)); $new_zone_content .= $matches['domain'] . ' ' . (($matches['ttl'] === '') ? 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 ' . $_POST['zone'] . ' --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 zone content is not correct (according to kzonecheck).')); ratelimit(); exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 3 zone-freeze ' . $_POST['zone'], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to freeze zone file.', $output); exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 3 zone-flush ' . $_POST['zone'], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to flush zone file.', $output); if (file_put_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone', $new_zone_content) === false) output(500, 'Failed to write zone file.'); exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 3 zone-reload ' . $_POST['zone'], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to reload zone file.', $output); exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 3 zone-thaw ' . $_POST['zone'], $output, $return_code); if ($return_code !== 0) output(500, 'Failed to thaw zone file.', $output); usleep(1000000); } // Display zone $zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone'); if ($zone_content === false) output(500, 'Unable to read zone file.'); $data['zone_content'] = ''; foreach (explode(LF, $zone_content) 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['zone'], '/') . '[\t ]+[0-9]{1,8}[\t ]+(?[A-Z]{1,16})[\t ]+.+$/D', $zone_line, $matches)) { if (in_array($matches['type'], ALLOWED_TYPES, true) !== true) continue; $data['zone_content'] .= $zone_line . LF; } } $data['zone_content'] .= LF;