You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dnssec.inc.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. <?php
  2. /* Poweradmin, a friendly web-based admin tool for PowerDNS.
  3. * See <http://www.poweradmin.org> for more details.
  4. *
  5. * Copyright 2007-2009 Rejo Zenger <rejo@zenger.nl>
  6. * Copyright 2010-2014 Poweradmin Development Team
  7. * <http://www.poweradmin.org/credits.html>
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. /**
  23. * DNSSEC functions
  24. *
  25. * @package Poweradmin
  26. * @copyright 2007-2010 Rejo Zenger <rejo@zenger.nl>
  27. * @copyright 2010-2014 Poweradmin Development Team
  28. * @license http://opensource.org/licenses/GPL-3.0 GPL
  29. */
  30. /** Check if it's possible to execute dnssec command
  31. *
  32. * @return boolean true on success, false on failure
  33. */
  34. function is_pdnssec_callable() {
  35. global $pdnssec_command;
  36. if (!function_exists('exec')) {
  37. error(ERR_EXEC_NOT_ALLOWED);
  38. return false;
  39. }
  40. if (!file_exists($pdnssec_command) || !is_executable($pdnssec_command)) {
  41. error(ERR_EXEC_PDNSSEC);
  42. return false;
  43. }
  44. return true;
  45. }
  46. /** Execute dnssec utility
  47. *
  48. * @return mixed[] Array with output from command execution and error code
  49. */
  50. function call_dnssec($command, $args) {
  51. global $pdnssec_command;
  52. $output = '';
  53. $return_code = -1;
  54. if (!is_pdnssec_callable()) {
  55. return array($output, $return_code);
  56. }
  57. $command = join(' ', array(
  58. $pdnssec_command,
  59. $command,
  60. $args)
  61. );
  62. exec($command, $output, $return_code);
  63. return array($output, $return_code);
  64. }
  65. /** Execute PDNSSEC rectify-zone command for Domain ID
  66. *
  67. * If a Domain is dnssec enabled, or uses features as
  68. * e.g. ALSO-NOTIFY, ALLOW-AXFR-FROM, TSIG-ALLOW-AXFR
  69. * following has to be executed
  70. * pdnssec rectify-zone $domain
  71. *
  72. * @param int $domain_id Domain ID
  73. *
  74. * @return boolean true on success, false on failure or unnecessary
  75. */
  76. function dnssec_rectify_zone($domain_id) {
  77. global $db;
  78. global $pdnssec_command;
  79. $output = array();
  80. /* if pdnssec_command is set we perform ``pdnssec rectify-zone $domain`` on all zones,
  81. * as pdns needs the "auth" column for all zones if dnssec is enabled
  82. *
  83. * If there is any entry at domainmetadata table for this domain,
  84. * it is an error if pdnssec_command is not set */
  85. $query = "SELECT COUNT(id) FROM domainmetadata WHERE domain_id = " . $db->quote($domain_id, 'integer');
  86. $count = $db->queryOne($query);
  87. if (PEAR::isError($count)) {
  88. error($count->getMessage());
  89. return false;
  90. }
  91. if (isset($pdnssec_command)) {
  92. $domain = get_zone_name_from_id($domain_id);
  93. $command = $pdnssec_command . " rectify-zone " . $domain;
  94. if (!is_pdnssec_callable()) {
  95. return false;
  96. }
  97. exec($command, $output, $return_code);
  98. if ($return_code != 0) {
  99. error(ERR_EXEC_PDNSSEC_RECTIFY_ZONE);
  100. return false;
  101. }
  102. return true;
  103. } else if ($count >= 1) {
  104. error(ERR_EXEC_PDNSSEC);
  105. return false;
  106. }
  107. return false;
  108. }
  109. /** Execute PDNSSEC secure-zone command for Domain Name
  110. *
  111. * @param string $domain_name Domain Name
  112. *
  113. * @return boolean true on success, false on failure or unnecessary
  114. */
  115. function dnssec_secure_zone($domain_name) {
  116. $call_result = call_dnssec('secure-zone', $domain_name);
  117. $return_code = $call_result[1];
  118. if ($return_code != 0) {
  119. error(ERR_EXEC_PDNSSEC_SECURE_ZONE);
  120. return false;
  121. }
  122. return true;
  123. }
  124. /** Execute PDNSSEC disable-dnssec command for Domain Name
  125. *
  126. * @param string $domain_name Domain Name
  127. *
  128. * @return boolean true on success, false on failure or unnecessary
  129. */
  130. function dnssec_unsecure_zone($domain_name) {
  131. $call_result = call_dnssec('disable-dnssec', $domain_name);
  132. $return_code = $call_result[1];
  133. if ($return_code != 0) {
  134. error(ERR_EXEC_PDNSSEC_DISABLE_ZONE);
  135. return false;
  136. }
  137. return true;
  138. }
  139. /** Check if zone is secured
  140. *
  141. * @param string $domain_name Domain Name
  142. *
  143. * @return boolean true on success, false on failure
  144. */
  145. function dnssec_is_zone_secured($domain_name) {
  146. $call_result = call_dnssec('show-zone', $domain_name);
  147. $output = $call_result[0];
  148. $return_code = $call_result[1];
  149. if ($return_code != 0) {
  150. error(ERR_EXEC_PDNSSEC_SHOW_ZONE);
  151. return false;
  152. }
  153. return (count($output) == 0 ? false : true);
  154. }
  155. /** Use presigned RRSIGs from storage
  156. *
  157. * @param string $domain_name Domain Name
  158. */
  159. function dnssec_set_nsec3($domain_name) {
  160. call_dnssec('set-nsec3', $domain_name);
  161. }
  162. /** Switch back to NSEC
  163. *
  164. * @param string $domain_name Domain Name
  165. */
  166. function dnssec_unset_nsec3($domain_name) {
  167. call_dnssec('unset-nsec3', $domain_name);
  168. }
  169. /** Return nsec type
  170. *
  171. * @param string $domain_name Domain Name
  172. *
  173. * @return string nsec or nsec3
  174. */
  175. function dnssec_get_nsec_type($domain_name) {
  176. $call_result = call_dnssec('show-zone', $domain_name);
  177. $output = $call_result[0];
  178. return ($output[0] == 'Zone has NSEC semantics' ? 'nsec' : 'nsec3');
  179. }
  180. /** Use presigned RRSIGs from storage
  181. *
  182. * @param string $domain_name Domain Name
  183. */
  184. function dnssec_set_presigned($domain_name) {
  185. call_dnssec('set-presigned', $domain_name);
  186. }
  187. /** No longer use presigned RRSIGs
  188. *
  189. * @param string $domain_name Domain Name
  190. */
  191. function dnssec_unset_presigned($domain_name) {
  192. call_dnssec('unset-presigned', $domain_name);
  193. }
  194. /** Return presigned status
  195. *
  196. * @param string $domain_name Domain Name
  197. *
  198. * @return boolean true if zone is presigned, otherwise false
  199. */
  200. function dnssec_get_presigned_status($domain_name) {
  201. $call_result = call_dnssec('show-zone', $domain_name);
  202. $output = $call_result[0];
  203. return ($output[1] == 'Zone is presigned' ? true : false);
  204. }
  205. /** Rectify all zones.
  206. */
  207. function dnssec_rectify_all_zones() {
  208. call_dnssec('rectify-all-zones', '');
  209. }
  210. /** Return DS records
  211. *
  212. * @param string $domain_name Domain Name
  213. *
  214. * @return mixed[] DS records
  215. */
  216. function dnssec_ds_records($domain_name) {
  217. $call_result = call_dnssec('show-zone', $domain_name);
  218. $output = $call_result[0];
  219. $return_code = $call_result[1];
  220. if ($return_code != 0) {
  221. error(ERR_EXEC_PDNSSEC_SHOW_ZONE);
  222. return false;
  223. }
  224. $ds_records = array();
  225. foreach ($output as $line) {
  226. if (substr($line, 0, 2) == 'DS') {
  227. $items = explode(' ', $line);
  228. $ds_line = join(" ", array_slice($items, 2));
  229. $ds_records[] = $ds_line;
  230. }
  231. }
  232. return $ds_records;
  233. }
  234. /** Return algorithm name for given number
  235. *
  236. * @param int $algo Algorithm id
  237. *
  238. * @return string algorithm name
  239. */
  240. function dnssec_algorithm_to_name($algo) {
  241. $name = 'Unallocated/Reserved';
  242. switch ($algo) {
  243. case 0:
  244. $name = 'Reserved';
  245. break;
  246. case 1:
  247. $name = 'RSAMD5';
  248. break;
  249. case 2:
  250. $name = 'DH';
  251. break;
  252. case 3:
  253. $name = 'DSA';
  254. break;
  255. case 4:
  256. $name = 'ECC';
  257. break;
  258. case 5:
  259. $name = 'RSASHA1';
  260. break;
  261. case 6:
  262. $name = 'DSA-NSEC3-SHA1';
  263. break;
  264. case 7:
  265. $name = 'RSASHA1-NSEC3-SHA1';
  266. break;
  267. case 8:
  268. $name = 'RSASHA256';
  269. break;
  270. case 9:
  271. $name = 'Reserved';
  272. break;
  273. case 10:
  274. $name = 'RSASHA512';
  275. break;
  276. case 11:
  277. $name = 'Reserved';
  278. break;
  279. case 12:
  280. $name = 'ECC-GOST';
  281. break;
  282. case 13:
  283. $name = 'ECDSAP256SHA256';
  284. break;
  285. case 14:
  286. $name = 'ECDSAP384SHA384';
  287. break;
  288. case 252:
  289. $name = 'INDIRECT';
  290. break;
  291. case 253:
  292. $name = 'PRIVATEDNS';
  293. break;
  294. case 254:
  295. $name = 'PRIVATEOID';
  296. break;
  297. }
  298. return $name;
  299. }
  300. /** Return algorihtm name for given short name
  301. *
  302. * @param string $short_name Short algorithm name
  303. */
  304. function dnssec_shorthand_to_algorithm_name($short_name) {
  305. $name = 'Unknown';
  306. switch ($short_name) {
  307. case "rsamd5":
  308. $name = dnssec_algorithm_to_name(1);
  309. break;
  310. case "dh":
  311. $name = dnssec_algorithm_to_name(2);
  312. break;
  313. case "dsa":
  314. $name = dnssec_algorithm_to_name(3);
  315. break;
  316. case "ecc":
  317. $name = dnssec_algorithm_to_name(4);
  318. break;
  319. case "rsasha1":
  320. $name = dnssec_algorithm_to_name(5);
  321. break;
  322. case "rsasha256":
  323. $name = dnssec_algorithm_to_name(8);
  324. break;
  325. case "rsasha512":
  326. $name = dnssec_algorithm_to_name(10);
  327. break;
  328. case "gost":
  329. $name = dnssec_algorithm_to_name(12);
  330. break;
  331. case "ecdsa256":
  332. $name = dnssec_algorithm_to_name(13);
  333. break;
  334. case "ecdsa384":
  335. $name = dnssec_algorithm_to_name(14);
  336. break;
  337. case "ed25519":
  338. $name = dnssec_algorithm_to_name(250);
  339. break;
  340. }
  341. return $name;
  342. }
  343. /** Get name of digest type
  344. *
  345. * @param int $type Digest type id
  346. *
  347. * @return string digest name
  348. */
  349. function dnssec_get_digest_name($type) {
  350. $name = 'Unknown';
  351. switch ($type) {
  352. case 1:
  353. $name = 'SHA-1';
  354. break;
  355. case 2:
  356. $name = 'SHA-256 ';
  357. break;
  358. }
  359. return $name;
  360. }
  361. /** Check if zone is secured
  362. *
  363. * @param string $domain_name Domain Name
  364. *
  365. * @return string string containing dns key
  366. */
  367. function dnssec_dnskey_record($domain_name) {
  368. $call_result = call_dnssec('show-zone', $domain_name);
  369. $output = $call_result[0];
  370. $return_code = $call_result[1];
  371. if ($return_code != 0) {
  372. error(ERR_EXEC_PDNSSEC_SHOW_ZONE);
  373. return false;
  374. }
  375. $dns_key = '';
  376. foreach ($output as $line) {
  377. if (substr($line, 0, 3) == 'KSK') {
  378. $items = explode(' ', $line);
  379. $dns_key = join(" ", array_slice($items, 3));
  380. }
  381. }
  382. return $dns_key;
  383. }
  384. /** Activate zone key
  385. *
  386. * @param string $domain_name Domain Name
  387. *
  388. * @return boolean true on success, false on failure
  389. */
  390. function dnssec_activate_zone_key($domain_name, $key_id) {
  391. $call_result = call_dnssec('activate-zone-key', join(" ", array($domain_name, $key_id)));
  392. $return_code = $call_result[1];
  393. if ($return_code != 0) {
  394. error(ERR_EXEC_PDNSSEC_SHOW_ZONE);
  395. return false;
  396. }
  397. return true;
  398. }
  399. /** Deactivate zone key
  400. *
  401. * @param string $domain_name Domain Name
  402. *
  403. * @return boolean true on success, false on failure
  404. */
  405. function dnssec_deactivate_zone_key($domain_name, $key_id) {
  406. $call_result = call_dnssec('deactivate-zone-key', join(" ", array($domain_name, $key_id)));
  407. $return_code = $call_result[1];
  408. if ($return_code != 0) {
  409. error(ERR_EXEC_PDNSSEC_SHOW_ZONE);
  410. return false;
  411. }
  412. return true;
  413. }
  414. /** Get list of existing DNSSEC keys
  415. *
  416. * @param string $domain_name Domain Name
  417. *
  418. * @return mixed[] array with DNSSEC keys
  419. */
  420. function dnssec_get_keys($domain_name) {
  421. $call_result = call_dnssec('show-zone', $domain_name);
  422. $output = $call_result[0];
  423. $return_code = $call_result[1];
  424. if ($return_code != 0) {
  425. error(ERR_EXEC_PDNSSEC_SHOW_ZONE);
  426. return false;
  427. }
  428. $keys = array();
  429. foreach ($output as $line) {
  430. if (substr($line, 0, 2) == 'ID') {
  431. $items = explode(' ', $line);
  432. $bits_array = explode("\t", $items[12]);
  433. $keys[] = array($items[2], substr($items[3], 1, -2), substr($items[6], 0, -1), substr($items[9], 0, -1), $bits_array[0], $items[13]);
  434. }
  435. }
  436. return $keys;
  437. }
  438. /** Create new DNSSEC key
  439. *
  440. * @param string $domain_name Domain Name
  441. * @param string $key_type Key type
  442. * @param string $bits Bits in length
  443. * @param string $algorithm Algorithm
  444. *
  445. * @return boolean true on success, false on failure
  446. */
  447. function dnssec_add_zone_key($domain_name, $key_type, $bits, $algorithm) {
  448. $call_result = call_dnssec('add-zone-key', join(" ", array($domain_name, $key_type, $bits, $algorithm)));
  449. $return_code = $call_result[1];
  450. if ($return_code != 0) {
  451. error(ERR_EXEC_PDNSSEC_ADD_ZONE_KEY);
  452. return false;
  453. }
  454. return true;
  455. }
  456. /** Remove DNSSEC key
  457. *
  458. * @param string $domain_name Domain Name
  459. * @param int $key_id Key ID
  460. *
  461. * @return boolean true on success, false on failure
  462. */
  463. function dnssec_remove_zone_key($domain_name, $key_id) {
  464. $call_result = call_dnssec('remove-zone-key', join(" ", array($domain_name, $key_id)));
  465. $return_code = $call_result[1];
  466. if ($return_code != 0) {
  467. error(ERR_EXEC_PDNSSEC_ADD_ZONE_KEY);
  468. return false;
  469. }
  470. return true;
  471. }
  472. /** Check if given key exists
  473. *
  474. * @param string $domain_name Domain Name
  475. * @param int $key_id Key ID
  476. *
  477. * @return boolean true if exists, otherwise false
  478. */
  479. function dnssec_zone_key_exists($domain_name, $key_id) {
  480. $keys = dnssec_get_keys($domain_name);
  481. foreach ($keys as $key) {
  482. if ($key[0] == $key_id) {
  483. return true;
  484. }
  485. }
  486. return false;
  487. }
  488. /** Return requested key
  489. *
  490. * @param string $domain_name Domain Name
  491. * @param int $key_id Key ID
  492. *
  493. * @return mixed[] true if exists, otherwise false
  494. */
  495. function dnssec_get_zone_key($domain_name, $key_id) {
  496. $keys = dnssec_get_keys($domain_name);
  497. foreach ($keys as $key) {
  498. if ($key[0] == $key_id) {
  499. return $key;
  500. }
  501. }
  502. return array();
  503. }