edit.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <?php declare(strict_types=1);
  2. nsCheckZonePossession($_POST['domain']);
  3. $path = CONF['ns']['knot_zones_path'] . '/' . $_POST['domain'] . 'zone';
  4. if (isset($_POST['records'])) {
  5. // Get current SOA record
  6. $current_zone_content = file_get_contents($path);
  7. if ($current_zone_content === false)
  8. output(500, 'Unable to read zone file.');
  9. if (preg_match('/^(?<soa>' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,16}[\t ]+SOA[\t ]+.+)$/Dm', $current_zone_content, $matches) !== 1)
  10. output(500, 'Unable to get current SOA record from zone file.');
  11. // Generate new content
  12. $new_zone_content = $matches['soa'] . LF;
  13. if (strlen($_POST['records']) > NS_TEXTAREA_MAX_CHARACTERS)
  14. output(403, sprintf(_('The zone is limited to %s characters.'), NS_TEXTAREA_MAX_CHARACTERS));
  15. foreach (explode("\r\n", $_POST['records']) as $record) {
  16. if ($record === '') continue;
  17. if (preg_match('/^(?<domain>[a-z0-9@._-]{1,256})(?:[\t ]+(?<ttl>[0-9]{1,16}))?(?:[\t ]+IN)?[\t ]+(?<type>[A-Z]{1,16})[\t ]+(?<value>.+)$/D', $record, $matches) !== 1)
  18. output(403, _('The following line does not match the expected format: ') . '<code>' . htmlspecialchars($record) . '</code>');
  19. if (in_array($matches['type'], NS_ALLOWED_TYPES, true) !== true)
  20. output(403, sprintf(_('The %s type is not allowed.'), '<code>' . $matches['type'] . '</code>'));
  21. if ($matches['ttl'] !== '' AND $matches['ttl'] < NS_MIN_TTL)
  22. output(403, sprintf(_('TTLs shorter than %s seconds are forbidden.'), NS_MIN_TTL));
  23. if ($matches['ttl'] !== '' AND $matches['ttl'] > NS_MAX_TTL)
  24. output(403, sprintf(_('TTLs longer than %s seconds are forbidden.'), NS_MAX_TTL));
  25. $new_zone_content .= $matches['domain'] . ' ' . (($matches['ttl'] === '') ? NS_DEFAULT_TTL : $matches['ttl']) . ' ' . $matches['type'] . ' ' . $matches['value'] . LF;
  26. }
  27. // Send the zone content to kzonecheck's stdin
  28. $process = proc_open(CONF['ns']['kzonecheck_path'] . ' --origin ' . escapeshellarg($_POST['domain']) . ' --dnssec off -', [0 => ['pipe', 'r']], $pipes);
  29. if (is_resource($process) !== true)
  30. output(500, 'Can\'t spawn kzonecheck.');
  31. fwrite($pipes[0], $new_zone_content);
  32. fclose($pipes[0]);
  33. if (proc_close($process) !== 0)
  34. output(403, _('Sent content is not correct (according to <code>kzonecheck</code>).'));
  35. ratelimit();
  36. knotc(['zone-freeze', $_POST['domain']], $output, $return_code);
  37. if ($return_code !== 0)
  38. output(500, 'Failed to freeze zone file.', $output);
  39. knotc(['zone-flush', $_POST['domain']], $output, $return_code);
  40. if ($return_code !== 0)
  41. output(500, 'Failed to flush zone file.', $output);
  42. if (file_put_contents($path, $new_zone_content) === false)
  43. output(500, 'Failed to write zone file.');
  44. knotc(['zone-reload', $_POST['domain']], $output, $return_code);
  45. if ($return_code !== 0)
  46. output(500, 'Failed to reload zone file.', $output);
  47. knotc(['zone-thaw', $_POST['domain']], $output, $return_code);
  48. if ($return_code !== 0)
  49. output(500, 'Failed to thaw zone file.', $output);
  50. usleep(1000000);
  51. }
  52. // Display zone
  53. if (($records = file_get_contents($path)) === false)
  54. output(500, 'Unable to read zone file.');
  55. $data['records'] = '';
  56. foreach (explode(LF, $records) as $zone_line) {
  57. if (empty($zone_line) OR str_starts_with($zone_line, ';'))
  58. continue;
  59. if (preg_match('/^(?:(?:[a-z0-9_-]{1,63}\.){1,127})?' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+(?<type>[A-Z]{1,16})[\t ]+.+$/D', $zone_line, $matches)) {
  60. if (in_array($matches['type'], NS_ALLOWED_TYPES, true) !== true)
  61. continue;
  62. $data['records'] .= $zone_line . LF;
  63. }
  64. }
  65. $data['records'] .= LF;